Commit bcd04089eb
Changed files (4)
src-self-hosted
src-self-hosted/astgen.zig
@@ -1235,6 +1235,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
break :blk index_ptr;
};
const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr);
+ _ = try addZIRUnOp(mod, &for_scope.base, for_node.array_expr.firstToken(), .ensure_indexable, array_ptr);
const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start;
const len_ptr = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.FieldPtr, .{
.object_ptr = array_ptr,
src-self-hosted/type.zig
@@ -2675,6 +2675,13 @@ pub const Type = extern union {
};
}
+ pub fn isIndexable(self: Type) bool {
+ const zig_tag = self.zigTypeTag();
+ // TODO tuples are indexable
+ return zig_tag == .Array or zig_tag == .Vector or self.isSlice() or
+ (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
+ }
+
/// This enum does not directly correspond to `std.builtin.TypeId` because
/// it has extra enum tags in it, as a way of using less memory. For example,
/// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
src-self-hosted/zir.zig
@@ -137,6 +137,8 @@ pub const Inst = struct {
ensure_result_used,
/// Emits a compile error if an error is ignored.
ensure_result_non_error,
+ /// Emits a compile error if operand cannot be indexed.
+ ensure_indexable,
/// Create a `E!T` type.
error_union_type,
/// Create an error set.
@@ -278,6 +280,7 @@ pub const Inst = struct {
.alloc,
.ensure_result_used,
.ensure_result_non_error,
+ .ensure_indexable,
.bitcast_result_ptr,
.ref,
.bitcast_ref,
@@ -409,6 +412,7 @@ pub const Inst = struct {
.elemptr,
.ensure_result_used,
.ensure_result_non_error,
+ .ensure_indexable,
.@"export",
.floatcast,
.fieldptr,
src-self-hosted/zir_sema.zig
@@ -48,6 +48,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.declval_in_module => return analyzeInstDeclValInModule(mod, scope, old_inst.castTag(.declval_in_module).?),
.ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?),
.ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),
+ .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),
.ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
.ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
.ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
@@ -382,6 +383,19 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
}
}
+fn analyzeInstEnsureIndexable(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
+ const operand = try resolveInst(mod, scope, inst.positionals.operand);
+ const elem_ty = operand.ty.elemType();
+ if (elem_ty.isIndexable()) {
+ return mod.constVoid(scope, operand.src);
+ } else {
+ // TODO error notes
+ // error: type '{}' does not support indexing
+ // note: for loop operand must be an array, a slice or a tuple
+ return mod.fail(scope, operand.src, "for loop operand must be an array, a slice or a tuple", .{});
+ }
+}
+
fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
const var_type = try resolveType(mod, scope, inst.positionals.operand);
// TODO this should happen only for var allocs