mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
Sema: do not analyze test decls when not in test mode
We do this by reserving string table indexes 0 and 1 in ZIR to be special. Decls now have 0 to mean comptime or usingnamespace, and 1 to mean an unnamed test decl.
This commit is contained in:
parent
2354cbafdb
commit
fa6bb4b662
59
BRANCH_TODO
59
BRANCH_TODO
@ -39,34 +39,6 @@
|
||||
* AstGen: add result location pointers to function calls
|
||||
* nested function decl: how to refer to params?
|
||||
|
||||
pub fn createContainerDecl(
|
||||
mod: *Module,
|
||||
scope: *Scope,
|
||||
base_token: std.zig.ast.TokenIndex,
|
||||
decl_arena: *std.heap.ArenaAllocator,
|
||||
typed_value: TypedValue,
|
||||
) !*Decl {
|
||||
const scope_decl = scope.ownerDecl().?;
|
||||
const name = try mod.getAnonTypeName(scope, base_token);
|
||||
defer mod.gpa.free(name);
|
||||
const name_hash = scope.namespace().fullyQualifiedNameHash(name);
|
||||
const src_hash: std.zig.SrcHash = undefined;
|
||||
const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
|
||||
const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
|
||||
|
||||
decl_arena_state.* = decl_arena.state;
|
||||
new_decl.typed_value = .{
|
||||
.most_recent = .{
|
||||
.typed_value = typed_value,
|
||||
.arena = decl_arena_state,
|
||||
},
|
||||
};
|
||||
new_decl.analysis = .complete;
|
||||
new_decl.generation = mod.generation;
|
||||
|
||||
return new_decl;
|
||||
}
|
||||
|
||||
fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
|
||||
// TODO add namespaces, generic function signatrues
|
||||
const tree = scope.tree();
|
||||
@ -83,14 +55,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
|
||||
}
|
||||
|
||||
|
||||
pub fn analyzeFile(mod: *Module, file: *Scope.File) !void {
|
||||
// We call `getAstTree` here so that `analyzeFile` has the error set that includes
|
||||
// file system operations, but `analyzeNamespace` does not.
|
||||
const tree = try mod.getAstTree(file.namespace.file_scope);
|
||||
const decls = tree.rootDecls();
|
||||
return mod.analyzeNamespace(file.namespace, decls);
|
||||
}
|
||||
|
||||
/// Returns `true` if the Decl type changed.
|
||||
/// Returns `true` if this is the first time analyzing the Decl.
|
||||
/// Returns `false` otherwise.
|
||||
@ -143,29 +107,6 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
|
||||
var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
defer analysis_arena.deinit();
|
||||
|
||||
var code: Zir = blk: {
|
||||
var astgen = try AstGen.init(mod, decl, &analysis_arena.allocator);
|
||||
defer astgen.deinit();
|
||||
|
||||
var gen_scope: Scope.GenZir = .{
|
||||
.force_comptime = true,
|
||||
.parent = &decl.namespace.base,
|
||||
.astgen = &astgen,
|
||||
};
|
||||
defer gen_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const block_expr = node_datas[decl_node].lhs;
|
||||
_ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
|
||||
_ = try gen_scope.addBreak(.break_inline, 0, .void_value);
|
||||
|
||||
const code = try gen_scope.finish();
|
||||
if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
|
||||
code.dump(mod.gpa, "comptime_block", &gen_scope.base, 0) catch {};
|
||||
}
|
||||
break :blk code;
|
||||
};
|
||||
defer code.deinit(mod.gpa);
|
||||
|
||||
var sema: Sema = .{
|
||||
.mod = mod,
|
||||
.gpa = mod.gpa,
|
||||
|
||||
@ -78,6 +78,9 @@ pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir {
|
||||
};
|
||||
defer astgen.deinit(gpa);
|
||||
|
||||
// String table indexes 0 and 1 are reserved for special meaning.
|
||||
try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0 });
|
||||
|
||||
// We expect at least as many ZIR instructions and extra data items
|
||||
// as AST nodes.
|
||||
try astgen.instructions.ensureTotalCapacity(gpa, file.tree.nodes.len);
|
||||
@ -3124,7 +3127,8 @@ fn testDecl(
|
||||
if (token_tags[str_lit_token] == .string_literal) {
|
||||
break :blk (try decl_block.strLitAsString(str_lit_token)).index;
|
||||
}
|
||||
break :blk 0;
|
||||
// String table index 1 has a special meaning here of test decl with no name.
|
||||
break :blk 1;
|
||||
};
|
||||
|
||||
var fn_block: GenZir = .{
|
||||
|
||||
@ -3415,7 +3415,7 @@ pub fn scanNamespace(
|
||||
|
||||
const hash_u32s = zir.extra[extra_index..][0..4];
|
||||
extra_index += 4;
|
||||
const name_idx = zir.extra[extra_index];
|
||||
const decl_name_index = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
const decl_index = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
@ -3429,7 +3429,6 @@ pub fn scanNamespace(
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
const decl_name: ?[]const u8 = if (name_idx == 0) null else zir.nullTerminatedString(name_idx);
|
||||
const contents_hash = @bitCast(std.zig.SrcHash, hash_u32s.*);
|
||||
|
||||
try mod.scanDecl(
|
||||
@ -3437,7 +3436,7 @@ pub fn scanNamespace(
|
||||
&deleted_decls,
|
||||
&outdated_decls,
|
||||
contents_hash,
|
||||
decl_name,
|
||||
decl_name_index,
|
||||
decl_index,
|
||||
is_pub,
|
||||
is_exported,
|
||||
@ -3477,7 +3476,7 @@ fn scanDecl(
|
||||
deleted_decls: *std.AutoArrayHashMap(*Decl, void),
|
||||
outdated_decls: *std.AutoArrayHashMap(*Decl, void),
|
||||
contents_hash: std.zig.SrcHash,
|
||||
decl_name: ?[]const u8,
|
||||
decl_name_index: u32,
|
||||
decl_index: Zir.Inst.Index,
|
||||
is_pub: bool,
|
||||
is_exported: bool,
|
||||
@ -3493,6 +3492,11 @@ fn scanDecl(
|
||||
const decl_block_inst_data = zir.instructions.items(.data)[decl_index].pl_node;
|
||||
const decl_node = parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);
|
||||
|
||||
const decl_name: ?[]const u8 = if (decl_name_index > 1)
|
||||
zir.nullTerminatedString(decl_name_index)
|
||||
else
|
||||
null;
|
||||
|
||||
// We create a Decl for it regardless of analysis status.
|
||||
// Decls that have names are keyed in the namespace by the name. Decls without
|
||||
// names are keyed by their contents hash. This way we can detect if, for example,
|
||||
@ -3510,8 +3514,14 @@ fn scanDecl(
|
||||
// Update the key reference to the longer-lived memory.
|
||||
gop.entry.key = &new_decl.contents_hash;
|
||||
gop.entry.value = new_decl;
|
||||
// exported decls, comptime, test, and usingnamespace decls get analyzed.
|
||||
if (decl_name == null or is_exported) {
|
||||
// Exported decls, comptime decls, usingnamespace decls, and
|
||||
// test decls if in test mode, get analyzed.
|
||||
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,
|
||||
};
|
||||
if (want_analysis) {
|
||||
mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
|
||||
}
|
||||
new_decl.is_pub = is_pub;
|
||||
|
||||
21
src/Zir.zig
21
src/Zir.zig
@ -32,6 +32,7 @@ instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// is referencing the data here whether they want to store both index and length,
|
||||
/// thus allowing null bytes, or store only index, and use null-termination. The
|
||||
/// `string_bytes` array is agnostic to either usage.
|
||||
/// Indexes 0 and 1 are reserved for special cases.
|
||||
string_bytes: []u8,
|
||||
/// The meaning of this data is determined by `Inst.Tag` value.
|
||||
/// The first few indexes are reserved. See `ExtraIndex` for the values.
|
||||
@ -2378,8 +2379,9 @@ pub const Inst = struct {
|
||||
/// 1. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// name: u32, // null terminated string index
|
||||
/// - can be 0 for test decls. always 0 for comptime and usingnamespace decls.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 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.
|
||||
/// value: Index,
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// link_section: Ref, // if corresponding bit is set
|
||||
@ -2411,8 +2413,9 @@ pub const Inst = struct {
|
||||
/// 1. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// name: u32, // null terminated string index
|
||||
/// - can be 0 for test decls. always 0 for comptime and usingnamespace decls.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 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.
|
||||
/// value: Index,
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// link_section: Ref, // if corresponding bit is set
|
||||
@ -2442,8 +2445,9 @@ pub const Inst = struct {
|
||||
/// 1. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// name: u32, // null terminated string index
|
||||
/// - can be 0 for test decls. always 0 for comptime and usingnamespace decls.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 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.
|
||||
/// value: Index,
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// link_section: Ref, // if corresponding bit is set
|
||||
@ -2483,8 +2487,9 @@ pub const Inst = struct {
|
||||
/// 1. decl: { // for every decls_len
|
||||
/// src_hash: [4]u32, // hash of source bytes
|
||||
/// name: u32, // null terminated string index
|
||||
/// - can be 0 for test decls. always 0 for comptime and usingnamespace decls.
|
||||
/// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
|
||||
/// - 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.
|
||||
/// value: Index,
|
||||
/// - one of: block_inline, block_inline_var
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user