From 0611aa39858e6d7613cda3b3da981ff6b208a5e8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 2 May 2021 14:58:27 -0700 Subject: [PATCH] stage2: test decls encode that they are tests in ZIR This allows Sema to namespace them separately from function decls with the same name. Ran into this in std.math.order conflicting with a test with the same name. --- BRANCH_TODO | 3 +++ src/AstGen.zig | 13 ++++++++++++- src/Module.zig | 9 +++++++-- src/Zir.zig | 22 ++++++++++++++++++---- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index 3594632ea1..94689cc41d 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,3 +1,6 @@ + * running build-exe with cached ZIR crashes + * implement lazy struct field resolution; don't resolve struct fields until + they are needed. * decouple AstGen from Module, Compilation * AstGen threadlocal * extern "foo" for vars and for functions diff --git a/src/AstGen.zig b/src/AstGen.zig index b5b31c4095..853cedeeff 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3197,7 +3197,7 @@ fn testDecl( const test_token = main_tokens[node]; const str_lit_token = test_token + 1; if (token_tags[str_lit_token] == .string_literal) { - break :blk (try astgen.strLitAsString(str_lit_token)).index; + break :blk try astgen.testNameString(str_lit_token); } // String table index 1 has a special meaning here of test decl with no name. break :blk 1; @@ -7806,3 +7806,14 @@ fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice { }; } } + +fn testNameString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !u32 { + const gpa = astgen.gpa; + const string_bytes = &astgen.string_bytes; + const str_index = @intCast(u32, string_bytes.items.len); + const token_bytes = astgen.file.tree.tokenSlice(str_lit_token); + try string_bytes.append(gpa, 0); // Indicates this is a test. + try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); + try string_bytes.append(gpa, 0); + return str_index; +} diff --git a/src/Module.zig b/src/Module.zig index 3f699efbdd..2852747746 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3817,7 +3817,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node); // Every Decl needs a name. - const decl_name: [:0]const u8 = switch (decl_name_index) { + const raw_decl_name: [:0]const u8 = switch (decl_name_index) { 0 => name: { if (is_exported) { const i = iter.usingnamespace_index; @@ -3836,6 +3836,10 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo }, else => zir.nullTerminatedString(decl_name_index), }; + const decl_name = if (raw_decl_name.len != 0) raw_decl_name else name: { + const test_name = zir.nullTerminatedString(decl_name_index + 1); + break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); + }; log.debug("scan decl {s} is_pub={}", .{ decl_name, is_pub }); // We create a Decl for it regardless of analysis status. @@ -3847,10 +3851,11 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo gop.entry.value = new_decl; // Exported decls, comptime decls, usingnamespace decls, and // test decls if in test mode, get analyzed. + const is_named_test = raw_decl_name.len == 0; const want_analysis = is_exported or switch (decl_name_index) { 0 => true, // comptime decl 1 => mod.comp.bin_file.options.is_test, // test decl - else => false, // TODO set to true for named tests when testing + else => is_named_test and mod.comp.bin_file.options.is_test, }; if (want_analysis) { mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); diff --git a/src/Zir.zig b/src/Zir.zig index b7f3b2ae48..ec4c97f0f7 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2421,6 +2421,8 @@ pub const Inst = struct { /// - 0 means comptime or usingnamespace decl. /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace /// - 1 means test decl with no name. + /// - if there is a 0 byte at the position `name` indexes, it indicates + /// this is a test decl, and the name starts at `name+1`. /// value: Index, /// align: Ref, // if corresponding bit is set /// link_section: Ref, // if corresponding bit is set @@ -2459,6 +2461,8 @@ pub const Inst = struct { /// - 0 means comptime or usingnamespace decl. /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace /// - 1 means test decl with no name. + /// - if there is a 0 byte at the position `name` indexes, it indicates + /// this is a test decl, and the name starts at `name+1`. /// value: Index, /// align: Ref, // if corresponding bit is set /// link_section: Ref, // if corresponding bit is set @@ -2492,6 +2496,8 @@ pub const Inst = struct { /// - 0 means comptime or usingnamespace decl. /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace /// - 1 means test decl with no name. + /// - if there is a 0 byte at the position `name` indexes, it indicates + /// this is a test decl, and the name starts at `name+1`. /// value: Index, /// align: Ref, // if corresponding bit is set /// link_section: Ref, // if corresponding bit is set @@ -2535,8 +2541,9 @@ pub const Inst = struct { /// - 0 means comptime or usingnamespace decl. /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace /// - 1 means test decl with no name. + /// - if there is a 0 byte at the position `name` indexes, it indicates + /// this is a test decl, and the name starts at `name+1`. /// value: Index, - /// - one of: block_inline /// align: Ref, // if corresponding bit is set /// link_section: Ref, // if corresponding bit is set /// } @@ -3631,7 +3638,6 @@ const Writer = struct { const line = self.code.extra[extra_index]; extra_index += 1; const decl_name_index = self.code.extra[extra_index]; - const decl_name = self.code.nullTerminatedString(decl_name_index); extra_index += 1; const decl_index = self.code.extra[extra_index]; extra_index += 1; @@ -3653,10 +3659,18 @@ const Writer = struct { const name = if (is_exported) "usingnamespace" else "comptime"; try stream.writeAll(pub_str); try stream.writeAll(name); + } else if (decl_name_index == 1) { + try stream.writeAll("test"); } else { + const raw_decl_name = self.code.nullTerminatedString(decl_name_index); + const decl_name = if (raw_decl_name.len == 0) + self.code.nullTerminatedString(decl_name_index + 1) + else + raw_decl_name; + const test_str = if (raw_decl_name.len == 0) "test " else ""; const export_str = if (is_exported) "export " else ""; - try stream.print("{s}{s}{}", .{ - pub_str, export_str, std.zig.fmtId(decl_name), + try stream.print("{s}{s}{s}{}", .{ + pub_str, test_str, export_str, std.zig.fmtId(decl_name), }); if (align_inst != .none) { try stream.writeAll(" align(");