Commit 27fa4bc2be

Andrew Kelley <andrew@ziglang.org>
2021-04-24 08:40:10
AstGen: support struct init with ref result location
1 parent d2b06c2
Changed files (3)
src/AstGen.zig
@@ -1300,40 +1300,28 @@ pub fn structInitExpr(
             }
             return Zir.Inst.Ref.void_value;
         },
-        .none, .none_or_ref => {
+        .ref => {
             if (struct_init.ast.type_expr != 0) {
                 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
-                return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst);
-            }
-            const fields_list = try gpa.alloc(Zir.Inst.StructInitAnon.Item, struct_init.ast.fields.len);
-            defer gpa.free(fields_list);
-
-            for (struct_init.ast.fields) |field_init, i| {
-                const name_token = tree.firstToken(field_init) - 2;
-                const str_index = try gz.identAsString(name_token);
-
-                fields_list[i] = .{
-                    .field_name = str_index,
-                    .init = try expr(gz, scope, .none, field_init),
-                };
+                return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst, .struct_init_ref);
+            } else {
+                return structInitExprRlNone(gz, scope, rl, node, struct_init, .struct_init_anon_ref);
             }
-            const init_inst = try gz.addPlNode(.struct_init_anon, node, Zir.Inst.StructInitAnon{
-                .fields_len = @intCast(u32, fields_list.len),
-            });
-            try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
-                fields_list.len * @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);
-            for (fields_list) |field| {
-                _ = gz.astgen.addExtraAssumeCapacity(field);
+        },
+        .none, .none_or_ref => {
+            if (struct_init.ast.type_expr != 0) {
+                const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+                return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst, .struct_init);
+            } else {
+                return structInitExprRlNone(gz, scope, rl, node, struct_init, .struct_init_anon);
             }
-            return init_inst;
         },
-        .ref => return astgen.failNode(node, "cannot take address of struct literal", .{}),
         .ty => |ty_inst| {
             if (struct_init.ast.type_expr == 0) {
-                return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst);
+                return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst, .struct_init);
             }
             const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
-            const result = try structInitExprRlTy(gz, scope, rl, node, struct_init, inner_ty_inst);
+            const result = try structInitExprRlTy(gz, scope, rl, node, struct_init, inner_ty_inst, .struct_init);
             return rvalue(gz, scope, rl, result, node);
         },
         .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst),
@@ -1341,6 +1329,41 @@ pub fn structInitExpr(
     }
 }
 
+pub fn structInitExprRlNone(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    struct_init: ast.full.StructInit,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const astgen = gz.astgen;
+    const gpa = astgen.gpa;
+    const tree = &astgen.file.tree;
+
+    const fields_list = try gpa.alloc(Zir.Inst.StructInitAnon.Item, struct_init.ast.fields.len);
+    defer gpa.free(fields_list);
+
+    for (struct_init.ast.fields) |field_init, i| {
+        const name_token = tree.firstToken(field_init) - 2;
+        const str_index = try gz.identAsString(name_token);
+
+        fields_list[i] = .{
+            .field_name = str_index,
+            .init = try expr(gz, scope, .none, field_init),
+        };
+    }
+    const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{
+        .fields_len = @intCast(u32, fields_list.len),
+    });
+    try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
+        fields_list.len * @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);
+    for (fields_list) |field| {
+        _ = gz.astgen.addExtraAssumeCapacity(field);
+    }
+    return init_inst;
+}
+
 pub fn structInitExprRlPtr(
     gz: *GenZir,
     scope: *Scope,
@@ -1380,6 +1403,7 @@ pub fn structInitExprRlTy(
     node: ast.Node.Index,
     struct_init: ast.full.StructInit,
     ty_inst: Zir.Inst.Ref,
+    tag: Zir.Inst.Tag,
 ) InnerError!Zir.Inst.Ref {
     const astgen = gz.astgen;
     const gpa = astgen.gpa;
@@ -1401,7 +1425,7 @@ pub fn structInitExprRlTy(
             .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
         };
     }
-    const init_inst = try gz.addPlNode(.struct_init, node, Zir.Inst.StructInit{
+    const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{
         .fields_len = @intCast(u32, fields_list.len),
     });
     try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
@@ -1886,7 +1910,9 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
             .switch_capture_else_ref,
             .struct_init_empty,
             .struct_init,
+            .struct_init_ref,
             .struct_init_anon,
+            .struct_init_anon_ref,
             .array_init,
             .array_init_anon,
             .array_init_ref,
src/Sema.zig
@@ -256,11 +256,13 @@ pub fn analyzeBody(
             .typeof_log2_int_type         => try sema.zirTypeofLog2IntType(block, inst),
             .xor                          => try sema.zirBitwise(block, inst, .xor),
             .struct_init_empty            => try sema.zirStructInitEmpty(block, inst),
-            .struct_init                  => try sema.zirStructInit(block, inst),
-            .struct_init_anon             => try sema.zirStructInitAnon(block, inst),
+            .struct_init                  => try sema.zirStructInit(block, inst, false),
+            .struct_init_ref              => try sema.zirStructInit(block, inst, true),
+            .struct_init_anon             => try sema.zirStructInitAnon(block, inst, false),
+            .struct_init_anon_ref         => try sema.zirStructInitAnon(block, inst, true),
             .array_init                   => try sema.zirArrayInit(block, inst, false),
-            .array_init_anon              => try sema.zirArrayInitAnon(block, inst, false),
             .array_init_ref               => try sema.zirArrayInit(block, inst, true),
+            .array_init_anon              => try sema.zirArrayInitAnon(block, inst, false),
             .array_init_anon_ref          => try sema.zirArrayInitAnon(block, inst, true),
             .union_init_ptr               => try sema.zirUnionInitPtr(block, inst),
             .field_type                   => try sema.zirFieldType(block, inst),
@@ -5078,13 +5080,13 @@ fn zirUnionInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
     return sema.mod.fail(&block.base, src, "TODO: Sema.zirUnionInitPtr", .{});
 }
 
-fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst {
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
     const src = inst_data.src();
     return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInit", .{});
 }
 
-fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst {
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
     const src = inst_data.src();
     return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInitAnon", .{});
src/Zir.zig
@@ -660,9 +660,15 @@ pub const Inst = struct {
         /// struct value.
         /// Uses the `pl_node` field. Payload is `StructInit`.
         struct_init,
+        /// Struct initialization syntax, make the result a pointer.
+        /// Uses the `pl_node` field. Payload is `StructInit`.
+        struct_init_ref,
         /// Struct initialization without a type.
         /// Uses the `pl_node` field. Payload is `StructInitAnon`.
         struct_init_anon,
+        /// Anonymous struct initialization syntax, make the result a pointer.
+        /// Uses the `pl_node` field. Payload is `StructInitAnon`.
+        struct_init_anon_ref,
         /// Array initialization syntax.
         /// Uses the `pl_node` field. Payload is `MultiOp`.
         array_init,
@@ -1093,7 +1099,9 @@ pub const Inst = struct {
                 .validate_array_init_ptr,
                 .struct_init_empty,
                 .struct_init,
+                .struct_init_ref,
                 .struct_init_anon,
+                .struct_init_anon_ref,
                 .array_init,
                 .array_init_anon,
                 .array_init_ref,
@@ -2442,7 +2450,9 @@ const Writer = struct {
             .slice_end,
             .slice_sentinel,
             .struct_init,
+            .struct_init_ref,
             .struct_init_anon,
+            .struct_init_anon_ref,
             .array_init,
             .array_init_anon,
             .array_init_ref,