| author | |
| committer | |
| log | d8128c272a087bbfc0b33a786c18267f49cd4982 |
| tree | 2db7e2c6b4bb59ea23826703e2926b89cf630efc |
| parent | 1658e4893d749c7d1ed378cd34b6cbe1a132c0e9 |
Closes #124033 files changed, 98 insertions(+), 34 deletions(-)
src/Module.zig+22-9| ... | ... | @@ -528,10 +528,10 @@ pub const Decl = struct { |
| 528 | 528 | /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it |
| 529 | 529 | /// deletes the Decl on the spot. |
| 530 | 530 | alive: bool, |
| 531 | /// Whether the Decl is a `usingnamespace` declaration. | |
| 532 | is_usingnamespace: bool, | |
| 533 | 531 | /// If true `name` is already fully qualified. |
| 534 | 532 | name_fully_qualified: bool = false, |
| 533 | /// What kind of a declaration is this. | |
| 534 | kind: Kind, | |
| 535 | 535 | |
| 536 | 536 | /// Represents the position of the code in the output file. |
| 537 | 537 | /// This is populated regardless of semantic analysis and code generation. |
| ... | ... | @@ -551,6 +551,14 @@ pub const Decl = struct { |
| 551 | 551 | /// typed_value may need to be regenerated. |
| 552 | 552 | dependencies: DepsTable = .{}, |
| 553 | 553 | |
| 554 | pub const Kind = enum { | |
| 555 | @"usingnamespace", | |
| 556 | @"test", | |
| 557 | @"comptime", | |
| 558 | named, | |
| 559 | anon, | |
| 560 | }; | |
| 561 | ||
| 554 | 562 | pub const Index = enum(u32) { |
| 555 | 563 | _, |
| 556 | 564 | |
| ... | ... | @@ -4438,7 +4446,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4438 | 4446 | // not the struct itself. |
| 4439 | 4447 | try sema.resolveTypeLayout(decl_tv.ty); |
| 4440 | 4448 | |
| 4441 | if (decl.is_usingnamespace) { | |
| 4449 | if (decl.kind == .@"usingnamespace") { | |
| 4442 | 4450 | if (!decl_tv.ty.eql(Type.type, mod)) { |
| 4443 | 4451 | return sema.fail(&block_scope, ty_src, "expected type, found {}", .{ |
| 4444 | 4452 | decl_tv.ty.fmt(mod), |
| ... | ... | @@ -4964,26 +4972,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4964 | 4972 | |
| 4965 | 4973 | // Every Decl needs a name. |
| 4966 | 4974 | var is_named_test = false; |
| 4975 | var kind: Decl.Kind = .named; | |
| 4967 | 4976 | const decl_name: [:0]const u8 = switch (decl_name_index) { |
| 4968 | 4977 | 0 => name: { |
| 4969 | 4978 | if (export_bit) { |
| 4970 | 4979 | const i = iter.usingnamespace_index; |
| 4971 | 4980 | iter.usingnamespace_index += 1; |
| 4981 | kind = .@"usingnamespace"; | |
| 4972 | 4982 | break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); |
| 4973 | 4983 | } else { |
| 4974 | 4984 | const i = iter.comptime_index; |
| 4975 | 4985 | iter.comptime_index += 1; |
| 4986 | kind = .@"comptime"; | |
| 4976 | 4987 | break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); |
| 4977 | 4988 | } |
| 4978 | 4989 | }, |
| 4979 | 4990 | 1 => name: { |
| 4980 | 4991 | const i = iter.unnamed_test_index; |
| 4981 | 4992 | iter.unnamed_test_index += 1; |
| 4993 | kind = .@"test"; | |
| 4982 | 4994 | break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); |
| 4983 | 4995 | }, |
| 4984 | 4996 | 2 => name: { |
| 4985 | 4997 | is_named_test = true; |
| 4986 | 4998 | const test_name = zir.nullTerminatedString(decl_doccomment_index); |
| 4999 | kind = .@"test"; | |
| 4987 | 5000 | break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); |
| 4988 | 5001 | }, |
| 4989 | 5002 | else => name: { |
| ... | ... | @@ -4991,6 +5004,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4991 | 5004 | if (raw_name.len == 0) { |
| 4992 | 5005 | is_named_test = true; |
| 4993 | 5006 | const test_name = zir.nullTerminatedString(decl_name_index + 1); |
| 5007 | kind = .@"test"; | |
| 4994 | 5008 | break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); |
| 4995 | 5009 | } else { |
| 4996 | 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 | 5012 | }, |
| 4999 | 5013 | }; |
| 5000 | 5014 | const is_exported = export_bit and decl_name_index != 0; |
| 5001 | const is_usingnamespace = export_bit and decl_name_index == 0; | |
| 5002 | if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); | |
| 5015 | if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); | |
| 5003 | 5016 | |
| 5004 | 5017 | // We create a Decl for it regardless of analysis status. |
| 5005 | 5018 | const gop = try namespace.decls.getOrPutContextAdapted( |
| ... | ... | @@ -5012,8 +5025,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5012 | 5025 | if (!gop.found_existing) { |
| 5013 | 5026 | const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope); |
| 5014 | 5027 | const new_decl = mod.declPtr(new_decl_index); |
| 5028 | new_decl.kind = kind; | |
| 5015 | 5029 | new_decl.name = decl_name; |
| 5016 | if (is_usingnamespace) { | |
| 5030 | if (kind == .@"usingnamespace") { | |
| 5017 | 5031 | namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); |
| 5018 | 5032 | } |
| 5019 | 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 | 5072 | } |
| 5059 | 5073 | new_decl.is_pub = is_pub; |
| 5060 | 5074 | new_decl.is_exported = is_exported; |
| 5061 | new_decl.is_usingnamespace = is_usingnamespace; | |
| 5062 | 5075 | new_decl.has_align = has_align; |
| 5063 | 5076 | new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5064 | 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 | 5089 | |
| 5077 | 5090 | decl.is_pub = is_pub; |
| 5078 | 5091 | decl.is_exported = is_exported; |
| 5079 | decl.is_usingnamespace = is_usingnamespace; | |
| 5092 | decl.kind = kind; | |
| 5080 | 5093 | decl.has_align = has_align; |
| 5081 | 5094 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5082 | 5095 | decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| ... | ... | @@ -5635,7 +5648,7 @@ pub fn allocateNewDecl( |
| 5635 | 5648 | .has_linksection_or_addrspace = false, |
| 5636 | 5649 | .has_align = false, |
| 5637 | 5650 | .alive = false, |
| 5638 | .is_usingnamespace = false, | |
| 5651 | .kind = .anon, | |
| 5639 | 5652 | }; |
| 5640 | 5653 | |
| 5641 | 5654 | return decl_and_index.decl_index; |
src/Sema.zig+52-25| ... | ... | @@ -16217,11 +16217,54 @@ fn typeInfoDecls( |
| 16217 | 16217 | }; |
| 16218 | 16218 | try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena)); |
| 16219 | 16219 | |
| 16220 | const decls_len = if (opt_namespace) |ns| ns.decls.count() else 0; | |
| 16221 | const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len); | |
| 16222 | for (decls_vals) |*decls_val, i| { | |
| 16223 | const decl_index = opt_namespace.?.decls.keys()[i]; | |
| 16220 | var decl_vals = std.ArrayList(Value).init(sema.gpa); | |
| 16221 | defer decl_vals.deinit(); | |
| 16222 | ||
| 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 | ||
| 16247 | fn 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 | 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 | 16268 | const name_val = v: { |
| 16226 | 16269 | var anon_decl = try block.startAnonDecl(); |
| 16227 | 16270 | defer anon_decl.deinit(); |
| ... | ... | @@ -16231,37 +16274,21 @@ fn typeInfoDecls( |
| 16231 | 16274 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16232 | 16275 | 0, // default alignment |
| 16233 | 16276 | ); |
| 16234 | break :v try Value.Tag.slice.create(decls_anon_decl.arena(), .{ | |
| 16235 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl), | |
| 16236 | .len = try Value.Tag.int_u64.create(decls_anon_decl.arena(), bytes.len), | |
| 16277 | break :v try Value.Tag.slice.create(decls_anon_decl, .{ | |
| 16278 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl), | |
| 16279 | .len = try Value.Tag.int_u64.create(decls_anon_decl, bytes.len), | |
| 16237 | 16280 | }); |
| 16238 | 16281 | }; |
| 16239 | 16282 | |
| 16240 | const fields = try decls_anon_decl.arena().create([2]Value); | |
| 16283 | const fields = try decls_anon_decl.create([2]Value); | |
| 16241 | 16284 | fields.* = .{ |
| 16242 | 16285 | //name: []const u8, |
| 16243 | 16286 | name_val, |
| 16244 | 16287 | //is_pub: bool, |
| 16245 | 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 | } |
| 16266 | 16293 | |
| 16267 | 16294 | fn 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 | 566 | try expect(@ptrCast(*const u8, a).* == 1); |
| 567 | 567 | } |
| 568 | 568 | } |
| 569 | ||
| 570 | test "@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 | } |