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 {...@@ -501,7 +501,9 @@ pub const Struct = struct {
501 layout: std.builtin.TypeInfo.ContainerLayout,501 layout: std.builtin.TypeInfo.ContainerLayout,
502 status: enum {502 status: enum {
503 none,503 none,
504 field_types_wip,
504 have_field_types,505 have_field_types,
506 layout_wip,
505 have_layout,507 have_layout,
506 },508 },
507509
src/Sema.zig+140-18
...@@ -1163,7 +1163,6 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Ind...@@ -1163,7 +1163,6 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Ind
1163 // Maps field index to field_ptr index of where it was already initialized.1163 // Maps field index to field_ptr index of where it was already initialized.
1164 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.entries.items.len);1164 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.entries.items.len);
1165 defer gpa.free(found_fields);1165 defer gpa.free(found_fields);
1166
1167 mem.set(Zir.Inst.Index, found_fields, 0);1166 mem.set(Zir.Inst.Index, found_fields, 0);
11681167
1169 for (instrs) |field_ptr| {1168 for (instrs) |field_ptr| {
...@@ -1190,11 +1189,12 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Ind...@@ -1190,11 +1189,12 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Ind
11901189
1191 var root_msg: ?*Module.ErrorMsg = null;1190 var root_msg: ?*Module.ErrorMsg = null;
11921191
1192 // TODO handle default struct field values
1193 for (found_fields) |field_ptr, i| {1193 for (found_fields) |field_ptr, i| {
1194 if (field_ptr != 0) continue;1194 if (field_ptr != 0) continue;
11951195
1196 const field_name = struct_obj.fields.entries.items[i].key;1196 const field_name = struct_obj.fields.entries.items[i].key;
1197 const template = "mising struct field: {s}";1197 const template = "missing struct field: {s}";
1198 const args = .{field_name};1198 const args = .{field_name};
1199 if (root_msg) |msg| {1199 if (root_msg) |msg| {
1200 try mod.errNote(&block.base, struct_init_src, msg, template, args);1200 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...@@ -4614,7 +4614,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
4614}4614}
46154615
4616fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {4616fn 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;
4618 const src = inst_data.src();4618 const src = inst_data.src();
4619 const operand = try sema.resolveInst(inst_data.operand);4619 const operand = try sema.resolveInst(inst_data.operand);
4620 return sema.mod.constType(sema.arena, src, operand.ty);4620 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...@@ -5052,9 +5052,112 @@ fn zirUnionInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
5052}5052}
50535053
5054fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst {5054fn 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);
5056 const src = inst_data.src();5060 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", .{});
5058}5161}
50595162
5060fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst {5163fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst {
...@@ -6043,17 +6146,18 @@ fn coerce(...@@ -6043,17 +6146,18 @@ fn coerce(
6043 if (inst.ty.zigTypeTag() == .EnumLiteral) {6146 if (inst.ty.zigTypeTag() == .EnumLiteral) {
6044 const val = try sema.resolveConstValue(block, inst_src, inst);6147 const val = try sema.resolveConstValue(block, inst_src, inst);
6045 const bytes = val.castTag(.enum_literal).?.data;6148 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 {
6047 const msg = msg: {6151 const msg = msg: {
6048 const msg = try mod.errMsg(6152 const msg = try mod.errMsg(
6049 &block.base,6153 &block.base,
6050 inst_src,6154 inst_src,
6051 "enum '{}' has no field named '{s}'",6155 "enum '{}' has no field named '{s}'",
6052 .{ dest_type, bytes },6156 .{ resolved_dest_type, bytes },
6053 );6157 );
6054 errdefer msg.destroy(sema.gpa);6158 errdefer msg.destroy(sema.gpa);
6055 try mod.errNoteNonLazy(6159 try mod.errNoteNonLazy(
6056 dest_type.declSrcLoc(),6160 resolved_dest_type.declSrcLoc(),
6057 msg,6161 msg,
6058 "enum declared here",6162 "enum declared here",
6059 .{},6163 .{},
...@@ -6063,7 +6167,7 @@ fn coerce(...@@ -6063,7 +6167,7 @@ fn coerce(
6063 return mod.failWithOwnedErrorMsg(&block.base, msg);6167 return mod.failWithOwnedErrorMsg(&block.base, msg);
6064 };6168 };
6065 return mod.constInst(arena, inst_src, .{6169 return mod.constInst(arena, inst_src, .{
6066 .ty = dest_type,6170 .ty = resolved_dest_type,
6067 .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),6171 .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),
6068 });6172 });
6069 }6173 }
...@@ -6698,23 +6802,41 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type...@@ -6698,23 +6802,41 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type
6698 const struct_obj = ty.castTag(.@"struct").?.data;6802 const struct_obj = ty.castTag(.@"struct").?.data;
6699 switch (struct_obj.status) {6803 switch (struct_obj.status) {
6700 .none => {},6804 .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,
6702 }6811 }
6812 struct_obj.status = .field_types_wip;
6703 try sema.mod.analyzeStructFields(struct_obj);6813 try sema.mod.analyzeStructFields(struct_obj);
6814 struct_obj.status = .have_field_types;
6704 return ty;6815 return ty;
6705 },6816 },
6706 .extern_options => {6817 .extern_options => return sema.resolveBuiltinTypeFields(block, src, ty, "ExternOptions"),
6707 const extern_options_ty = try sema.getBuiltinType(block, src, "ExternOptions");6818 .export_options => return sema.resolveBuiltinTypeFields(block, src, ty, "ExportOptions"),
6708 return sema.resolveTypeFields(block, src, extern_options_ty);6819 .atomic_ordering => return sema.resolveBuiltinTypeFields(block, src, ty, "AtomicOrdering"),
6709 },6820 .atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, ty, "AtomicRmwOp"),
6710 .export_options => {6821 .calling_convention => return sema.resolveBuiltinTypeFields(block, src, ty, "CallingConvention"),
6711 const export_options_ty = try sema.getBuiltinType(block, src, "ExportOptions");6822 .float_mode => return sema.resolveBuiltinTypeFields(block, src, ty, "FloatMode"),
6712 return sema.resolveTypeFields(block, src, export_options_ty);6823 .reduce_op => return sema.resolveBuiltinTypeFields(block, src, ty, "ReduceOp"),
6713 },6824 .call_options => return sema.resolveBuiltinTypeFields(block, src, ty, "CallOptions"),
6714 else => return ty,6825 else => return ty,
6715 }6826 }
6716}6827}
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
6718fn getBuiltinType(6840fn getBuiltinType(
6719 sema: *Sema,6841 sema: *Sema,
6720 block: *Scope.Block,6842 block: *Scope.Block,
src/value.zig+18
...@@ -118,6 +118,8 @@ pub const Value = extern union {...@@ -118,6 +118,8 @@ pub const Value = extern union {
118 enum_field_index,118 enum_field_index,
119 @"error",119 @"error",
120 error_union,120 error_union,
121 /// An instance of a struct.
122 @"struct",
121 /// This is a special value that tracks a set of types that have been stored123 /// This is a special value that tracks a set of types that have been stored
122 /// to an inferred allocation. It does not support any of the normal value queries.124 /// to an inferred allocation. It does not support any of the normal value queries.
123 inferred_alloc,125 inferred_alloc,
...@@ -225,6 +227,7 @@ pub const Value = extern union {...@@ -225,6 +227,7 @@ pub const Value = extern union {
225 .float_128 => Payload.Float_128,227 .float_128 => Payload.Float_128,
226 .@"error" => Payload.Error,228 .@"error" => Payload.Error,
227 .inferred_alloc => Payload.InferredAlloc,229 .inferred_alloc => Payload.InferredAlloc,
230 .@"struct" => Payload.Struct,
228 };231 };
229 }232 }
230233
...@@ -442,6 +445,7 @@ pub const Value = extern union {...@@ -442,6 +445,7 @@ pub const Value = extern union {
442 };445 };
443 return Value{ .ptr_otherwise = &new_payload.base };446 return Value{ .ptr_otherwise = &new_payload.base };
444 },447 },
448 .@"struct" => @panic("TODO can't copy struct value without knowing the type"),
445449
446 .inferred_alloc => unreachable,450 .inferred_alloc => unreachable,
447 }451 }
...@@ -521,6 +525,9 @@ pub const Value = extern union {...@@ -521,6 +525,9 @@ pub const Value = extern union {
521 .abi_align_default => return out_stream.writeAll("(default ABI alignment)"),525 .abi_align_default => return out_stream.writeAll("(default ABI alignment)"),
522526
523 .empty_struct_value => return out_stream.writeAll("struct {}{}"),527 .empty_struct_value => return out_stream.writeAll("struct {}{}"),
528 .@"struct" => {
529 return out_stream.writeAll("(struct value)");
530 },
524 .null_value => return out_stream.writeAll("null"),531 .null_value => return out_stream.writeAll("null"),
525 .undef => return out_stream.writeAll("undefined"),532 .undef => return out_stream.writeAll("undefined"),
526 .zero => return out_stream.writeAll("0"),533 .zero => return out_stream.writeAll("0"),
...@@ -701,6 +708,7 @@ pub const Value = extern union {...@@ -701,6 +708,7 @@ pub const Value = extern union {
701 .@"error",708 .@"error",
702 .error_union,709 .error_union,
703 .empty_struct_value,710 .empty_struct_value,
711 .@"struct",
704 .inferred_alloc,712 .inferred_alloc,
705 .abi_align_default,713 .abi_align_default,
706 => unreachable,714 => unreachable,
...@@ -1207,6 +1215,7 @@ pub const Value = extern union {...@@ -1207,6 +1215,7 @@ pub const Value = extern union {
1207 .call_options_type,1215 .call_options_type,
1208 .export_options_type,1216 .export_options_type,
1209 .extern_options_type,1217 .extern_options_type,
1218 .@"struct",
1210 => @panic("TODO this hash function looks pretty broken. audit it"),1219 => @panic("TODO this hash function looks pretty broken. audit it"),
1211 }1220 }
1212 return hasher.final();1221 return hasher.final();
...@@ -1394,6 +1403,7 @@ pub const Value = extern union {...@@ -1394,6 +1403,7 @@ pub const Value = extern union {
1394 .@"error",1403 .@"error",
1395 .error_union,1404 .error_union,
1396 .empty_struct_value,1405 .empty_struct_value,
1406 .@"struct",
1397 .null_value,1407 .null_value,
1398 .abi_align_default,1408 .abi_align_default,
1399 => false,1409 => false,
...@@ -1537,6 +1547,14 @@ pub const Value = extern union {...@@ -1537,6 +1547,14 @@ pub const Value = extern union {
1537 stored_inst_list: std.ArrayListUnmanaged(*ir.Inst) = .{},1547 stored_inst_list: std.ArrayListUnmanaged(*ir.Inst) = .{},
1538 },1548 },
1539 };1549 };
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 };
1540 };1558 };
15411559
1542 /// Big enough to fit any non-BigInt value1560 /// Big enough to fit any non-BigInt value