Commit a2533e6fca

Veikka Tuominen <git@vexu.eu>
2022-02-19 21:31:24
stage2: validate struct/array init ty
1 parent 6f0601c
src/AstGen.zig
@@ -1282,6 +1282,7 @@ fn arrayInitExpr(
             }
         }
         const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr);
+        _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, node);
         const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr);
         break :inst .{
             .array = array_type_inst,
@@ -1495,8 +1496,10 @@ fn structInitExpr(
     switch (rl) {
         .discard => {
             // TODO if a type expr is given the fields should be validated for that type
-            if (struct_init.ast.type_expr != 0)
-                _ = try typeExpr(gz, scope, struct_init.ast.type_expr);
+            if (struct_init.ast.type_expr != 0) {
+                const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+                _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
+            }
             for (struct_init.ast.fields) |field_init| {
                 _ = try expr(gz, scope, .discard, field_init);
             }
@@ -1505,6 +1508,7 @@ fn structInitExpr(
         .ref => {
             if (struct_init.ast.type_expr != 0) {
                 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+                _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
                 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);
             } else {
                 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);
@@ -1513,6 +1517,7 @@ fn structInitExpr(
         .none => {
             if (struct_init.ast.type_expr != 0) {
                 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+                _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
                 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
             } else {
                 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
@@ -1523,6 +1528,7 @@ fn structInitExpr(
                 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
             }
             const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+            _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node);
             const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
             return rvalue(gz, rl, result, node);
         },
@@ -1573,6 +1579,7 @@ fn structInitExprRlPtr(
         return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr);
     }
     const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+    _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
 
     var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);
     defer as_scope.unstack();
@@ -2334,6 +2341,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
             .closure_capture,
             .memcpy,
             .memset,
+            .validate_array_init_ty,
+            .validate_struct_init_ty,
             => break :b true,
         }
     } else switch (maybe_unused_result) {
src/print_zir.zig
@@ -237,6 +237,8 @@ const Writer = struct {
             .switch_cond_ref,
             .array_base_ptr,
             .field_base_ptr,
+            .validate_array_init_ty,
+            .validate_struct_init_ty,
             => try self.writeUnNode(stream, inst),
 
             .ref,
src/Sema.zig
@@ -872,6 +872,16 @@ fn analyzeBodyInner(
                 i += 1;
                 continue;
             },
+            .validate_array_init_ty => {
+                try sema.validateArrayInitTy(block, inst);
+                i += 1;
+                continue;
+            },
+            .validate_struct_init_ty => {
+                try sema.validateStructInitTy(block, inst);
+                i += 1;
+                continue;
+            },
             .validate_struct_init => {
                 try sema.zirValidateStructInit(block, inst, false);
                 i += 1;
@@ -1341,6 +1351,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt
     return sema.fail(block, src, "expected optional type, found {}", .{optional_ty});
 }
 
+fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
+    return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ty});
+}
+
+fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
+    return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ty});
+}
+
 fn failWithErrorSetCodeMissing(
     sema: *Sema,
     block: *Block,
@@ -2614,9 +2632,7 @@ fn zirArrayBasePtr(
         .Struct => if (elem_ty.isTuple()) return base_ptr,
         else => {},
     }
-    return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{
-        sema.typeOf(start_ptr).childType(),
-    });
+    return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
 }
 
 fn zirFieldBasePtr(
@@ -2640,9 +2656,40 @@ fn zirFieldBasePtr(
         .Struct, .Union => return base_ptr,
         else => {},
     }
-    return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{
-        sema.typeOf(start_ptr).childType(),
-    });
+    return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
+}
+
+fn validateArrayInitTy(
+    sema: *Sema,
+    block: *Block,
+    inst: Zir.Inst.Index,
+) CompileError!void {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    const ty = try sema.resolveType(block, src, inst_data.operand);
+
+    switch (ty.zigTypeTag()) {
+        .Array, .Vector => return,
+        .Struct => if (ty.isTuple()) return,
+        else => {},
+    }
+    return sema.failWithArrayInitNotSupported(block, src, ty);
+}
+
+fn validateStructInitTy(
+    sema: *Sema,
+    block: *Block,
+    inst: Zir.Inst.Index,
+) CompileError!void {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    const ty = try sema.resolveType(block, src, inst_data.operand);
+
+    switch (ty.zigTypeTag()) {
+        .Struct, .Union => return,
+        else => {},
+    }
+    return sema.failWithStructInitNotSupported(block, src, ty);
 }
 
 fn zirValidateStructInit(
@@ -10815,7 +10862,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
         .Struct => return structInitEmpty(sema, block, obj_ty, src, src),
         .Array => return arrayInitEmpty(sema, obj_ty),
         .Void => return sema.addConstant(obj_ty, Value.void),
-        else => unreachable,
+        else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
     }
 }
 
src/Zir.zig
@@ -655,6 +655,12 @@ pub const Inst = struct {
         ///   *?S returns *S
         /// Uses the `un_node` field.
         field_base_ptr,
+        /// Checks that the type supports array init syntax.
+        /// Uses the `un_node` field.
+        validate_array_init_ty,
+        /// Checks that the type supports struct init syntax.
+        /// Uses the `un_node` field.
+        validate_struct_init_ty,
         /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
         /// initialization expression, and emits compile errors for duplicate fields
         /// as well as missing fields, if applicable.
@@ -1101,6 +1107,8 @@ pub const Inst = struct {
                 .switch_cond_ref,
                 .array_base_ptr,
                 .field_base_ptr,
+                .validate_array_init_ty,
+                .validate_struct_init_ty,
                 .validate_struct_init,
                 .validate_struct_init_comptime,
                 .validate_array_init,
@@ -1356,6 +1364,8 @@ pub const Inst = struct {
                 .switch_capture_multi_ref = .switch_capture,
                 .array_base_ptr = .un_node,
                 .field_base_ptr = .un_node,
+                .validate_array_init_ty = .un_node,
+                .validate_struct_init_ty = .un_node,
                 .validate_struct_init = .pl_node,
                 .validate_struct_init_comptime = .pl_node,
                 .validate_array_init = .pl_node,