authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-18 17:16:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-19 19:03:20-07:00
loge4c437f23baecf9d170f3f058cde78f34dedd5d0
treeb6d6b6fd132fe0b94467445f4bd6816d2126738b
parent6329f4e47a78dc75b234e6d89c82fb3cff058fe1

stage2: implement union member access as enum tag


2 files changed, 65 insertions(+), 39 deletions(-)

src/Sema.zig+61-39
...@@ -2316,7 +2316,7 @@ fn validateStructInit(...@@ -2316,7 +2316,7 @@ fn validateStructInit(
2316 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;2316 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
2317 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);2317 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
2318 const field_index = struct_obj.fields.getIndex(field_name) orelse2318 const field_index = struct_obj.fields.getIndex(field_name) orelse
2319 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);2319 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
2320 if (found_fields[field_index] != 0) {2320 if (found_fields[field_index] != 0) {
2321 const other_field_ptr = found_fields[field_index];2321 const other_field_ptr = found_fields[field_index];
2322 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;2322 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
...@@ -2378,7 +2378,32 @@ fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil...@@ -2378,7 +2378,32 @@ fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
2378 }2378 }
2379}2379}
23802380
2381fn failWithBadFieldAccess(2381fn failWithBadMemberAccess(
2382 sema: *Sema,
2383 block: *Block,
2384 agg_ty: Type,
2385 field_src: LazySrcLoc,
2386 field_name: []const u8,
2387) CompileError {
2388 const kw_name = switch (agg_ty.zigTypeTag()) {
2389 .Union => "union",
2390 .Struct => "struct",
2391 .Opaque => "opaque",
2392 .Enum => "enum",
2393 else => unreachable,
2394 };
2395 const msg = msg: {
2396 const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{
2397 kw_name, agg_ty, field_name,
2398 });
2399 errdefer msg.destroy(sema.gpa);
2400 try sema.addDeclaredHereNote(msg, agg_ty);
2401 break :msg msg;
2402 };
2403 return sema.failWithOwnedErrorMsg(msg);
2404}
2405
2406fn failWithBadStructFieldAccess(
2382 sema: *Sema,2407 sema: *Sema,
2383 block: *Block,2408 block: *Block,
2384 struct_obj: *Module.Struct,2409 struct_obj: *Module.Struct,
...@@ -8828,7 +8853,7 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool)...@@ -8828,7 +8853,7 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool)
8828 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;8853 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
8829 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);8854 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
8830 const field_index = struct_obj.fields.getIndex(field_name) orelse8855 const field_index = struct_obj.fields.getIndex(field_name) orelse
8831 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);8856 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
8832 if (found_fields[field_index] != 0) {8857 if (found_fields[field_index] != 0) {
8833 const other_field_type = found_fields[field_index];8858 const other_field_type = found_fields[field_index];
8834 const other_field_type_data = zir_datas[other_field_type].pl_node;8859 const other_field_type_data = zir_datas[other_field_type].pl_node;
...@@ -9037,7 +9062,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -9037,7 +9062,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
9037 .Struct => {9062 .Struct => {
9038 const struct_obj = resolved_ty.castTag(.@"struct").?.data;9063 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
9039 const field = struct_obj.fields.get(field_name) orelse9064 const field = struct_obj.fields.get(field_name) orelse
9040 return sema.failWithBadFieldAccess(block, struct_obj, src, field_name);9065 return sema.failWithBadStructFieldAccess(block, struct_obj, src, field_name);
9041 return sema.addType(field.ty);9066 return sema.addType(field.ty);
9042 },9067 },
9043 .Union => {9068 .Union => {
...@@ -10859,7 +10884,7 @@ fn fieldVal(...@@ -10859,7 +10884,7 @@ fn fieldVal(
10859 },10884 },
10860 else => {},10885 else => {},
10861 }10886 }
10862 return sema.fail(block, src, "type '{}' does not support field access (fieldVal, {}.{s})", .{object_ty, object_ty, field_name});10887 return sema.fail(block, src, "type '{}' does not support field access (fieldVal, {}.{s})", .{ object_ty, object_ty, field_name });
10863}10888}
1086410889
10865fn fieldPtr(10890fn fieldPtr(
...@@ -11001,22 +11026,24 @@ fn fieldPtr(...@@ -11001,22 +11026,24 @@ fn fieldPtr(
11001 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),11026 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
11002 ));11027 ));
11003 },11028 },
11004 .Struct, .Opaque, .Union => {11029 .Union => {
11005 if (child_type.getNamespace()) |namespace| {11030 if (child_type.getNamespace()) |namespace| {
11006 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {11031 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
11007 return inst;11032 return inst;
11008 }11033 }
11009 }11034 }
11010 // TODO add note: declared here11035 if (child_type.unionTagType()) |enum_ty| {
11011 const kw_name = switch (child_type.zigTypeTag()) {11036 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
11012 .Struct => "struct",11037 const field_index_u32 = @intCast(u32, field_index);
11013 .Opaque => "opaque",11038 var anon_decl = try block.startAnonDecl();
11014 .Union => "union",11039 defer anon_decl.deinit();
11015 else => unreachable,11040 return sema.analyzeDeclRef(try anon_decl.finish(
11016 };11041 try enum_ty.copy(anon_decl.arena()),
11017 return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{11042 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
11018 kw_name, child_type, field_name,11043 ));
11019 });11044 }
11045 }
11046 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
11020 },11047 },
11021 .Enum => {11048 .Enum => {
11022 if (child_type.getNamespace()) |namespace| {11049 if (child_type.getNamespace()) |namespace| {
...@@ -11025,23 +11052,7 @@ fn fieldPtr(...@@ -11025,23 +11052,7 @@ fn fieldPtr(
11025 }11052 }
11026 }11053 }
11027 const field_index = child_type.enumFieldIndex(field_name) orelse {11054 const field_index = child_type.enumFieldIndex(field_name) orelse {
11028 const msg = msg: {11055 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
11029 const msg = try sema.errMsg(
11030 block,
11031 src,
11032 "enum '{}' has no member named '{s}'",
11033 .{ child_type, field_name },
11034 );
11035 errdefer msg.destroy(sema.gpa);
11036 try sema.mod.errNoteNonLazy(
11037 child_type.declSrcLoc(),
11038 msg,
11039 "enum declared here",
11040 .{},
11041 );
11042 break :msg msg;
11043 };
11044 return sema.failWithOwnedErrorMsg(msg);
11045 };11056 };
11046 const field_index_u32 = @intCast(u32, field_index);11057 const field_index_u32 = @intCast(u32, field_index);
11047 var anon_decl = try block.startAnonDecl();11058 var anon_decl = try block.startAnonDecl();
...@@ -11051,6 +11062,14 @@ fn fieldPtr(...@@ -11051,6 +11062,14 @@ fn fieldPtr(
11051 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),11062 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
11052 ));11063 ));
11053 },11064 },
11065 .Struct, .Opaque => {
11066 if (child_type.getNamespace()) |namespace| {
11067 if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
11068 return inst;
11069 }
11070 }
11071 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
11072 },
11054 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),11073 else => return sema.fail(block, src, "type '{}' has no members", .{child_type}),
11055 }11074 }
11056 },11075 },
...@@ -11070,7 +11089,7 @@ fn fieldPtr(...@@ -11070,7 +11089,7 @@ fn fieldPtr(
11070 },11089 },
11071 else => {},11090 else => {},
11072 }11091 }
11073 return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{object_ty, object_ptr_ty, field_name});11092 return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{ object_ty, object_ptr_ty, field_name });
11074}11093}
1107511094
11076fn fieldCallBind(11095fn fieldCallBind(
...@@ -11242,7 +11261,7 @@ fn structFieldPtr(...@@ -11242,7 +11261,7 @@ fn structFieldPtr(
11242 const struct_obj = struct_ty.castTag(.@"struct").?.data;11261 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1124311262
11244 const field_index_big = struct_obj.fields.getIndex(field_name) orelse11263 const field_index_big = struct_obj.fields.getIndex(field_name) orelse
11245 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);11264 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
11246 const field_index = @intCast(u32, field_index_big);11265 const field_index = @intCast(u32, field_index_big);
11247 const field = struct_obj.fields.values()[field_index];11266 const field = struct_obj.fields.values()[field_index];
11248 const ptr_field_ty = try Type.ptr(arena, .{11267 const ptr_field_ty = try Type.ptr(arena, .{
...@@ -11279,10 +11298,9 @@ fn structFieldVal(...@@ -11279,10 +11298,9 @@ fn structFieldVal(
11279 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);11298 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
11280 const struct_obj = struct_ty.castTag(.@"struct").?.data;11299 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1128111300
11282 const field_index_big = struct_obj.fields.getIndex(field_name) orelse11301 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
11283 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);11302 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
11284 const field_index = @intCast(u32, field_index_big);11303 const field_index = @intCast(u32, field_index_usize);
11285
11286 const field = struct_obj.fields.values()[field_index];11304 const field = struct_obj.fields.values()[field_index];
1128711305
11288 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {11306 if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
...@@ -13168,6 +13186,10 @@ pub fn resolveTypeLayout(...@@ -13168,6 +13186,10 @@ pub fn resolveTypeLayout(
13168 }13186 }
13169 union_obj.status = .have_layout;13187 union_obj.status = .have_layout;
13170 },13188 },
13189 .Array => {
13190 const elem_ty = ty.childType();
13191 return sema.resolveTypeLayout(block, src, elem_ty);
13192 },
13171 else => {},13193 else => {},
13172 }13194 }
13173}13195}
src/codegen/llvm.zig+4
...@@ -1261,6 +1261,10 @@ pub const DeclGen = struct {...@@ -1261,6 +1261,10 @@ pub const DeclGen = struct {
1261 }1261 }
1262 const field_ty = tv.ty.unionFieldType(tag_and_val.tag);1262 const field_ty = tv.ty.unionFieldType(tag_and_val.tag);
1263 const payload = p: {1263 const payload = p: {
1264 if (!field_ty.hasCodeGenBits()) {
1265 const padding_len = @intCast(c_uint, layout.payload_size);
1266 break :p self.context.intType(8).arrayType(padding_len).getUndef();
1267 }
1264 const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val });1268 const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val });
1265 const field_size = field_ty.abiSize(target);1269 const field_size = field_ty.abiSize(target);
1266 if (field_size == layout.payload_size) {1270 if (field_size == layout.payload_size) {