diff --git a/src/AstGen.zig b/src/AstGen.zig index f4a07fb028..0a9f10e630 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -823,7 +823,31 @@ pub fn structInitExpr( .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}), .ref => unreachable, // struct literal not valid as l-value .ty => |ty_inst| { - return mod.failNode(scope, node, "TODO implement structInitExpr ty", .{}); + 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 = astgen.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 rvalue(gz, scope, rl, init_inst, node); }, .ptr => |ptr_inst| { const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len); @@ -1321,6 +1345,8 @@ fn blockExprStmts( .switch_capture_else, .switch_capture_else_ref, .struct_init_empty, + .struct_init, + .field_type, .struct_decl, .struct_decl_packed, .struct_decl_extern, diff --git a/src/Sema.zig b/src/Sema.zig index 04bc817839..98c9d39a5a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -264,6 +264,8 @@ pub fn analyzeBody( .typeof_peer => try sema.zirTypeofPeer(block, inst), .xor => try sema.zirBitwise(block, inst, .xor), .struct_init_empty => try sema.zirStructInitEmpty(block, inst), + .struct_init => try sema.zirStructInit(block, inst), + .field_type => try sema.zirFieldType(block, inst), .struct_decl => try sema.zirStructDecl(block, inst, .Auto), .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed), @@ -4493,6 +4495,18 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In }); } +fn zirStructInit(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.zirStructInit", .{}); +} + +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(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldType", .{}); +} + fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { if (sema.func == null) { return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{}); diff --git a/src/zir.zig b/src/zir.zig index 807e25e6b8..8086de5b75 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -674,6 +674,13 @@ 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`. + field_type, + /// Finalizes a typed struct initialization, performs validation, and returns the + /// struct value. + /// Uses the `pl_node` field. Payload is `StructInit`. + struct_init, /// Converts an integer into an enum value. /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand. int_to_enum, @@ -839,6 +846,8 @@ pub const Inst = struct { .switch_block_ref_under_multi, .validate_struct_init_ptr, .struct_init_empty, + .struct_init, + .field_type, .int_to_enum, .enum_to_int, => false, @@ -1551,6 +1560,24 @@ pub const Inst = struct { return @bitCast(f128, int_bits); } }; + + /// Trailing is an item per field. + pub const StructInit = struct { + fields_len: u32, + + pub const Item = struct { + /// The `field_type` ZIR instruction for this field init. + field_type: Index, + /// 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 SpecialProng = enum { none, @"else", under }; @@ -1665,6 +1692,8 @@ const Writer = struct { .union_decl, .enum_decl, .enum_decl_nonexhaustive, + .struct_init, + .field_type, => try self.writePlNode(stream, inst), .add,