Commit 3f60481be4

Andrew Kelley <andrew@ziglang.org>
2021-04-19 20:09:00
AstGen: implement the remaining struct init ResultLoc forms
1 parent ae495de
Changed files (3)
src/AstGen.zig
@@ -877,63 +877,115 @@ pub fn structInitExpr(
         }
     }
     switch (rl) {
-        .discard => return astgen.failNode(node, "TODO implement structInitExpr discard", .{}),
-        .none, .none_or_ref => return astgen.failNode(node, "TODO implement structInitExpr none", .{}),
-        .ref => unreachable, // struct literal not valid as l-value
-        .ty => |ty_inst| {
-            const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len);
+        .discard => {
+            for (struct_init.ast.fields) |field_init| {
+                _ = try expr(gz, scope, .discard, field_init);
+            }
+            return Zir.Inst.Ref.void_value;
+        },
+        .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);
+            }
+            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);
 
-                const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
-                    .container_type = ty_inst,
-                    .name_start = str_index,
-                });
                 fields_list[i] = .{
-                    .field_type = gz.refToIndex(field_ty_inst).?,
-                    .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
+                    .field_name = str_index,
+                    .init = try expr(gz, scope, .none, field_init),
                 };
             }
-            const init_inst = try gz.addPlNode(.struct_init, node, Zir.Inst.StructInit{
+            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.StructInit.Item).Struct.fields.len);
+                fields_list.len * @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);
             for (fields_list) |field| {
                 _ = gz.astgen.addExtraAssumeCapacity(field);
             }
-            return rvalue(gz, scope, rl, init_inst, node);
+            return init_inst;
         },
-        .ptr => |ptr_inst| {
-            const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len);
-            defer gpa.free(field_ptr_list);
+        .ref => unreachable, // struct literal not valid as l-value
+        .ty => |ty_inst| return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst),
+        .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst),
+        .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr),
+    }
+}
 
-            for (struct_init.ast.fields) |field_init, i| {
-                const name_token = tree.firstToken(field_init) - 2;
-                const str_index = try gz.identAsString(name_token);
-                const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{
-                    .lhs = ptr_inst,
-                    .field_name_start = str_index,
-                });
-                field_ptr_list[i] = gz.refToIndex(field_ptr).?;
-                _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
-            }
-            const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{
-                .body_len = @intCast(u32, field_ptr_list.len),
-            });
-            try astgen.extra.appendSlice(gpa, field_ptr_list);
-            return validate_inst;
-        },
-        .inferred_ptr => |ptr_inst| {
-            return astgen.failNode(node, "TODO implement structInitExpr inferred_ptr", .{});
-        },
-        .block_ptr => |block_gz| {
-            return astgen.failNode(node, "TODO implement structInitExpr block", .{});
-        },
+pub fn structInitExprRlPtr(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    struct_init: ast.full.StructInit,
+    result_ptr: Zir.Inst.Ref,
+) InnerError!Zir.Inst.Ref {
+    const astgen = gz.astgen;
+    const gpa = astgen.gpa;
+    const tree = &astgen.file.tree;
+
+    const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len);
+    defer gpa.free(field_ptr_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);
+        const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{
+            .lhs = result_ptr,
+            .field_name_start = str_index,
+        });
+        field_ptr_list[i] = gz.refToIndex(field_ptr).?;
+        _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
+    }
+    const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{
+        .body_len = @intCast(u32, field_ptr_list.len),
+    });
+    try astgen.extra.appendSlice(gpa, field_ptr_list);
+    return validate_inst;
+}
+
+pub fn structInitExprRlTy(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    struct_init: ast.full.StructInit,
+    ty_inst: Zir.Inst.Ref,
+) 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.StructInit.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);
+
+        const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
+            .container_type = ty_inst,
+            .name_start = str_index,
+        });
+        fields_list[i] = .{
+            .field_type = gz.refToIndex(field_ty_inst).?,
+            .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
+        };
     }
+    const init_inst = try gz.addPlNode(.struct_init, node, Zir.Inst.StructInit{
+        .fields_len = @intCast(u32, fields_list.len),
+    });
+    try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
+        fields_list.len * @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len);
+    for (fields_list) |field| {
+        _ = gz.astgen.addExtraAssumeCapacity(field);
+    }
+    return init_inst;
 }
 
 pub fn comptimeExpr(
@@ -1318,7 +1370,6 @@ fn blockExprStmts(
                         .elem_val,
                         .elem_ptr_node,
                         .elem_val_node,
-                        .floatcast,
                         .field_ptr,
                         .field_val,
                         .field_ptr_named,
@@ -1403,8 +1454,10 @@ fn blockExprStmts(
                         .switch_capture_else_ref,
                         .struct_init_empty,
                         .struct_init,
+                        .struct_init_anon,
                         .union_init_ptr,
                         .field_type,
+                        .field_type_ref,
                         .struct_decl,
                         .struct_decl_packed,
                         .struct_decl_extern,
@@ -4706,21 +4759,61 @@ fn as(
             const result = try expr(gz, scope, .{ .ty = dest_type }, rhs);
             return rvalue(gz, scope, rl, result, node);
         },
-
-        .ptr => |result_ptr| {
+        .ptr, .inferred_ptr => |result_ptr| {
             return asRlPtr(gz, scope, rl, result_ptr, rhs, dest_type);
         },
         .block_ptr => |block_scope| {
             return asRlPtr(gz, scope, rl, block_scope.rl_ptr, rhs, dest_type);
         },
+    }
+}
 
-        .inferred_ptr => |result_alloc| {
-            // TODO here we should be able to resolve the inference; we now have a type for the result.
-            return gz.astgen.failNode(node, "TODO implement @as with inferred-type result location pointer", .{});
+fn unionInit(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    params: []const ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+    const union_type = try typeExpr(gz, scope, params[0]);
+    const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
+    switch (rl) {
+        .none, .none_or_ref, .discard, .ref, .ty, .inferred_ptr => {
+            const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
+                .container_type = union_type,
+                .field_name = field_name,
+            });
+            const result = try expr(gz, scope, .{ .ty = union_type }, params[2]);
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .ptr => |result_ptr| {
+            return unionInitRlPtr(gz, scope, rl, node, result_ptr, params[2], union_type, field_name);
+        },
+        .block_ptr => |block_scope| {
+            return unionInitRlPtr(gz, scope, rl, node, block_scope.rl_ptr, params[2], union_type, field_name);
         },
     }
 }
 
+fn unionInitRlPtr(
+    parent_gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    result_ptr: Zir.Inst.Ref,
+    expr_node: ast.Node.Index,
+    union_type: Zir.Inst.Ref,
+    field_name: Zir.Inst.Ref,
+) InnerError!Zir.Inst.Ref {
+    const union_init_ptr = try parent_gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{
+        .result_ptr = result_ptr,
+        .union_type = union_type,
+        .field_name = field_name,
+    });
+    // TODO check if we need to do the elision like below in asRlPtr
+    return expr(parent_gz, scope, .{ .ptr = union_init_ptr }, expr_node);
+}
+
 fn asRlPtr(
     parent_gz: *GenZir,
     scope: *Scope,
@@ -4750,8 +4843,7 @@ fn asRlPtr(
         // Busted! This expression didn't actually need a pointer.
         const zir_tags = astgen.instructions.items(.tag);
         const zir_datas = astgen.instructions.items(.data);
-        const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;
-        try parent_zir.ensureCapacity(astgen.gpa, expected_len);
+        try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);
         for (as_scope.instructions.items) |src_inst| {
             if (parent_gz.indexToRef(src_inst) == as_scope.rl_ptr) continue;
             if (zir_tags[src_inst] == .store_to_block_ptr) {
@@ -4759,7 +4851,6 @@ fn asRlPtr(
             }
             parent_zir.appendAssumeCapacity(src_inst);
         }
-        assert(parent_zir.items.len == expected_len);
         const casted_result = try parent_gz.addBin(.as, dest_type, result);
         return rvalue(parent_gz, scope, rl, casted_result, operand_node);
     } else {
@@ -5445,24 +5536,6 @@ fn cImport(
     return rvalue(gz, scope, rl, .void_value, node);
 }
 
-fn unionInit(
-    gz: *GenZir,
-    scope: *Scope,
-    rl: ResultLoc,
-    node: ast.Node.Index,
-    params: []const ast.Node.Index,
-) InnerError!Zir.Inst.Ref {
-    const union_type = try typeExpr(gz, scope, params[0]);
-    const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
-    const union_init_ptr = try gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{
-        .union_type = union_type,
-        .field_name = field_name,
-    });
-    // TODO: set up a store_to_block_ptr elision thing here
-    const result = try expr(gz, scope, .{ .ptr = union_init_ptr }, params[2]);
-    return rvalue(gz, scope, rl, result, node);
-}
-
 fn overflowArithmetic(
     gz: *GenZir,
     scope: *Scope,
src/Sema.zig
@@ -193,7 +193,6 @@ pub fn analyzeBody(
             .field_ptr_named              => try sema.zirFieldPtrNamed(block, inst),
             .field_val                    => try sema.zirFieldVal(block, inst),
             .field_val_named              => try sema.zirFieldValNamed(block, inst),
-            .floatcast                    => try sema.zirFloatcast(block, inst),
             .func                         => try sema.zirFunc(block, inst, false),
             .func_extra                   => try sema.zirFuncExtra(block, inst, false),
             .func_extra_var_args          => try sema.zirFuncExtra(block, inst, true),
@@ -266,8 +265,10 @@ pub fn analyzeBody(
             .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),
             .union_init_ptr               => try sema.zirUnionInitPtr(block, inst),
             .field_type                   => try sema.zirFieldType(block, inst),
+            .field_type_ref               => try sema.zirFieldTypeRef(block, inst),
             .error_return_trace           => try sema.zirErrorReturnTrace(block, inst),
             .frame                        => try sema.zirFrame(block, inst),
             .frame_address                => try sema.zirFrameAddress(block, inst),
@@ -2904,7 +2905,7 @@ fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError
     return sema.bitcast(block, dest_type, operand);
 }
 
-fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+fn zirFloatCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -4984,6 +4985,18 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
     return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInit", .{});
 }
 
+fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) 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", .{});
+}
+
+fn zirFieldTypeRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) 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.zirFieldTypeRef", .{});
+}
+
 fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
     const src = inst_data.src();
@@ -5092,12 +5105,6 @@ fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
     return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToPtr", .{});
 }
 
-fn zirFloatCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) 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.zirFloatCast", .{});
-}
-
 fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
     const src = inst_data.src();
src/Zir.zig
@@ -367,11 +367,6 @@ pub const Inst = struct {
         /// The field name is a comptime instruction. Used by @field.
         /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
         field_val_named,
-        /// Convert a larger float type to any other float type, possibly causing
-        /// a loss of precision.
-        /// Uses the `pl_node` field. AST is the `@floatCast` syntax.
-        /// Payload is `Bin` with lhs as the dest type, rhs the operand.
-        floatcast,
         /// Returns a function type, or a function instance, depending on whether
         /// the body_len is 0. Calling convention is auto.
         /// Uses the `pl_node` union field. `payload_index` points to a `Func`.
@@ -686,13 +681,19 @@ pub const Inst = struct {
         /// A struct literal with a specified type, with no fields.
         /// Uses the `un_node` field.
         struct_init_empty,
-        /// Given a struct, union, enum, or opaque and a field name, returns the field type.
-        /// Uses the `pl_node` field. Payload is `FieldType`.
+        /// Given a struct, union, enum, or opaque and a field name as a string index,
+        /// returns the field type. Uses the `pl_node` field. Payload is `FieldType`.
         field_type,
+        /// Given a struct, union, enum, or opaque and a field name as a Ref,
+        /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.
+        field_type_ref,
         /// Finalizes a typed struct initialization, performs validation, and returns the
         /// struct value.
         /// Uses the `pl_node` field. Payload is `StructInit`.
         struct_init,
+        /// Struct initialization without a type.
+        /// Uses the `pl_node` field. Payload is `StructInitAnon`.
+        struct_init_anon,
         /// Given a pointer to a union and a comptime known field name, activates that field
         /// and returns a pointer to it.
         /// Uses the `pl_node` field. Payload is `UnionInitPtr`.
@@ -813,8 +814,10 @@ pub const Inst = struct {
         /// Converts an integer into an enum value.
         /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
         int_to_enum,
-        /// Implements the `@floatCast` builtin.
-        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        /// Convert a larger float type to any other float type, possibly causing
+        /// a loss of precision.
+        /// Uses the `pl_node` field. AST is the `@floatCast` syntax.
+        /// Payload is `Bin` with lhs as the dest type, rhs the operand.
         float_cast,
         /// Implements the `@intCast` builtin.
         /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
@@ -1002,7 +1005,6 @@ pub const Inst = struct {
                 .ensure_result_used,
                 .ensure_result_non_error,
                 .@"export",
-                .floatcast,
                 .field_ptr,
                 .field_val,
                 .field_ptr_named,
@@ -1099,8 +1101,10 @@ pub const Inst = struct {
                 .validate_struct_init_ptr,
                 .struct_init_empty,
                 .struct_init,
+                .struct_init_anon,
                 .union_init_ptr,
                 .field_type,
+                .field_type_ref,
                 .int_to_enum,
                 .enum_to_int,
                 .type_info,
@@ -2031,12 +2035,29 @@ pub const Inst = struct {
         };
     };
 
+    /// Trailing is an item per field.
+    pub const StructInitAnon = struct {
+        fields_len: u32,
+
+        pub const Item = struct {
+            /// Null-terminated string table index.
+            field_name: u32,
+            /// The field init expression to be used as the field value.
+            init: Ref,
+        };
+    };
+
     pub const FieldType = struct {
         container_type: Ref,
         /// Offset into `string_bytes`, null terminated.
         name_start: u32,
     };
 
+    pub const FieldTypeRef = struct {
+        container_type: Ref,
+        field_name: Ref,
+    };
+
     pub const OverflowArithmetic = struct {
         lhs: Ref,
         rhs: Ref,
@@ -2059,6 +2080,7 @@ pub const Inst = struct {
     };
 
     pub const UnionInitPtr = struct {
+        result_ptr: Ref,
         union_type: Ref,
         field_name: Ref,
     };
@@ -2279,14 +2301,15 @@ const Writer = struct {
             .elem_val_node,
             .field_ptr_named,
             .field_val_named,
-            .floatcast,
             .slice_start,
             .slice_end,
             .slice_sentinel,
             .union_decl,
             .struct_init,
+            .struct_init_anon,
             .union_init_ptr,
             .field_type,
+            .field_type_ref,
             .cmpxchg_strong,
             .cmpxchg_weak,
             .shuffle,