mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 13:30:45 +00:00
stage2: split Scope.Container from Scope.File
This commit is contained in:
parent
1174cb1517
commit
6f0126e957
@ -125,7 +125,7 @@ pub const Decl = struct {
|
||||
/// mapping them to an address in the output file.
|
||||
/// Memory owned by this decl, using Module's allocator.
|
||||
name: [*:0]const u8,
|
||||
/// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`.
|
||||
/// The direct parent container of the Decl. This is either a `Scope.Container` or `Scope.ZIRModule`.
|
||||
/// Reference to externally owned memory.
|
||||
scope: *Scope,
|
||||
/// The AST Node decl index or ZIR Inst index that contains this declaration.
|
||||
@ -217,9 +217,10 @@ pub const Decl = struct {
|
||||
|
||||
pub fn src(self: Decl) usize {
|
||||
switch (self.scope.tag) {
|
||||
.file => {
|
||||
const file = @fieldParentPtr(Scope.File, "base", self.scope);
|
||||
const tree = file.contents.tree;
|
||||
.container => {
|
||||
const container = @fieldParentPtr(Scope.Container, "base", self.scope);
|
||||
const tree = container.file_scope.contents.tree;
|
||||
// TODO Container should have it's own decls()
|
||||
const decl_node = tree.root_node.decls()[self.src_index];
|
||||
return tree.token_locs[decl_node.firstToken()].start;
|
||||
},
|
||||
@ -229,6 +230,7 @@ pub const Decl = struct {
|
||||
const src_decl = module.decls[self.src_index];
|
||||
return src_decl.inst.src;
|
||||
},
|
||||
.file,
|
||||
.block => unreachable,
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
@ -359,6 +361,7 @@ pub const Scope = struct {
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
|
||||
.zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
|
||||
.file => unreachable,
|
||||
.container => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,15 +371,16 @@ pub const Scope = struct {
|
||||
return switch (self.tag) {
|
||||
.block => self.cast(Block).?.decl,
|
||||
.gen_zir => self.cast(GenZIR).?.decl,
|
||||
.local_val => return self.cast(LocalVal).?.gen_zir.decl,
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir.decl,
|
||||
.local_val => self.cast(LocalVal).?.gen_zir.decl,
|
||||
.local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
|
||||
.decl => self.cast(DeclAnalysis).?.decl,
|
||||
.zir_module => null,
|
||||
.file => null,
|
||||
.container => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the scope has a parent which is a ZIRModule or File and
|
||||
/// Asserts the scope has a parent which is a ZIRModule or Container and
|
||||
/// returns it.
|
||||
pub fn namespace(self: *Scope) *Scope {
|
||||
switch (self.tag) {
|
||||
@ -385,7 +389,8 @@ pub const Scope = struct {
|
||||
.local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,
|
||||
.decl => return self.cast(DeclAnalysis).?.decl.scope,
|
||||
.zir_module, .file => return self,
|
||||
.file => return &self.cast(File).?.root_container.base,
|
||||
.zir_module, .container => return self,
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,8 +404,9 @@ pub const Scope = struct {
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.decl => unreachable,
|
||||
.file => unreachable,
|
||||
.zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
|
||||
.file => return self.cast(File).?.fullyQualifiedNameHash(name),
|
||||
.container => return self.cast(Container).?.fullyQualifiedNameHash(name),
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,11 +415,12 @@ pub const Scope = struct {
|
||||
switch (self.tag) {
|
||||
.file => return self.cast(File).?.contents.tree,
|
||||
.zir_module => unreachable,
|
||||
.decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
|
||||
.block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
|
||||
.gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,
|
||||
.local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(File).?.contents.tree,
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(File).?.contents.tree,
|
||||
.decl => return self.cast(DeclAnalysis).?.decl.scope.cast(Container).?.file_scope.contents.tree,
|
||||
.block => return self.cast(Block).?.decl.scope.cast(Container).?.file_scope.contents.tree,
|
||||
.gen_zir => return self.cast(GenZIR).?.decl.scope.cast(Container).?.file_scope.contents.tree,
|
||||
.local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
|
||||
.container => return self.cast(Container).?.file_scope.contents.tree,
|
||||
}
|
||||
}
|
||||
|
||||
@ -427,13 +434,15 @@ pub const Scope = struct {
|
||||
.decl => unreachable,
|
||||
.zir_module => unreachable,
|
||||
.file => unreachable,
|
||||
.container => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the scope has a parent which is a ZIRModule or File and
|
||||
/// Asserts the scope has a parent which is a ZIRModule, Contaienr or File and
|
||||
/// returns the sub_file_path field.
|
||||
pub fn subFilePath(base: *Scope) []const u8 {
|
||||
switch (base.tag) {
|
||||
.container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,
|
||||
.file => return @fieldParentPtr(File, "base", base).sub_file_path,
|
||||
.zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
|
||||
.block => unreachable,
|
||||
@ -453,11 +462,13 @@ pub const Scope = struct {
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.decl => unreachable,
|
||||
.container => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
|
||||
switch (base.tag) {
|
||||
.container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),
|
||||
.file => return @fieldParentPtr(File, "base", base).getSource(module),
|
||||
.zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
|
||||
.gen_zir => unreachable,
|
||||
@ -471,8 +482,9 @@ pub const Scope = struct {
|
||||
/// Asserts the scope is a namespace Scope and removes the Decl from the namespace.
|
||||
pub fn removeDecl(base: *Scope, child: *Decl) void {
|
||||
switch (base.tag) {
|
||||
.file => return @fieldParentPtr(File, "base", base).removeDecl(child),
|
||||
.container => return @fieldParentPtr(Container, "base", base).removeDecl(child),
|
||||
.zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
|
||||
.file => unreachable,
|
||||
.block => unreachable,
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
@ -499,6 +511,7 @@ pub const Scope = struct {
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.decl => unreachable,
|
||||
.container => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -515,6 +528,8 @@ pub const Scope = struct {
|
||||
zir_module,
|
||||
/// .zig source code.
|
||||
file,
|
||||
/// struct, enum or union, every .file contains one of these.
|
||||
container,
|
||||
block,
|
||||
decl,
|
||||
gen_zir,
|
||||
@ -522,6 +537,38 @@ pub const Scope = struct {
|
||||
local_ptr,
|
||||
};
|
||||
|
||||
pub const Container = struct {
|
||||
pub const base_tag: Tag = .container;
|
||||
base: Scope = Scope{ .tag = base_tag },
|
||||
|
||||
file_scope: *Scope.File,
|
||||
|
||||
/// Direct children of the file.
|
||||
decls: ArrayListUnmanaged(*Decl),
|
||||
|
||||
// TODO implement container types and put this in a status union
|
||||
// ty: Type
|
||||
|
||||
pub fn deinit(self: *Container, gpa: *Allocator) void {
|
||||
self.decls.deinit(gpa);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn removeDecl(self: *Container, child: *Decl) void {
|
||||
for (self.decls.items) |item, i| {
|
||||
if (item == child) {
|
||||
_ = self.decls.swapRemove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fullyQualifiedNameHash(self: *Container, name: []const u8) NameHash {
|
||||
// TODO container scope qualified names.
|
||||
return std.zig.hashSrc(name);
|
||||
}
|
||||
};
|
||||
|
||||
pub const File = struct {
|
||||
pub const base_tag: Tag = .file;
|
||||
base: Scope = Scope{ .tag = base_tag },
|
||||
@ -544,8 +591,7 @@ pub const Scope = struct {
|
||||
loaded_success,
|
||||
},
|
||||
|
||||
/// Direct children of the file.
|
||||
decls: ArrayListUnmanaged(*Decl),
|
||||
root_container: Container,
|
||||
|
||||
pub fn unload(self: *File, gpa: *Allocator) void {
|
||||
switch (self.status) {
|
||||
@ -569,20 +615,11 @@ pub const Scope = struct {
|
||||
}
|
||||
|
||||
pub fn deinit(self: *File, gpa: *Allocator) void {
|
||||
self.decls.deinit(gpa);
|
||||
self.root_container.deinit(gpa);
|
||||
self.unload(gpa);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn removeDecl(self: *File, child: *Decl) void {
|
||||
for (self.decls.items) |item, i| {
|
||||
if (item == child) {
|
||||
_ = self.decls.swapRemove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dumpSrc(self: *File, src: usize) void {
|
||||
const loc = std.zig.findLineColumn(self.source.bytes, src);
|
||||
std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
|
||||
@ -604,11 +641,6 @@ pub const Scope = struct {
|
||||
.bytes => |bytes| return bytes,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fullyQualifiedNameHash(self: *File, name: []const u8) NameHash {
|
||||
// We don't have struct scopes yet so this is currently just a simple name hash.
|
||||
return std.zig.hashSrc(name);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ZIRModule = struct {
|
||||
@ -861,7 +893,10 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
|
||||
.source = .{ .unloaded = {} },
|
||||
.contents = .{ .not_available = {} },
|
||||
.status = .never_loaded,
|
||||
.decls = .{},
|
||||
.root_container = .{
|
||||
.file_scope = root_scope,
|
||||
.decls = .{},
|
||||
},
|
||||
};
|
||||
break :blk &root_scope.base;
|
||||
} else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) {
|
||||
@ -969,7 +1004,7 @@ pub fn update(self: *Module) !void {
|
||||
// to force a refresh we unload now.
|
||||
if (self.root_scope.cast(Scope.File)) |zig_file| {
|
||||
zig_file.unload(self.gpa);
|
||||
self.analyzeRootSrcFile(zig_file) catch |err| switch (err) {
|
||||
self.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
assert(self.totalErrorCount() != 0);
|
||||
},
|
||||
@ -1237,8 +1272,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const file_scope = decl.scope.cast(Scope.File).?;
|
||||
const tree = try self.getAstTree(file_scope);
|
||||
const container_scope = decl.scope.cast(Scope.Container).?;
|
||||
const tree = try self.getAstTree(container_scope);
|
||||
const ast_node = tree.root_node.decls()[decl.src_index];
|
||||
switch (ast_node.tag) {
|
||||
.FnProto => {
|
||||
@ -1698,10 +1733,12 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
|
||||
}
|
||||
}
|
||||
|
||||
fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
|
||||
fn getAstTree(self: *Module, container_scope: *Scope.Container) !*ast.Tree {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const root_scope = container_scope.file_scope;
|
||||
|
||||
switch (root_scope.status) {
|
||||
.never_loaded, .unloaded_success => {
|
||||
try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
|
||||
@ -1743,24 +1780,24 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
|
||||
}
|
||||
}
|
||||
|
||||
fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||
fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
// We may be analyzing it for the first time, or this may be
|
||||
// an incremental update. This code handles both cases.
|
||||
const tree = try self.getAstTree(root_scope);
|
||||
const tree = try self.getAstTree(container_scope);
|
||||
const decls = tree.root_node.decls();
|
||||
|
||||
try self.work_queue.ensureUnusedCapacity(decls.len);
|
||||
try root_scope.decls.ensureCapacity(self.gpa, decls.len);
|
||||
try container_scope.decls.ensureCapacity(self.gpa, decls.len);
|
||||
|
||||
// Keep track of the decls that we expect to see in this file so that
|
||||
// we know which ones have been deleted.
|
||||
var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
|
||||
defer deleted_decls.deinit();
|
||||
try deleted_decls.ensureCapacity(root_scope.decls.items.len);
|
||||
for (root_scope.decls.items) |file_decl| {
|
||||
try deleted_decls.ensureCapacity(container_scope.decls.items.len);
|
||||
for (container_scope.decls.items) |file_decl| {
|
||||
deleted_decls.putAssumeCapacityNoClobber(file_decl, {});
|
||||
}
|
||||
|
||||
@ -1773,7 +1810,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||
|
||||
const name_loc = tree.token_locs[name_tok];
|
||||
const name = tree.tokenSliceLoc(name_loc);
|
||||
const name_hash = root_scope.fullyQualifiedNameHash(name);
|
||||
const name_hash = container_scope.fullyQualifiedNameHash(name);
|
||||
const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
|
||||
if (self.decl_table.get(name_hash)) |decl| {
|
||||
// Update the AST Node index of the decl, even if its contents are unchanged, it may
|
||||
@ -1801,8 +1838,8 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
|
||||
root_scope.decls.appendAssumeCapacity(new_decl);
|
||||
const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
|
||||
container_scope.decls.appendAssumeCapacity(new_decl);
|
||||
if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {
|
||||
if (tree.token_ids[maybe_export_token] == .Keyword_export) {
|
||||
self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
|
||||
@ -1812,7 +1849,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||
} else if (src_decl.castTag(.VarDecl)) |var_decl| {
|
||||
const name_loc = tree.token_locs[var_decl.name_token];
|
||||
const name = tree.tokenSliceLoc(name_loc);
|
||||
const name_hash = root_scope.fullyQualifiedNameHash(name);
|
||||
const name_hash = container_scope.fullyQualifiedNameHash(name);
|
||||
const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
|
||||
if (self.decl_table.get(name_hash)) |decl| {
|
||||
// Update the AST Node index of the decl, even if its contents are unchanged, it may
|
||||
@ -1828,8 +1865,8 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||
decl.contents_hash = contents_hash;
|
||||
}
|
||||
} else {
|
||||
const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
|
||||
root_scope.decls.appendAssumeCapacity(new_decl);
|
||||
const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
|
||||
container_scope.decls.appendAssumeCapacity(new_decl);
|
||||
if (var_decl.getExternExportToken()) |maybe_export_token| {
|
||||
if (tree.token_ids[maybe_export_token] == .Keyword_export) {
|
||||
self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
|
||||
@ -1841,11 +1878,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||
const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
|
||||
defer self.gpa.free(name);
|
||||
|
||||
const name_hash = root_scope.fullyQualifiedNameHash(name);
|
||||
const name_hash = container_scope.fullyQualifiedNameHash(name);
|
||||
const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
|
||||
|
||||
const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
|
||||
root_scope.decls.appendAssumeCapacity(new_decl);
|
||||
const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
|
||||
container_scope.decls.appendAssumeCapacity(new_decl);
|
||||
self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
|
||||
} else if (src_decl.castTag(.ContainerField)) |container_field| {
|
||||
log.err("TODO: analyze container field", .{});
|
||||
@ -3124,6 +3161,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
|
||||
self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
|
||||
},
|
||||
.file => unreachable,
|
||||
.container => unreachable,
|
||||
}
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
@ -436,8 +436,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
try branch_stack.append(.{});
|
||||
|
||||
const src_data: struct {lbrace_src: usize, rbrace_src: usize, source: []const u8} = blk: {
|
||||
if (module_fn.owner_decl.scope.cast(Module.Scope.File)) |scope_file| {
|
||||
const tree = scope_file.contents.tree;
|
||||
if (module_fn.owner_decl.scope.cast(Module.Scope.Container)) |container_scope| {
|
||||
const tree = container_scope.file_scope.contents.tree;
|
||||
const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?;
|
||||
const block = fn_proto.getBodyNode().?.castTag(.Block).?;
|
||||
const lbrace_src = tree.token_locs[block.lbrace].start;
|
||||
|
||||
@ -1656,8 +1656,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
try dbg_line_buffer.ensureCapacity(26);
|
||||
|
||||
const line_off: u28 = blk: {
|
||||
if (decl.scope.cast(Module.Scope.File)) |scope_file| {
|
||||
const tree = scope_file.contents.tree;
|
||||
if (decl.scope.cast(Module.Scope.Container)) |container_scope| {
|
||||
const tree = container_scope.file_scope.contents.tree;
|
||||
const file_ast_decls = tree.root_node.decls();
|
||||
// TODO Look into improving the performance here by adding a token-index-to-line
|
||||
// lookup table. Currently this involves scanning over the source code for newlines.
|
||||
@ -2157,8 +2157,8 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const scope_file = decl.scope.cast(Module.Scope.File).?;
|
||||
const tree = scope_file.contents.tree;
|
||||
const container_scope = decl.scope.cast(Module.Scope.Container).?;
|
||||
const tree = container_scope.file_scope.contents.tree;
|
||||
const file_ast_decls = tree.root_node.decls();
|
||||
// TODO Look into improving the performance here by adding a token-index-to-line
|
||||
// lookup table. Currently this involves scanning over the source code for newlines.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user