authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-03 18:35:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-03 18:35:37-07:00
log95b014caeaef6b04dc83b85e5b16823520072b44
treea604f3621e9196ea3436318a9a394849791300b5
parentaa4e9399db4001a49ad93f35dafbc53e3dec3cf3

Sema: implement struct_decl instruction


3 files changed, 160 insertions(+), 18 deletions(-)

src/Module.zig+2
......@@ -501,7 +501,9 @@ pub const Struct = struct {
501501 layout: std.builtin.TypeInfo.ContainerLayout,
502502 status: enum {
503503 none,
504 field_types_wip,
504505 have_field_types,
506 layout_wip,
505507 have_layout,
506508 },
507509
src/Sema.zig+140-18
......@@ -1163,7 +1163,6 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Ind
11631163 // Maps field index to field_ptr index of where it was already initialized.
11641164 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.entries.items.len);
11651165 defer gpa.free(found_fields);
1166
11671166 mem.set(Zir.Inst.Index, found_fields, 0);
11681167
11691168 for (instrs) |field_ptr| {
......@@ -1190,11 +1189,12 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Ind
11901189
11911190 var root_msg: ?*Module.ErrorMsg = null;
11921191
1192 // TODO handle default struct field values
11931193 for (found_fields) |field_ptr, i| {
11941194 if (field_ptr != 0) continue;
11951195
11961196 const field_name = struct_obj.fields.entries.items[i].key;
1197 const template = "mising struct field: {s}";
1197 const template = "missing struct field: {s}";
11981198 const args = .{field_name};
11991199 if (root_msg) |msg| {
12001200 try mod.errNote(&block.base, struct_init_src, msg, template, args);
......@@ -4614,7 +4614,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
46144614}
46154615
46164616fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4617 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4617 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
46184618 const src = inst_data.src();
46194619 const operand = try sema.resolveInst(inst_data.operand);
46204620 return sema.mod.constType(sema.arena, src, operand.ty);
......@@ -5052,9 +5052,112 @@ fn zirUnionInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
50525052}
50535053
50545054fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst {
5055 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
5055 const mod = sema.mod;
5056 const gpa = sema.gpa;
5057 const zir_datas = sema.code.instructions.items(.data);
5058 const inst_data = zir_datas[inst].pl_node;
5059 const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
50565060 const src = inst_data.src();
5057 return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInit", .{});
5061
5062 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
5063 const first_field_type_data = zir_datas[first_item.field_type].pl_node;
5064 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
5065 const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type);
5066 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type);
5067 const struct_obj = struct_ty.castTag(.@"struct").?.data;
5068
5069 // Maps field index to field_type index of where it was already initialized.
5070 // For making sure all fields are accounted for and no fields are duplicated.
5071 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.entries.items.len);
5072 defer gpa.free(found_fields);
5073 mem.set(Zir.Inst.Index, found_fields, 0);
5074
5075 // The init values to use for the struct instance.
5076 const field_inits = try gpa.alloc(*ir.Inst, struct_obj.fields.entries.items.len);
5077 defer gpa.free(field_inits);
5078
5079 var field_i: u32 = 0;
5080 var extra_index = extra.end;
5081
5082 while (field_i < extra.data.fields_len) : (field_i += 1) {
5083 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
5084 extra_index = item.end;
5085
5086 const field_type_data = zir_datas[item.data.field_type].pl_node;
5087 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };
5088 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
5089 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
5090 const field_index = struct_obj.fields.getIndex(field_name) orelse
5091 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);
5092 if (found_fields[field_index] != 0) {
5093 const other_field_type = found_fields[field_index];
5094 const other_field_type_data = zir_datas[other_field_type].pl_node;
5095 const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_type_data.src_node };
5096 const msg = msg: {
5097 const msg = try mod.errMsg(&block.base, field_src, "duplicate field", .{});
5098 errdefer msg.destroy(gpa);
5099 try mod.errNote(&block.base, other_field_src, msg, "other field here", .{});
5100 break :msg msg;
5101 };
5102 return mod.failWithOwnedErrorMsg(&block.base, msg);
5103 }
5104 found_fields[field_index] = item.data.field_type;
5105 field_inits[field_index] = try sema.resolveInst(item.data.init);
5106 }
5107
5108 var root_msg: ?*Module.ErrorMsg = null;
5109
5110 for (found_fields) |field_type_inst, i| {
5111 if (field_type_inst != 0) continue;
5112
5113 // Check if the field has a default init.
5114 const field = struct_obj.fields.entries.items[i].value;
5115 if (field.default_val.tag() == .unreachable_value) {
5116 const field_name = struct_obj.fields.entries.items[i].key;
5117 const template = "missing struct field: {s}";
5118 const args = .{field_name};
5119 if (root_msg) |msg| {
5120 try mod.errNote(&block.base, src, msg, template, args);
5121 } else {
5122 root_msg = try mod.errMsg(&block.base, src, template, args);
5123 }
5124 } else {
5125 field_inits[i] = try mod.constInst(sema.arena, src, .{
5126 .ty = field.ty,
5127 .val = field.default_val,
5128 });
5129 }
5130 }
5131 if (root_msg) |msg| {
5132 const fqn = try struct_obj.getFullyQualifiedName(gpa);
5133 defer gpa.free(fqn);
5134 try mod.errNoteNonLazy(
5135 struct_obj.srcLoc(),
5136 msg,
5137 "struct '{s}' declared here",
5138 .{fqn},
5139 );
5140 return mod.failWithOwnedErrorMsg(&block.base, msg);
5141 }
5142
5143 const is_comptime = for (field_inits) |field_init| {
5144 if (field_init.value() == null) {
5145 break false;
5146 }
5147 } else true;
5148
5149 if (is_comptime) {
5150 const values = try sema.arena.alloc(Value, field_inits.len);
5151 for (field_inits) |field_init, i| {
5152 values[i] = field_init.value().?;
5153 }
5154 return mod.constInst(sema.arena, src, .{
5155 .ty = struct_ty,
5156 .val = try Value.Tag.@"struct".create(sema.arena, values.ptr),
5157 });
5158 }
5159
5160 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit for runtime-known struct values", .{});
50585161}
50595162
50605163fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst {
......@@ -6043,17 +6146,18 @@ fn coerce(
60436146 if (inst.ty.zigTypeTag() == .EnumLiteral) {
60446147 const val = try sema.resolveConstValue(block, inst_src, inst);
60456148 const bytes = val.castTag(.enum_literal).?.data;
6046 const field_index = dest_type.enumFieldIndex(bytes) orelse {
6149 const resolved_dest_type = try sema.resolveTypeFields(block, inst_src, dest_type);
6150 const field_index = resolved_dest_type.enumFieldIndex(bytes) orelse {
60476151 const msg = msg: {
60486152 const msg = try mod.errMsg(
60496153 &block.base,
60506154 inst_src,
60516155 "enum '{}' has no field named '{s}'",
6052 .{ dest_type, bytes },
6156 .{ resolved_dest_type, bytes },
60536157 );
60546158 errdefer msg.destroy(sema.gpa);
60556159 try mod.errNoteNonLazy(
6056 dest_type.declSrcLoc(),
6160 resolved_dest_type.declSrcLoc(),
60576161 msg,
60586162 "enum declared here",
60596163 .{},
......@@ -6063,7 +6167,7 @@ fn coerce(
60636167 return mod.failWithOwnedErrorMsg(&block.base, msg);
60646168 };
60656169 return mod.constInst(arena, inst_src, .{
6066 .ty = dest_type,
6170 .ty = resolved_dest_type,
60676171 .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),
60686172 });
60696173 }
......@@ -6698,23 +6802,41 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type
66986802 const struct_obj = ty.castTag(.@"struct").?.data;
66996803 switch (struct_obj.status) {
67006804 .none => {},
6701 .have_field_types, .have_layout => return ty,
6805 .field_types_wip => {
6806 return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{
6807 ty,
6808 });
6809 },
6810 .have_field_types, .have_layout, .layout_wip => return ty,
67026811 }
6812 struct_obj.status = .field_types_wip;
67036813 try sema.mod.analyzeStructFields(struct_obj);
6814 struct_obj.status = .have_field_types;
67046815 return ty;
67056816 },
6706 .extern_options => {
6707 const extern_options_ty = try sema.getBuiltinType(block, src, "ExternOptions");
6708 return sema.resolveTypeFields(block, src, extern_options_ty);
6709 },
6710 .export_options => {
6711 const export_options_ty = try sema.getBuiltinType(block, src, "ExportOptions");
6712 return sema.resolveTypeFields(block, src, export_options_ty);
6713 },
6817 .extern_options => return sema.resolveBuiltinTypeFields(block, src, ty, "ExternOptions"),
6818 .export_options => return sema.resolveBuiltinTypeFields(block, src, ty, "ExportOptions"),
6819 .atomic_ordering => return sema.resolveBuiltinTypeFields(block, src, ty, "AtomicOrdering"),
6820 .atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, ty, "AtomicRmwOp"),
6821 .calling_convention => return sema.resolveBuiltinTypeFields(block, src, ty, "CallingConvention"),
6822 .float_mode => return sema.resolveBuiltinTypeFields(block, src, ty, "FloatMode"),
6823 .reduce_op => return sema.resolveBuiltinTypeFields(block, src, ty, "ReduceOp"),
6824 .call_options => return sema.resolveBuiltinTypeFields(block, src, ty, "CallOptions"),
67146825 else => return ty,
67156826 }
67166827}
67176828
6829fn resolveBuiltinTypeFields(
6830 sema: *Sema,
6831 block: *Scope.Block,
6832 src: LazySrcLoc,
6833 ty: Type,
6834 name: []const u8,
6835) InnerError!Type {
6836 const resolved_ty = try sema.getBuiltinType(block, src, name);
6837 return sema.resolveTypeFields(block, src, resolved_ty);
6838}
6839
67186840fn getBuiltinType(
67196841 sema: *Sema,
67206842 block: *Scope.Block,
src/value.zig+18
......@@ -118,6 +118,8 @@ pub const Value = extern union {
118118 enum_field_index,
119119 @"error",
120120 error_union,
121 /// An instance of a struct.
122 @"struct",
121123 /// This is a special value that tracks a set of types that have been stored
122124 /// to an inferred allocation. It does not support any of the normal value queries.
123125 inferred_alloc,
......@@ -225,6 +227,7 @@ pub const Value = extern union {
225227 .float_128 => Payload.Float_128,
226228 .@"error" => Payload.Error,
227229 .inferred_alloc => Payload.InferredAlloc,
230 .@"struct" => Payload.Struct,
228231 };
229232 }
230233
......@@ -442,6 +445,7 @@ pub const Value = extern union {
442445 };
443446 return Value{ .ptr_otherwise = &new_payload.base };
444447 },
448 .@"struct" => @panic("TODO can't copy struct value without knowing the type"),
445449
446450 .inferred_alloc => unreachable,
447451 }
......@@ -521,6 +525,9 @@ pub const Value = extern union {
521525 .abi_align_default => return out_stream.writeAll("(default ABI alignment)"),
522526
523527 .empty_struct_value => return out_stream.writeAll("struct {}{}"),
528 .@"struct" => {
529 return out_stream.writeAll("(struct value)");
530 },
524531 .null_value => return out_stream.writeAll("null"),
525532 .undef => return out_stream.writeAll("undefined"),
526533 .zero => return out_stream.writeAll("0"),
......@@ -701,6 +708,7 @@ pub const Value = extern union {
701708 .@"error",
702709 .error_union,
703710 .empty_struct_value,
711 .@"struct",
704712 .inferred_alloc,
705713 .abi_align_default,
706714 => unreachable,
......@@ -1207,6 +1215,7 @@ pub const Value = extern union {
12071215 .call_options_type,
12081216 .export_options_type,
12091217 .extern_options_type,
1218 .@"struct",
12101219 => @panic("TODO this hash function looks pretty broken. audit it"),
12111220 }
12121221 return hasher.final();
......@@ -1394,6 +1403,7 @@ pub const Value = extern union {
13941403 .@"error",
13951404 .error_union,
13961405 .empty_struct_value,
1406 .@"struct",
13971407 .null_value,
13981408 .abi_align_default,
13991409 => false,
......@@ -1537,6 +1547,14 @@ pub const Value = extern union {
15371547 stored_inst_list: std.ArrayListUnmanaged(*ir.Inst) = .{},
15381548 },
15391549 };
1550
1551 pub const Struct = struct {
1552 pub const base_tag = Tag.@"struct";
1553
1554 base: Payload = .{ .tag = base_tag },
1555 /// Field values. The number and type are according to the struct type.
1556 data: [*]Value,
1557 };
15401558 };
15411559
15421560 /// Big enough to fit any non-BigInt value