Commit bcd04089eb

Vexu <git@vexu.eu>
2020-08-25 18:31:39
stage2: add helpful error message for invalid for operands
1 parent b1aa285
Changed files (4)
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