authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-10 21:54:58+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-11 21:11:21+02:00
logd8128c272a087bbfc0b33a786c18267f49cd4982
tree2db7e2c6b4bb59ea23826703e2926b89cf630efc
parent1658e4893d749c7d1ed378cd34b6cbe1a132c0e9

Sema: fix typeInfo decls with usingnamespace

Closes #12403

3 files changed, 98 insertions(+), 34 deletions(-)

src/Module.zig+22-9
...@@ -528,10 +528,10 @@ pub const Decl = struct {...@@ -528,10 +528,10 @@ pub const Decl = struct {
528 /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it528 /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it
529 /// deletes the Decl on the spot.529 /// deletes the Decl on the spot.
530 alive: bool,530 alive: bool,
531 /// Whether the Decl is a `usingnamespace` declaration.
532 is_usingnamespace: bool,
533 /// If true `name` is already fully qualified.531 /// If true `name` is already fully qualified.
534 name_fully_qualified: bool = false,532 name_fully_qualified: bool = false,
533 /// What kind of a declaration is this.
534 kind: Kind,
535535
536 /// Represents the position of the code in the output file.536 /// Represents the position of the code in the output file.
537 /// This is populated regardless of semantic analysis and code generation.537 /// This is populated regardless of semantic analysis and code generation.
...@@ -551,6 +551,14 @@ pub const Decl = struct {...@@ -551,6 +551,14 @@ pub const Decl = struct {
551 /// typed_value may need to be regenerated.551 /// typed_value may need to be regenerated.
552 dependencies: DepsTable = .{},552 dependencies: DepsTable = .{},
553553
554 pub const Kind = enum {
555 @"usingnamespace",
556 @"test",
557 @"comptime",
558 named,
559 anon,
560 };
561
554 pub const Index = enum(u32) {562 pub const Index = enum(u32) {
555 _,563 _,
556564
...@@ -4438,7 +4446,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4438,7 +4446,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4438 // not the struct itself.4446 // not the struct itself.
4439 try sema.resolveTypeLayout(decl_tv.ty);4447 try sema.resolveTypeLayout(decl_tv.ty);
44404448
4441 if (decl.is_usingnamespace) {4449 if (decl.kind == .@"usingnamespace") {
4442 if (!decl_tv.ty.eql(Type.type, mod)) {4450 if (!decl_tv.ty.eql(Type.type, mod)) {
4443 return sema.fail(&block_scope, ty_src, "expected type, found {}", .{4451 return sema.fail(&block_scope, ty_src, "expected type, found {}", .{
4444 decl_tv.ty.fmt(mod),4452 decl_tv.ty.fmt(mod),
...@@ -4964,26 +4972,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -4964,26 +4972,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
49644972
4965 // Every Decl needs a name.4973 // Every Decl needs a name.
4966 var is_named_test = false;4974 var is_named_test = false;
4975 var kind: Decl.Kind = .named;
4967 const decl_name: [:0]const u8 = switch (decl_name_index) {4976 const decl_name: [:0]const u8 = switch (decl_name_index) {
4968 0 => name: {4977 0 => name: {
4969 if (export_bit) {4978 if (export_bit) {
4970 const i = iter.usingnamespace_index;4979 const i = iter.usingnamespace_index;
4971 iter.usingnamespace_index += 1;4980 iter.usingnamespace_index += 1;
4981 kind = .@"usingnamespace";
4972 break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i});4982 break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i});
4973 } else {4983 } else {
4974 const i = iter.comptime_index;4984 const i = iter.comptime_index;
4975 iter.comptime_index += 1;4985 iter.comptime_index += 1;
4986 kind = .@"comptime";
4976 break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i});4987 break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i});
4977 }4988 }
4978 },4989 },
4979 1 => name: {4990 1 => name: {
4980 const i = iter.unnamed_test_index;4991 const i = iter.unnamed_test_index;
4981 iter.unnamed_test_index += 1;4992 iter.unnamed_test_index += 1;
4993 kind = .@"test";
4982 break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i});4994 break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i});
4983 },4995 },
4984 2 => name: {4996 2 => name: {
4985 is_named_test = true;4997 is_named_test = true;
4986 const test_name = zir.nullTerminatedString(decl_doccomment_index);4998 const test_name = zir.nullTerminatedString(decl_doccomment_index);
4999 kind = .@"test";
4987 break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name});5000 break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name});
4988 },5001 },
4989 else => name: {5002 else => name: {
...@@ -4991,6 +5004,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -4991,6 +5004,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
4991 if (raw_name.len == 0) {5004 if (raw_name.len == 0) {
4992 is_named_test = true;5005 is_named_test = true;
4993 const test_name = zir.nullTerminatedString(decl_name_index + 1);5006 const test_name = zir.nullTerminatedString(decl_name_index + 1);
5007 kind = .@"test";
4994 break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name});5008 break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name});
4995 } else {5009 } else {
4996 break :name try gpa.dupeZ(u8, raw_name);5010 break :name try gpa.dupeZ(u8, raw_name);
...@@ -4998,8 +5012,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -4998,8 +5012,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
4998 },5012 },
4999 };5013 };
5000 const is_exported = export_bit and decl_name_index != 0;5014 const is_exported = export_bit and decl_name_index != 0;
5001 const is_usingnamespace = export_bit and decl_name_index == 0;5015 if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
5002 if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
50035016
5004 // We create a Decl for it regardless of analysis status.5017 // We create a Decl for it regardless of analysis status.
5005 const gop = try namespace.decls.getOrPutContextAdapted(5018 const gop = try namespace.decls.getOrPutContextAdapted(
...@@ -5012,8 +5025,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -5012,8 +5025,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
5012 if (!gop.found_existing) {5025 if (!gop.found_existing) {
5013 const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope);5026 const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope);
5014 const new_decl = mod.declPtr(new_decl_index);5027 const new_decl = mod.declPtr(new_decl_index);
5028 new_decl.kind = kind;
5015 new_decl.name = decl_name;5029 new_decl.name = decl_name;
5016 if (is_usingnamespace) {5030 if (kind == .@"usingnamespace") {
5017 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub);5031 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub);
5018 }5032 }
5019 log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace });5033 log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace });
...@@ -5058,7 +5072,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -5058,7 +5072,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
5058 }5072 }
5059 new_decl.is_pub = is_pub;5073 new_decl.is_pub = is_pub;
5060 new_decl.is_exported = is_exported;5074 new_decl.is_exported = is_exported;
5061 new_decl.is_usingnamespace = is_usingnamespace;
5062 new_decl.has_align = has_align;5075 new_decl.has_align = has_align;
5063 new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;5076 new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
5064 new_decl.zir_decl_index = @intCast(u32, decl_sub_index);5077 new_decl.zir_decl_index = @intCast(u32, decl_sub_index);
...@@ -5076,7 +5089,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -5076,7 +5089,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
50765089
5077 decl.is_pub = is_pub;5090 decl.is_pub = is_pub;
5078 decl.is_exported = is_exported;5091 decl.is_exported = is_exported;
5079 decl.is_usingnamespace = is_usingnamespace;5092 decl.kind = kind;
5080 decl.has_align = has_align;5093 decl.has_align = has_align;
5081 decl.has_linksection_or_addrspace = has_linksection_or_addrspace;5094 decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
5082 decl.zir_decl_index = @intCast(u32, decl_sub_index);5095 decl.zir_decl_index = @intCast(u32, decl_sub_index);
...@@ -5635,7 +5648,7 @@ pub fn allocateNewDecl(...@@ -5635,7 +5648,7 @@ pub fn allocateNewDecl(
5635 .has_linksection_or_addrspace = false,5648 .has_linksection_or_addrspace = false,
5636 .has_align = false,5649 .has_align = false,
5637 .alive = false,5650 .alive = false,
5638 .is_usingnamespace = false,5651 .kind = .anon,
5639 };5652 };
56405653
5641 return decl_and_index.decl_index;5654 return decl_and_index.decl_index;
src/Sema.zig+52-25
...@@ -16217,11 +16217,54 @@ fn typeInfoDecls(...@@ -16217,11 +16217,54 @@ fn typeInfoDecls(
16217 };16217 };
16218 try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena));16218 try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena));
1621916219
16220 const decls_len = if (opt_namespace) |ns| ns.decls.count() else 0;16220 var decl_vals = std.ArrayList(Value).init(sema.gpa);
16221 const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len);16221 defer decl_vals.deinit();
16222 for (decls_vals) |*decls_val, i| {16222
16223 const decl_index = opt_namespace.?.decls.keys()[i];16223 var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa);
16224 defer seen_namespaces.deinit();
16225
16226 if (opt_namespace) |some| {
16227 try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), some, &decl_vals, &seen_namespaces);
16228 }
16229
16230 const new_decl = try decls_anon_decl.finish(
16231 try Type.Tag.array.create(decls_anon_decl.arena(), .{
16232 .len = decl_vals.items.len,
16233 .elem_type = declaration_ty,
16234 }),
16235 try Value.Tag.aggregate.create(
16236 decls_anon_decl.arena(),
16237 try decls_anon_decl.arena().dupe(Value, decl_vals.items),
16238 ),
16239 0, // default alignment
16240 );
16241 return try Value.Tag.slice.create(sema.arena, .{
16242 .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
16243 .len = try Value.Tag.int_u64.create(sema.arena, decl_vals.items.len),
16244 });
16245}
16246
16247fn typeInfoNamespaceDecls(
16248 sema: *Sema,
16249 block: *Block,
16250 decls_anon_decl: Allocator,
16251 namespace: *Namespace,
16252 decl_vals: *std.ArrayList(Value),
16253 seen_namespaces: *std.AutoHashMap(*Namespace, void),
16254) !void {
16255 const gop = try seen_namespaces.getOrPut(namespace);
16256 if (gop.found_existing) return;
16257 const decls = namespace.decls.keys();
16258 for (decls) |decl_index| {
16224 const decl = sema.mod.declPtr(decl_index);16259 const decl = sema.mod.declPtr(decl_index);
16260 if (decl.kind == .@"usingnamespace") {
16261 try sema.mod.ensureDeclAnalyzed(decl_index);
16262 var buf: Value.ToTypeBuffer = undefined;
16263 const new_ns = decl.val.toType(&buf).getNamespace().?;
16264 try sema.typeInfoNamespaceDecls(block, decls_anon_decl, new_ns, decl_vals, seen_namespaces);
16265 continue;
16266 }
16267 if (decl.kind != .named) continue;
16225 const name_val = v: {16268 const name_val = v: {
16226 var anon_decl = try block.startAnonDecl();16269 var anon_decl = try block.startAnonDecl();
16227 defer anon_decl.deinit();16270 defer anon_decl.deinit();
...@@ -16231,37 +16274,21 @@ fn typeInfoDecls(...@@ -16231,37 +16274,21 @@ fn typeInfoDecls(
16231 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),16274 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
16232 0, // default alignment16275 0, // default alignment
16233 );16276 );
16234 break :v try Value.Tag.slice.create(decls_anon_decl.arena(), .{16277 break :v try Value.Tag.slice.create(decls_anon_decl, .{
16235 .ptr = try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl),16278 .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl),
16236 .len = try Value.Tag.int_u64.create(decls_anon_decl.arena(), bytes.len),16279 .len = try Value.Tag.int_u64.create(decls_anon_decl, bytes.len),
16237 });16280 });
16238 };16281 };
1623916282
16240 const fields = try decls_anon_decl.arena().create([2]Value);16283 const fields = try decls_anon_decl.create([2]Value);
16241 fields.* = .{16284 fields.* = .{
16242 //name: []const u8,16285 //name: []const u8,
16243 name_val,16286 name_val,
16244 //is_pub: bool,16287 //is_pub: bool,
16245 Value.makeBool(decl.is_pub),16288 Value.makeBool(decl.is_pub),
16246 };16289 };
16247 decls_val.* = try Value.Tag.aggregate.create(decls_anon_decl.arena(), fields);16290 try decl_vals.append(try Value.Tag.aggregate.create(decls_anon_decl, fields));
16248 }16291 }
16249
16250 const new_decl = try decls_anon_decl.finish(
16251 try Type.Tag.array.create(decls_anon_decl.arena(), .{
16252 .len = decls_vals.len,
16253 .elem_type = declaration_ty,
16254 }),
16255 try Value.Tag.aggregate.create(
16256 decls_anon_decl.arena(),
16257 try decls_anon_decl.arena().dupe(Value, decls_vals),
16258 ),
16259 0, // default alignment
16260 );
16261 return try Value.Tag.slice.create(sema.arena, .{
16262 .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
16263 .len = try Value.Tag.int_u64.create(sema.arena, decls_vals.len),
16264 });
16265}16292}
1626616293
16267fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {16294fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
test/behavior/type_info.zig+24
...@@ -566,3 +566,27 @@ test "value from struct @typeInfo default_value can be loaded at comptime" {...@@ -566,3 +566,27 @@ test "value from struct @typeInfo default_value can be loaded at comptime" {
566 try expect(@ptrCast(*const u8, a).* == 1);566 try expect(@ptrCast(*const u8, a).* == 1);
567 }567 }
568}568}
569
570test "@typeInfo decls and usingnamespace" {
571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
572 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
573 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
574
575 const A = struct {
576 const x = 5;
577 const y = 34;
578
579 comptime {}
580 };
581 const B = struct {
582 usingnamespace A;
583 const z = 56;
584
585 test {}
586 };
587 const decls = @typeInfo(B).Struct.decls;
588 try expect(decls.len == 3);
589 try expectEqualStrings(decls[0].name, "x");
590 try expectEqualStrings(decls[1].name, "y");
591 try expectEqualStrings(decls[2].name, "z");
592}