aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-14 11:26:53 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-15 19:06:39 -0700
commit3114115348e789ae4bab8844c7ebd0067185f1c4 (patch)
tree3d7fb3bd000ee263054bc4ddc9c98c0359b04a1f /src/Module.zig
parent9088d40e838b62c8f8ea0e6e68616b72e7704b27 (diff)
downloadzig-3114115348e789ae4bab8844c7ebd0067185f1c4.tar.gz
zig-3114115348e789ae4bab8844c7ebd0067185f1c4.zip
stage2: preliminary reworking for whole-file-AstGen
See #8516. * AstGen is now done on whole files at once rather than per Decl. * Introduce a new wait group for AstGen tasks. `performAllTheWork` waits for all AstGen tasks to be complete before doing Sema, single-threaded. - The C object compilation tasks are moved to be spawned after AstGen, since they only need to complete by the end of the function. With this commit, the codebase compiles, but much more reworking is needed to get things back into a useful state.
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig1603
1 files changed, 325 insertions, 1278 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 3f9a78f8d1..bcb4b8dc99 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -274,7 +274,7 @@ pub const Decl = struct {
};
}
- pub fn srcToken(decl: Decl) u32 {
+ pub fn srcToken(decl: Decl) ast.TokenIndex {
const tree = &decl.namespace.file_scope.tree;
return tree.firstToken(decl.src_node);
}
@@ -531,9 +531,9 @@ pub const Scope = struct {
pub fn ownerDecl(scope: *Scope) ?*Decl {
return switch (scope.tag) {
.block => scope.cast(Block).?.sema.owner_decl,
- .gen_zir => scope.cast(GenZir).?.astgen.decl,
- .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
- .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
+ .gen_zir => unreachable,
+ .local_val => unreachable,
+ .local_ptr => unreachable,
.file => null,
.namespace => null,
.decl_ref => scope.cast(DeclRef).?.decl,
@@ -543,9 +543,9 @@ pub const Scope = struct {
pub fn srcDecl(scope: *Scope) ?*Decl {
return switch (scope.tag) {
.block => scope.cast(Block).?.src_decl,
- .gen_zir => scope.cast(GenZir).?.astgen.decl,
- .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
- .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
+ .gen_zir => unreachable,
+ .local_val => unreachable,
+ .local_ptr => unreachable,
.file => null,
.namespace => null,
.decl_ref => scope.cast(DeclRef).?.decl,
@@ -556,28 +556,15 @@ pub const Scope = struct {
pub fn namespace(scope: *Scope) *Namespace {
switch (scope.tag) {
.block => return scope.cast(Block).?.sema.owner_decl.namespace,
- .gen_zir => return scope.cast(GenZir).?.astgen.decl.namespace,
- .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace,
- .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace,
+ .gen_zir => unreachable,
+ .local_val => unreachable,
+ .local_ptr => unreachable,
.file => return scope.cast(File).?.namespace,
.namespace => return scope.cast(Namespace).?,
.decl_ref => return scope.cast(DeclRef).?.decl.namespace,
}
}
- /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
- pub fn tree(scope: *Scope) *const ast.Tree {
- switch (scope.tag) {
- .file => return &scope.cast(File).?.tree,
- .block => return &scope.cast(Block).?.src_decl.namespace.file_scope.tree,
- .gen_zir => return scope.cast(GenZir).?.tree(),
- .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace.file_scope.tree,
- .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace.file_scope.tree,
- .namespace => return &scope.cast(Namespace).?.file_scope.tree,
- .decl_ref => return &scope.cast(DeclRef).?.decl.namespace.file_scope.tree,
- }
- }
-
/// Asserts the scope is a child of a `GenZir` and returns it.
pub fn getGenZir(scope: *Scope) *GenZir {
return switch (scope.tag) {
@@ -690,11 +677,14 @@ pub const Scope = struct {
base: Scope = Scope{ .tag = base_tag },
status: enum {
never_loaded,
- unloaded_success,
- unloaded_parse_failure,
- loaded_success,
+ parse_failure,
+ astgen_failure,
+ retryable_failure,
+ success,
},
source_loaded: bool,
+ tree_loaded: bool,
+ zir_loaded: bool,
/// Relative to the owning package's root_src_dir.
/// Memory is stored in gpa, owned by File.
sub_file_path: []const u8,
@@ -706,23 +696,27 @@ pub const Scope = struct {
stat_inode: std.fs.File.INode,
/// Whether this is populated depends on `status`.
stat_mtime: i128,
- /// Whether this is populated or not depends on `status`.
+ /// Whether this is populated or not depends on `tree_loaded`.
tree: ast.Tree,
+ /// Whether this is populated or not depends on `zir_loaded`.
+ zir: Zir,
/// Package that this file is a part of, managed externally.
pkg: *Package,
/// The namespace of the struct that represents this file.
+ /// Populated only when status is success.
namespace: *Namespace,
pub fn unload(file: *File, gpa: *Allocator) void {
file.unloadTree(gpa);
file.unloadSource(gpa);
+ file.unloadZir(gpa);
}
pub fn unloadTree(file: *File, gpa: *Allocator) void {
- if (file.status == .loaded_success) {
+ if (file.tree_loaded) {
+ file.tree_loaded = false;
file.tree.deinit(gpa);
}
- file.status = .unloaded_success;
}
pub fn unloadSource(file: *File, gpa: *Allocator) void {
@@ -732,21 +726,18 @@ pub const Scope = struct {
}
}
+ pub fn unloadZir(file: *File, gpa: *Allocator) void {
+ if (file.zir_loaded) {
+ file.zir_loaded = false;
+ file.zir.deinit(gpa);
+ }
+ }
+
pub fn deinit(file: *File, gpa: *Allocator) void {
file.unload(gpa);
file.* = undefined;
}
- pub fn destroy(file: *File, gpa: *Allocator) void {
- file.deinit(gpa);
- gpa.destroy(file);
- }
-
- pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
- const loc = std.zig.findLineColumn(file.source.bytes, src);
- std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
- }
-
pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {
if (file.source_loaded) return file.source;
@@ -757,31 +748,32 @@ pub const Scope = struct {
const stat = try f.stat();
- try file.finishGettingSource(gpa, f, stat);
- assert(file.source_loaded);
- return file.source;
- }
-
- pub fn finishGettingSource(
- file: *File,
- gpa: *Allocator,
- f: std.fs.File,
- stat: std.fs.File.Stat,
- ) !void {
if (stat.size > std.math.maxInt(u32))
return error.FileTooBig;
const source = try gpa.allocSentinel(u8, stat.size, 0);
- errdefer gpa.free(source);
+ defer if (!file.source_loaded) gpa.free(source);
const amt = try f.readAll(source);
if (amt != stat.size)
return error.UnexpectedEndOfFile;
- file.stat_size = stat.size;
- file.stat_inode = stat.inode;
- file.stat_mtime = stat.mtime;
+ // Here we do not modify stat fields because this function is the one
+ // used for error reporting. We need to keep the stat fields stale so that
+ // astGenFile can know to regenerate ZIR.
+
file.source = source;
file.source_loaded = true;
+ return source;
+ }
+
+ pub fn destroy(file: *File, gpa: *Allocator) void {
+ file.deinit(gpa);
+ gpa.destroy(file);
+ }
+
+ pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
+ const loc = std.zig.findLineColumn(file.source.bytes, src);
+ std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
}
};
@@ -1050,6 +1042,11 @@ pub const Scope = struct {
pub const base_tag: Tag = .gen_zir;
base: Scope = Scope{ .tag = base_tag },
force_comptime: bool,
+ /// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert
+ /// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters.
+ ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len,
+ /// The containing decl AST node.
+ decl_node_index: ast.Node.Index,
/// Parents can be: `GenZir`, `File`
parent: *Scope,
/// All `GenZir` scopes for the same ZIR share this.
@@ -1089,29 +1086,49 @@ pub const Scope = struct {
used: bool = false,
};
- /// Only valid to call on the top of the `GenZir` stack. Completes the
- /// `AstGen` into a `Zir`. Leaves the `AstGen` in an
- /// initialized, but empty, state.
- pub fn finish(gz: *GenZir) !Zir {
- const gpa = gz.astgen.mod.gpa;
- try gz.setBlockBody(0);
- return Zir{
- .instructions = gz.astgen.instructions.toOwnedSlice(),
- .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),
- .extra = gz.astgen.extra.toOwnedSlice(gpa),
- };
+ pub fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool {
+ if (inst_ref == .unreachable_value) return true;
+ if (gz.refToIndex(inst_ref)) |inst_index| {
+ return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn();
+ }
+ return false;
}
pub fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc {
- return gz.astgen.decl.tokSrcLoc(token_index);
+ return .{ .token_offset = token_index - gz.srcToken() };
}
pub fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc {
- return gz.astgen.decl.nodeSrcLoc(node_index);
+ return .{ .node_offset = gz.nodeIndexToRelative(node_index) };
+ }
+
+ pub fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 {
+ return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index);
+ }
+
+ pub fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 {
+ return token - gz.srcToken();
+ }
+
+ pub fn srcToken(gz: GenZir) ast.TokenIndex {
+ return gz.astgen.file.tree.firstToken(gz.decl_node_index);
}
pub fn tree(gz: *const GenZir) *const ast.Tree {
- return &gz.astgen.decl.namespace.file_scope.tree;
+ return &gz.astgen.file.tree;
+ }
+
+ pub fn indexToRef(gz: GenZir, inst: Zir.Inst.Index) Zir.Inst.Ref {
+ return @intToEnum(Zir.Inst.Ref, gz.ref_start_index + inst);
+ }
+
+ pub fn refToIndex(gz: GenZir, inst: Zir.Inst.Ref) ?Zir.Inst.Index {
+ const ref_int = @enumToInt(inst);
+ if (ref_int >= gz.ref_start_index) {
+ return ref_int - gz.ref_start_index;
+ } else {
+ return null;
+ }
}
pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
@@ -1149,7 +1166,7 @@ pub const Scope = struct {
}
pub fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
@typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
const zir_datas = gz.astgen.instructions.items(.data);
@@ -1160,7 +1177,7 @@ pub const Scope = struct {
}
pub fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
@typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
const zir_datas = gz.astgen.instructions.items(.data);
@@ -1172,77 +1189,133 @@ pub const Scope = struct {
pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {
const astgen = gz.astgen;
- const gpa = astgen.mod.gpa;
+ const gpa = astgen.gpa;
const string_bytes = &astgen.string_bytes;
const str_index = @intCast(u32, string_bytes.items.len);
- try astgen.mod.appendIdentStr(&gz.base, ident_token, string_bytes);
- try string_bytes.append(gpa, 0);
- return str_index;
+ try astgen.appendIdentStr(ident_token, string_bytes);
+ const key = string_bytes.items[str_index..];
+ const gop = try astgen.string_table.getOrPut(gpa, key);
+ if (gop.found_existing) {
+ string_bytes.shrinkRetainingCapacity(str_index);
+ return gop.entry.value;
+ } else {
+ // We have to dupe the key into the arena, otherwise the memory
+ // becomes invalidated when string_bytes gets data appended.
+ // TODO https://github.com/ziglang/zig/issues/8528
+ gop.entry.key = try astgen.arena.dupe(u8, key);
+ gop.entry.value = str_index;
+ try string_bytes.append(gpa, 0);
+ return str_index;
+ }
}
- pub fn addFnTypeCc(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
+ pub const IndexSlice = struct { index: u32, len: u32 };
+
+ pub fn strLitAsString(gz: *GenZir, str_lit_token: ast.TokenIndex) !IndexSlice {
+ const astgen = gz.astgen;
+ 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 astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
+ const key = string_bytes.items[str_index..];
+ const gop = try astgen.string_table.getOrPut(gpa, key);
+ if (gop.found_existing) {
+ string_bytes.shrinkRetainingCapacity(str_index);
+ return IndexSlice{
+ .index = gop.entry.value,
+ .len = @intCast(u32, key.len),
+ };
+ } else {
+ // We have to dupe the key into the arena, otherwise the memory
+ // becomes invalidated when string_bytes gets data appended.
+ // TODO https://github.com/ziglang/zig/issues/8528
+ gop.entry.key = try astgen.arena.dupe(u8, key);
+ gop.entry.value = str_index;
+ // Still need a null byte because we are using the same table
+ // to lookup null terminated strings, so if we get a match, it has to
+ // be null terminated for that to work.
+ try string_bytes.append(gpa, 0);
+ return IndexSlice{
+ .index = str_index,
+ .len = @intCast(u32, key.len),
+ };
+ }
+ }
+
+ pub fn addFuncExtra(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
src_node: ast.Node.Index,
param_types: []const Zir.Inst.Ref,
ret_ty: Zir.Inst.Ref,
cc: Zir.Inst.Ref,
+ body: []const Zir.Inst.Index,
+ lib_name: u32,
}) !Zir.Inst.Ref {
assert(args.src_node != 0);
assert(args.ret_ty != .none);
assert(args.cc != .none);
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
- @typeInfo(Zir.Inst.FnTypeCc).Struct.fields.len + args.param_types.len);
+ @typeInfo(Zir.Inst.FuncExtra).Struct.fields.len + args.param_types.len +
+ args.body.len);
- const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.FnTypeCc{
+ const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.FuncExtra{
.return_type = args.ret_ty,
.cc = args.cc,
.param_types_len = @intCast(u32, args.param_types.len),
+ .body_len = @intCast(u32, args.body.len),
+ .lib_name = args.lib_name,
});
gz.astgen.appendRefsAssumeCapacity(args.param_types);
+ gz.astgen.extra.appendSliceAssumeCapacity(args.body);
const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
gz.astgen.instructions.appendAssumeCapacity(.{
.tag = tag,
.data = .{ .pl_node = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node),
+ .src_node = gz.nodeIndexToRelative(args.src_node),
.payload_index = payload_index,
} },
});
gz.instructions.appendAssumeCapacity(new_index);
- return gz.astgen.indexToRef(new_index);
+ return gz.indexToRef(new_index);
}
- pub fn addFnType(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
+ pub fn addFunc(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
src_node: ast.Node.Index,
ret_ty: Zir.Inst.Ref,
param_types: []const Zir.Inst.Ref,
+ body: []const Zir.Inst.Index,
}) !Zir.Inst.Ref {
assert(args.src_node != 0);
assert(args.ret_ty != .none);
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
- @typeInfo(Zir.Inst.FnType).Struct.fields.len + args.param_types.len);
+ @typeInfo(Zir.Inst.Func).Struct.fields.len + args.param_types.len +
+ args.body.len);
- const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.FnType{
+ const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{
.return_type = args.ret_ty,
.param_types_len = @intCast(u32, args.param_types.len),
+ .body_len = @intCast(u32, args.body.len),
});
gz.astgen.appendRefsAssumeCapacity(args.param_types);
+ gz.astgen.extra.appendSliceAssumeCapacity(args.body);
const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
gz.astgen.instructions.appendAssumeCapacity(.{
.tag = tag,
.data = .{ .pl_node = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node),
+ .src_node = gz.nodeIndexToRelative(args.src_node),
.payload_index = payload_index,
} },
});
gz.instructions.appendAssumeCapacity(new_index);
- return gz.astgen.indexToRef(new_index);
+ return gz.indexToRef(new_index);
}
pub fn addCall(
@@ -1255,7 +1328,7 @@ pub const Scope = struct {
) !Zir.Inst.Ref {
assert(callee != .none);
assert(src_node != 0);
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
@@ -1271,12 +1344,12 @@ pub const Scope = struct {
gz.astgen.instructions.appendAssumeCapacity(.{
.tag = tag,
.data = .{ .pl_node = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
+ .src_node = gz.nodeIndexToRelative(src_node),
.payload_index = payload_index,
} },
});
gz.instructions.appendAssumeCapacity(new_index);
- return gz.astgen.indexToRef(new_index);
+ return gz.indexToRef(new_index);
}
/// Note that this returns a `Zir.Inst.Index` not a ref.
@@ -1287,7 +1360,7 @@ pub const Scope = struct {
lhs: Zir.Inst.Ref,
) !Zir.Inst.Index {
assert(lhs != .none);
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
@@ -1314,7 +1387,7 @@ pub const Scope = struct {
return gz.add(.{
.tag = .float,
.data = .{ .float = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
+ .src_node = gz.nodeIndexToRelative(src_node),
.number = number,
} },
});
@@ -1332,7 +1405,7 @@ pub const Scope = struct {
.tag = tag,
.data = .{ .un_node = .{
.operand = operand,
- .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
+ .src_node = gz.nodeIndexToRelative(src_node),
} },
});
}
@@ -1344,7 +1417,7 @@ pub const Scope = struct {
src_node: ast.Node.Index,
extra: anytype,
) !Zir.Inst.Ref {
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
@@ -1353,12 +1426,12 @@ pub const Scope = struct {
gz.astgen.instructions.appendAssumeCapacity(.{
.tag = tag,
.data = .{ .pl_node = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
+ .src_node = gz.nodeIndexToRelative(src_node),
.payload_index = payload_index,
} },
});
gz.instructions.appendAssumeCapacity(new_index);
- return gz.astgen.indexToRef(new_index);
+ return gz.indexToRef(new_index);
}
pub fn addArrayTypeSentinel(
@@ -1367,7 +1440,7 @@ pub const Scope = struct {
sentinel: Zir.Inst.Ref,
elem_type: Zir.Inst.Ref,
) !Zir.Inst.Ref {
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
@@ -1384,7 +1457,7 @@ pub const Scope = struct {
} },
});
gz.instructions.appendAssumeCapacity(new_index);
- return gz.astgen.indexToRef(new_index);
+ return gz.indexToRef(new_index);
}
pub fn addUnTok(
@@ -1399,7 +1472,7 @@ pub const Scope = struct {
.tag = tag,
.data = .{ .un_tok = .{
.operand = operand,
- .src_tok = abs_tok_index - gz.astgen.decl.srcToken(),
+ .src_tok = gz.tokenIndexToRelative(abs_tok_index),
} },
});
}
@@ -1415,7 +1488,7 @@ pub const Scope = struct {
.tag = tag,
.data = .{ .str_tok = .{
.start = str_index,
- .src_tok = abs_tok_index - gz.astgen.decl.srcToken(),
+ .src_tok = gz.tokenIndexToRelative(abs_tok_index),
} },
});
}
@@ -1461,7 +1534,7 @@ pub const Scope = struct {
return gz.add(.{
.tag = tag,
.data = .{ .pl_node = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
+ .src_node = gz.nodeIndexToRelative(src_node),
.payload_index = decl_index,
} },
});
@@ -1475,7 +1548,7 @@ pub const Scope = struct {
) !Zir.Inst.Ref {
return gz.add(.{
.tag = tag,
- .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(src_node) },
+ .data = .{ .node = gz.nodeIndexToRelative(src_node) },
});
}
@@ -1500,11 +1573,11 @@ pub const Scope = struct {
/// Leaves the `payload_index` field undefined.
pub fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.astgen.instructions.append(gpa, .{
.tag = tag,
.data = .{ .pl_node = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(node),
+ .src_node = gz.nodeIndexToRelative(node),
.payload_index = undefined,
} },
});
@@ -1514,13 +1587,13 @@ pub const Scope = struct {
/// Note that this returns a `Zir.Inst.Index` not a ref.
/// Leaves the `payload_index` field undefined.
pub fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
try gz.astgen.instructions.append(gpa, .{
.tag = tag,
.data = .{ .pl_node = .{
- .src_node = gz.astgen.decl.nodeIndexToRelative(node),
+ .src_node = gz.nodeIndexToRelative(node),
.payload_index = undefined,
} },
});
@@ -1529,11 +1602,11 @@ pub const Scope = struct {
}
pub fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {
- return gz.astgen.indexToRef(try gz.addAsIndex(inst));
+ return gz.indexToRef(try gz.addAsIndex(inst));
}
pub fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index {
- const gpa = gz.astgen.mod.gpa;
+ const gpa = gz.astgen.gpa;
try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
@@ -1556,7 +1629,7 @@ pub const Scope = struct {
name: []const u8,
inst: Zir.Inst.Ref,
/// Source location of the corresponding variable declaration.
- src: LazySrcLoc,
+ token_src: ast.TokenIndex,
};
/// This could be a `const` or `var` local. It has a pointer instead of a value.
@@ -1571,7 +1644,7 @@ pub const Scope = struct {
name: []const u8,
ptr: Zir.Inst.Ref,
/// Source location of the corresponding variable declaration.
- src: LazySrcLoc,
+ token_src: ast.TokenIndex,
};
pub const DeclRef = struct {
@@ -1653,6 +1726,7 @@ pub const SrcLoc = struct {
.byte_abs,
.token_abs,
.node_abs,
+ .entire_file,
=> src_loc.container.file_scope,
.byte_offset,
@@ -1686,16 +1760,17 @@ pub const SrcLoc = struct {
pub fn byteOffset(src_loc: SrcLoc) !u32 {
switch (src_loc.lazy) {
.unneeded => unreachable,
+ .entire_file => unreachable,
.byte_abs => |byte_index| return byte_index,
.token_abs => |tok_index| {
- const tree = src_loc.container.file_scope.base.tree();
+ const tree = src_loc.container.file_scope.tree;
const token_starts = tree.tokens.items(.start);
return token_starts[tok_index];
},
.node_abs => |node| {
- const tree = src_loc.container.file_scope.base.tree();
+ const tree = src_loc.container.file_scope.tree;
const token_starts = tree.tokens.items(.start);
const tok_index = tree.firstToken(node);
return token_starts[tok_index];
@@ -1707,14 +1782,14 @@ pub const SrcLoc = struct {
.token_offset => |tok_off| {
const decl = src_loc.container.decl;
const tok_index = decl.srcToken() + tok_off;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const token_starts = tree.tokens.items(.start);
return token_starts[tok_index];
},
.node_offset, .node_offset_bin_op => |node_off| {
const decl = src_loc.container.decl;
const node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const main_tokens = tree.nodes.items(.main_token);
const tok_index = main_tokens[node];
const token_starts = tree.tokens.items(.start);
@@ -1723,7 +1798,7 @@ pub const SrcLoc = struct {
.node_offset_back2tok => |node_off| {
const decl = src_loc.container.decl;
const node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const tok_index = tree.firstToken(node) - 2;
const token_starts = tree.tokens.items(.start);
return token_starts[tok_index];
@@ -1731,7 +1806,7 @@ pub const SrcLoc = struct {
.node_offset_var_decl_ty => |node_off| {
const decl = src_loc.container.decl;
const node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_tags = tree.nodes.items(.tag);
const full = switch (node_tags[node]) {
.global_var_decl => tree.globalVarDecl(node),
@@ -1751,7 +1826,7 @@ pub const SrcLoc = struct {
},
.node_offset_builtin_call_arg0 => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1767,7 +1842,7 @@ pub const SrcLoc = struct {
},
.node_offset_builtin_call_arg1 => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1783,7 +1858,7 @@ pub const SrcLoc = struct {
},
.node_offset_array_access_index => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1794,7 +1869,7 @@ pub const SrcLoc = struct {
},
.node_offset_slice_sentinel => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1811,7 +1886,7 @@ pub const SrcLoc = struct {
},
.node_offset_call_func => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1838,7 +1913,7 @@ pub const SrcLoc = struct {
},
.node_offset_field_name => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1851,7 +1926,7 @@ pub const SrcLoc = struct {
},
.node_offset_deref_ptr => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1861,7 +1936,7 @@ pub const SrcLoc = struct {
},
.node_offset_asm_source => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1877,7 +1952,7 @@ pub const SrcLoc = struct {
},
.node_offset_asm_ret_ty => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -1895,7 +1970,7 @@ pub const SrcLoc = struct {
.node_offset_for_cond, .node_offset_if_cond => |node_off| {
const decl = src_loc.container.decl;
const node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_tags = tree.nodes.items(.tag);
const src_node = switch (node_tags[node]) {
.if_simple => tree.ifSimple(node).ast.cond_expr,
@@ -1915,7 +1990,7 @@ pub const SrcLoc = struct {
.node_offset_bin_lhs => |node_off| {
const decl = src_loc.container.decl;
const node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const src_node = node_datas[node].lhs;
const main_tokens = tree.nodes.items(.main_token);
@@ -1926,7 +2001,7 @@ pub const SrcLoc = struct {
.node_offset_bin_rhs => |node_off| {
const decl = src_loc.container.decl;
const node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const src_node = node_datas[node].rhs;
const main_tokens = tree.nodes.items(.main_token);
@@ -1938,7 +2013,7 @@ pub const SrcLoc = struct {
.node_offset_switch_operand => |node_off| {
const decl = src_loc.container.decl;
const node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const src_node = node_datas[node].lhs;
const main_tokens = tree.nodes.items(.main_token);
@@ -1950,7 +2025,7 @@ pub const SrcLoc = struct {
.node_offset_switch_special_prong => |node_off| {
const decl = src_loc.container.decl;
const switch_node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
@@ -1977,7 +2052,7 @@ pub const SrcLoc = struct {
.node_offset_switch_range => |node_off| {
const decl = src_loc.container.decl;
const switch_node = decl.relativeToNodeIndex(node_off);
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
@@ -2007,7 +2082,7 @@ pub const SrcLoc = struct {
.node_offset_fn_type_cc => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -2027,7 +2102,7 @@ pub const SrcLoc = struct {
.node_offset_fn_type_ret_ty => |node_off| {
const decl = src_loc.container.decl;
- const tree = decl.namespace.file_scope.base.tree();
+ const tree = decl.namespace.file_scope.tree;
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = decl.relativeToNodeIndex(node_off);
@@ -2063,6 +2138,9 @@ pub const LazySrcLoc = union(enum) {
/// look into using reverse-continue with a memory watchpoint to see where the
/// value is being set to this tag.
unneeded,
+ /// Means the source location points to an entire file; not any particular
+ /// location within the file. `file_scope` union field will be active.
+ entire_file,
/// The source location points to a byte offset within a source file,
/// offset from 0. The source file is determined contextually.
/// Inside a `SrcLoc`, the `file_scope` union field will be active.
@@ -2205,6 +2283,7 @@ pub const LazySrcLoc = union(enum) {
pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {
return switch (lazy) {
.unneeded,
+ .entire_file,
.byte_abs,
.token_abs,
.node_abs,
@@ -2248,6 +2327,7 @@ pub const LazySrcLoc = union(enum) {
pub fn toSrcLocWithDecl(lazy: LazySrcLoc, decl: *Decl) SrcLoc {
return switch (lazy) {
.unneeded,
+ .entire_file,
.byte_abs,
.token_abs,
.node_abs,
@@ -2376,6 +2456,108 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
gpa.free(export_list);
}
+pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {
+ const comp = mod.comp;
+ const gpa = mod.gpa;
+
+ // In any case we need to examine the stat of the file to determine the course of action.
+ var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
+ defer f.close();
+
+ const stat = try f.stat();
+
+ // Determine whether we need to reload the file from disk and redo parsing and AstGen.
+ switch (file.status) {
+ .never_loaded, .retryable_failure => {},
+ .parse_failure, .astgen_failure, .success => {
+ const unchanged_metadata =
+ stat.size == file.stat_size and
+ stat.mtime == file.stat_mtime and
+ stat.inode == file.stat_inode;
+
+ if (unchanged_metadata) {
+ log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
+ return;
+ }
+
+ log.debug("metadata changed: {s}", .{file.sub_file_path});
+ },
+ }
+ // Clear compile error for this file.
+ switch (file.status) {
+ .success, .retryable_failure => {},
+ .never_loaded, .parse_failure, .astgen_failure => {
+ const lock = comp.mutex.acquire();
+ defer lock.release();
+ if (mod.failed_files.swapRemove(file)) |entry| {
+ entry.value.destroy(gpa); // Delete previous error message.
+ }
+ },
+ }
+ file.unload(gpa);
+
+ if (stat.size > std.math.maxInt(u32))
+ return error.FileTooBig;
+
+ const source = try gpa.allocSentinel(u8, stat.size, 0);
+ defer if (!file.source_loaded) gpa.free(source);
+ const amt = try f.readAll(source);
+ if (amt != stat.size)
+ return error.UnexpectedEndOfFile;
+
+ file.stat_size = stat.size;
+ file.stat_inode = stat.inode;
+ file.stat_mtime = stat.mtime;
+ file.source = source;
+ file.source_loaded = true;
+
+ file.tree = try std.zig.parse(gpa, source);
+ defer if (!file.tree_loaded) file.tree.deinit(gpa);
+
+ if (file.tree.errors.len != 0) {
+ const parse_err = file.tree.errors[0];
+
+ var msg = std.ArrayList(u8).init(gpa);
+ defer msg.deinit();
+
+ const token_starts = file.tree.tokens.items(.start);
+
+ try file.tree.renderError(parse_err, msg.writer());
+ const err_msg = try gpa.create(ErrorMsg);
+ err_msg.* = .{
+ .src_loc = .{
+ .container = .{ .file_scope = file },
+ .lazy = .{ .byte_abs = token_starts[parse_err.token] },
+ },
+ .msg = msg.toOwnedSlice(),
+ };
+
+ {
+ const lock = comp.mutex.acquire();
+ defer lock.release();
+ try mod.failed_files.putNoClobber(gpa, file, err_msg);
+ }
+ file.status = .parse_failure;
+ return error.AnalysisFail;
+ }
+ file.tree_loaded = true;
+
+ file.zir = try AstGen.generate(gpa, file);
+ file.zir_loaded = true;
+
+ if (file.zir.extra[1] != 0) {
+ {
+ const lock = comp.mutex.acquire();
+ defer lock.release();
+ try mod.failed_files.putNoClobber(gpa, file, undefined);
+ }
+ file.status = .astgen_failure;
+ return error.AnalysisFail;
+ }
+
+ file.status = .success;
+}
+
pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
const tracy = trace(@src());
defer tracy.end();
@@ -2417,7 +2599,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
.unreferenced => false,
};
- const type_changed = mod.astgenAndSemaDecl(decl) catch |err| switch (err) {
+ const type_changed = mod.semaDecl(decl) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => return error.AnalysisFail,
else => {
@@ -2462,822 +2644,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
/// Returns `true` if the Decl type changed.
/// Returns `true` if this is the first time analyzing the Decl.
/// Returns `false` otherwise.
-fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
+fn semaDecl(mod: *Module, decl: *Decl) !bool {
const tracy = trace(@src());
defer tracy.end();
- const tree = try mod.getAstTree(decl.namespace.file_scope);
- const node_tags = tree.nodes.items(.tag);
- const node_datas = tree.nodes.items(.data);
- const decl_node = decl.src_node;
- switch (node_tags[decl_node]) {
- .fn_decl => {
- const fn_proto = node_datas[decl_node].lhs;
- const body = node_datas[decl_node].rhs;
- switch (node_tags[fn_proto]) {
- .fn_proto_simple => {
- var params: [1]ast.Node.Index = undefined;
- return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoSimple(&params, fn_proto));
- },
- .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoMulti(fn_proto)),
- .fn_proto_one => {
- var params: [1]ast.Node.Index = undefined;
- return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoOne(&params, fn_proto));
- },
- .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProto(fn_proto)),
- else => unreachable,
- }
- },
- .fn_proto_simple => {
- var params: [1]ast.Node.Index = undefined;
- return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoSimple(&params, decl_node));
- },
- .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoMulti(decl_node)),
- .fn_proto_one => {
- var params: [1]ast.Node.Index = undefined;
- return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoOne(&params, decl_node));
- },
- .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProto(decl_node)),
-
- .global_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.globalVarDecl(decl_node)),
- .local_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.localVarDecl(decl_node)),
- .simple_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.simpleVarDecl(decl_node)),
- .aligned_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.alignedVarDecl(decl_node)),
-
- .@"comptime" => {
- decl.analysis = .in_progress;
-
- // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
- 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,
- .arena = &analysis_arena.allocator,
- .code = code,
- .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- _ = try sema.root(&block_scope);
-
- decl.analysis = .complete;
- decl.generation = mod.generation;
- return true;
- },
- .@"usingnamespace" => {
- decl.analysis = .in_progress;
-
- const type_expr = node_datas[decl_node].lhs;
- const is_pub = blk: {
- const main_tokens = tree.nodes.items(.main_token);
- const token_tags = tree.tokens.items(.tag);
- const main_token = main_tokens[decl_node];
- break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub);
- };
-
- // A usingnamespace decl does not store any value so we can
- // deinit this arena after analysis is done.
- 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 ns_type = try AstGen.typeExpr(&gen_scope, &gen_scope.base, type_expr);
- _ = try gen_scope.addBreak(.break_inline, 0, ns_type);
-
- const code = try gen_scope.finish();
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(mod.gpa, "usingnamespace_type", &gen_scope.base, 0) catch {};
- }
- break :blk code;
- };
- defer code.deinit(mod.gpa);
-
- var sema: Sema = .{
- .mod = mod,
- .gpa = mod.gpa,
- .arena = &analysis_arena.allocator,
- .code = code,
- .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- const ty = try sema.rootAsType(&block_scope);
- try decl.namespace.usingnamespace_set.put(mod.gpa, ty.getNamespace().?, is_pub);
-
- decl.analysis = .complete;
- decl.generation = mod.generation;
- return true;
- },
- else => unreachable,
- }
-}
-
-fn astgenAndSemaFn(
- mod: *Module,
- decl: *Decl,
- tree: ast.Tree,
- body_node: ast.Node.Index,
- fn_proto: ast.full.FnProto,
-) !bool {
- const tracy = trace(@src());
- defer tracy.end();
-
- decl.analysis = .in_progress;
-
- const token_tags = tree.tokens.items(.tag);
-
- // This arena allocator's memory is discarded at the end of this function. It is used
- // to determine the type of the function, and hence the type of the decl, which is needed
- // to complete the Decl analysis.
- var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
- defer fn_type_scope_arena.deinit();
-
- var fn_type_astgen = try AstGen.init(mod, decl, &fn_type_scope_arena.allocator);
- defer fn_type_astgen.deinit();
-
- var fn_type_scope: Scope.GenZir = .{
- .force_comptime = true,
- .parent = &decl.namespace.base,
- .astgen = &fn_type_astgen,
- };
- defer fn_type_scope.instructions.deinit(mod.gpa);
-
- decl.is_pub = fn_proto.visib_token != null;
-
- // The AST params array does not contain anytype and ... parameters.
- // We must iterate to count how many param types to allocate.
- const param_count = blk: {
- var count: usize = 0;
- var it = fn_proto.iterate(tree);
- while (it.next()) |param| {
- if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;
- count += 1;
- }
- break :blk count;
- };
- const param_types = try fn_type_scope_arena.allocator.alloc(Zir.Inst.Ref, param_count);
-
- var is_var_args = false;
- {
- var param_type_i: usize = 0;
- var it = fn_proto.iterate(tree);
- while (it.next()) |param| : (param_type_i += 1) {
- if (param.anytype_ellipsis3) |token| {
- switch (token_tags[token]) {
- .keyword_anytype => return mod.failTok(
- &fn_type_scope.base,
- token,
- "TODO implement anytype parameter",
- .{},
- ),
- .ellipsis3 => {
- is_var_args = true;
- break;
- },
- else => unreachable,
- }
- }
- const param_type_node = param.type_expr;
- assert(param_type_node != 0);
- param_types[param_type_i] =
- try AstGen.expr(&fn_type_scope, &fn_type_scope.base, .{ .ty = .type_type }, param_type_node);
- }
- assert(param_type_i == param_count);
- }
- if (fn_proto.lib_name) |lib_name_token| blk: {
- // TODO call std.zig.parseStringLiteral
- const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name_token), "\"");
- log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
- const target = mod.comp.getTarget();
- if (target_util.is_libc_lib_name(target, lib_name_str)) {
- if (!mod.comp.bin_file.options.link_libc) {
- return mod.failTok(
- &fn_type_scope.base,
- lib_name_token,
- "dependency on libc must be explicitly specified in the build command",
- .{},
- );
- }
- break :blk;
- }
- if (target_util.is_libcpp_lib_name(target, lib_name_str)) {
- if (!mod.comp.bin_file.options.link_libcpp) {
- return mod.failTok(
- &fn_type_scope.base,
- lib_name_token,
- "dependency on libc++ must be explicitly specified in the build command",
- .{},
- );
- }
- break :blk;
- }
- if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
- return mod.failTok(
- &fn_type_scope.base,
- lib_name_token,
- "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
- .{ lib_name_str, lib_name_str },
- );
- }
- mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
- return mod.failTok(
- &fn_type_scope.base,
- lib_name_token,
- "unable to add link lib '{s}': {s}",
- .{ lib_name_str, @errorName(err) },
- );
- };
- }
- if (fn_proto.ast.align_expr != 0) {
- return mod.failNode(
- &fn_type_scope.base,
- fn_proto.ast.align_expr,
- "TODO implement function align expression",
- .{},
- );
- }
- if (fn_proto.ast.section_expr != 0) {
- return mod.failNode(
- &fn_type_scope.base,
- fn_proto.ast.section_expr,
- "TODO implement function section expression",
- .{},
- );
- }
-
- const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
- if (token_tags[maybe_bang] == .bang) {
- return mod.failTok(&fn_type_scope.base, maybe_bang, "TODO implement inferred error sets", .{});
- }
- const return_type_inst = try AstGen.expr(
- &fn_type_scope,
- &fn_type_scope.base,
- .{ .ty = .type_type },
- fn_proto.ast.return_type,
- );
-
- const is_extern = if (fn_proto.extern_export_token) |maybe_export_token|
- token_tags[maybe_export_token] == .keyword_extern
- else
- false;
-
- const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
- // TODO instead of enum literal type, this needs to be the
- // std.builtin.CallingConvention enum. We need to implement importing other files
- // and enums in order to fix this.
- try AstGen.comptimeExpr(
- &fn_type_scope,
- &fn_type_scope.base,
- .{ .ty = .enum_literal_type },
- fn_proto.ast.callconv_expr,
- )
- else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269
- try fn_type_scope.addSmallStr(.enum_literal_small, "C")
- else
- .none;
-
- const fn_type_inst: Zir.Inst.Ref = if (cc != .none) fn_type: {
- const tag: Zir.Inst.Tag = if (is_var_args) .fn_type_cc_var_args else .fn_type_cc;
- break :fn_type try fn_type_scope.addFnTypeCc(tag, .{
- .src_node = fn_proto.ast.proto_node,
- .ret_ty = return_type_inst,
- .param_types = param_types,
- .cc = cc,
- });
- } else fn_type: {
- const tag: Zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type;
- break :fn_type try fn_type_scope.addFnType(tag, .{
- .src_node = fn_proto.ast.proto_node,
- .ret_ty = return_type_inst,
- .param_types = param_types,
- });
- };
- _ = try fn_type_scope.addBreak(.break_inline, 0, fn_type_inst);
-
- // We need the memory for the Type to go into the arena for the Decl
- var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
- errdefer decl_arena.deinit();
- const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
-
- var fn_type_code = try fn_type_scope.finish();
- defer fn_type_code.deinit(mod.gpa);
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- fn_type_code.dump(mod.gpa, "fn_type", &fn_type_scope.base, 0) catch {};
- }
-
- var fn_type_sema: Sema = .{
- .mod = mod,
- .gpa = mod.gpa,
- .arena = &decl_arena.allocator,
- .code = fn_type_code,
- .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &fn_type_sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- const fn_type = try fn_type_sema.rootAsType(&block_scope);
- if (body_node == 0) {
- if (!is_extern) {
- return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});
- }
-
- // Extern function.
- var type_changed = true;
- if (decl.typedValueManaged()) |tvm| {
- type_changed = !tvm.typed_value.ty.eql(fn_type);
-
- tvm.deinit(mod.gpa);
- }
- const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl);
-
- decl_arena_state.* = decl_arena.state;
- decl.typed_value = .{
- .most_recent = .{
- .typed_value = .{ .ty = fn_type, .val = fn_val },
- .arena = decl_arena_state,
- },
- };
- decl.analysis = .complete;
- decl.generation = mod.generation;
-
- try mod.comp.bin_file.allocateDeclIndexes(decl);
- try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
-
- if (type_changed and mod.emit_h != null) {
- try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
- }
-
- return type_changed;
- }
-
- if (fn_type.fnIsVarArgs()) {
- return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
- }
-
- const new_func = try decl_arena.allocator.create(Fn);
- const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
-
- const fn_zir: Zir = blk: {
- // We put the ZIR inside the Decl arena.
- var astgen = try AstGen.init(mod, decl, &decl_arena.allocator);
- astgen.ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count);
- defer astgen.deinit();
-
- var gen_scope: Scope.GenZir = .{
- .force_comptime = false,
- .parent = &decl.namespace.base,
- .astgen = &astgen,
- };
- defer gen_scope.instructions.deinit(mod.gpa);
-
- // Iterate over the parameters. We put the param names as the first N
- // items inside `extra` so that debug info later can refer to the parameter names
- // even while the respective source code is unloaded.
- try astgen.extra.ensureCapacity(mod.gpa, param_count);
-
- var params_scope = &gen_scope.base;
- var i: usize = 0;
- var it = fn_proto.iterate(tree);
- while (it.next()) |param| : (i += 1) {
- const name_token = param.name_token.?;
- const param_name = try mod.identifierTokenString(&gen_scope.base, name_token);
- const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
- sub_scope.* = .{
- .parent = params_scope,
- .gen_zir = &gen_scope,
- .name = param_name,
- // Implicit const list first, then implicit arg list.
- .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
- .src = decl.tokSrcLoc(name_token),
- };
- params_scope = &sub_scope.base;
-
- // Additionally put the param name into `string_bytes` and reference it with
- // `extra` so that we have access to the data in codegen, for debug info.
- const str_index = @intCast(u32, astgen.string_bytes.items.len);
- astgen.extra.appendAssumeCapacity(str_index);
- const used_bytes = astgen.string_bytes.items.len;
- try astgen.string_bytes.ensureCapacity(mod.gpa, used_bytes + param_name.len + 1);
- astgen.string_bytes.appendSliceAssumeCapacity(param_name);
- astgen.string_bytes.appendAssumeCapacity(0);
- }
-
- _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node);
-
- if (gen_scope.instructions.items.len == 0 or
- !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
- .isNoReturn())
- {
- // astgen uses result location semantics to coerce return operands.
- // Since we are adding the return instruction here, we must handle the coercion.
- // We do this by using the `ret_coerce` instruction.
- _ = try gen_scope.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
- }
-
- const code = try gen_scope.finish();
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(mod.gpa, "fn_body", &gen_scope.base, param_count) catch {};
- }
-
- break :blk code;
- };
-
- const is_inline = fn_type.fnCallingConvention() == .Inline;
- const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
-
- new_func.* = .{
- .state = anal_state,
- .zir = fn_zir,
- .body = undefined,
- .owner_decl = decl,
- };
- fn_payload.* = .{
- .base = .{ .tag = .function },
- .data = new_func,
- };
-
- var prev_type_has_bits = false;
- var prev_is_inline = false;
- var type_changed = true;
-
- if (decl.typedValueManaged()) |tvm| {
- prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
- type_changed = !tvm.typed_value.ty.eql(fn_type);
- if (tvm.typed_value.val.castTag(.function)) |payload| {
- const prev_func = payload.data;
- prev_is_inline = prev_func.state == .inline_only;
- prev_func.deinit(mod.gpa);
- }
-
- tvm.deinit(mod.gpa);
- }
-
- decl_arena_state.* = decl_arena.state;
- decl.typed_value = .{
- .most_recent = .{
- .typed_value = .{
- .ty = fn_type,
- .val = Value.initPayload(&fn_payload.base),
- },
- .arena = decl_arena_state,
- },
- };
- decl.analysis = .complete;
- decl.generation = mod.generation;
-
- if (!is_inline and fn_type.hasCodeGenBits()) {
- // We don't fully codegen the decl until later, but we do need to reserve a global
- // offset table index for it. This allows us to codegen decls out of dependency order,
- // increasing how many computations can be done in parallel.
- try mod.comp.bin_file.allocateDeclIndexes(decl);
- try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
- if (type_changed and mod.emit_h != null) {
- try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
- }
- } else if (!prev_is_inline and prev_type_has_bits) {
- mod.comp.bin_file.freeDecl(decl);
- }
-
- if (fn_proto.extern_export_token) |maybe_export_token| {
- if (token_tags[maybe_export_token] == .keyword_export) {
- if (is_inline) {
- return mod.failTok(
- &block_scope.base,
- maybe_export_token,
- "export of inline function",
- .{},
- );
- }
- const export_src = decl.tokSrcLoc(maybe_export_token);
- const name = tree.tokenSlice(fn_proto.name_token.?); // TODO identifierTokenString
- // The scope needs to have the decl in it.
- try mod.analyzeExport(&block_scope.base, export_src, name, decl);
- }
- }
- return type_changed or is_inline != prev_is_inline;
-}
-
-fn astgenAndSemaVarDecl(
- mod: *Module,
- decl: *Decl,
- tree: ast.Tree,
- var_decl: ast.full.VarDecl,
-) !bool {
- const tracy = trace(@src());
- defer tracy.end();
-
- decl.analysis = .in_progress;
- decl.is_pub = var_decl.visib_token != null;
-
- const token_tags = tree.tokens.items(.tag);
-
- // We need the memory for the Type to go into the arena for the Decl
- var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
- errdefer decl_arena.deinit();
- const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
-
- // Used for simple error reporting.
- var decl_scope: Scope.DeclRef = .{ .decl = decl };
-
- const is_extern = blk: {
- const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
- break :blk token_tags[maybe_extern_token] == .keyword_extern;
- };
-
- if (var_decl.lib_name) |lib_name| {
- assert(is_extern);
- return mod.failTok(&decl_scope.base, lib_name, "TODO implement function library name", .{});
- }
- const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
- const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: {
- if (!is_mutable) {
- return mod.failTok(&decl_scope.base, some, "threadlocal variable cannot be constant", .{});
- }
- break :blk true;
- } else false;
- assert(var_decl.comptime_token == null);
- if (var_decl.ast.align_node != 0) {
- return mod.failNode(
- &decl_scope.base,
- var_decl.ast.align_node,
- "TODO implement function align expression",
- .{},
- );
- }
- if (var_decl.ast.section_node != 0) {
- return mod.failNode(
- &decl_scope.base,
- var_decl.ast.section_node,
- "TODO implement function section expression",
- .{},
- );
- }
-
- const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {
- if (is_extern) {
- return mod.failNode(
- &decl_scope.base,
- var_decl.ast.init_node,
- "extern variables have no initializers",
- .{},
- );
- }
-
- var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
- defer gen_scope_arena.deinit();
-
- var astgen = try AstGen.init(mod, decl, &gen_scope_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 init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{
- .ty = try AstGen.expr(&gen_scope, &gen_scope.base, .{ .ty = .type_type }, var_decl.ast.type_node),
- } else .none;
-
- const init_inst = try AstGen.comptimeExpr(
- &gen_scope,
- &gen_scope.base,
- init_result_loc,
- var_decl.ast.init_node,
- );
- _ = try gen_scope.addBreak(.break_inline, 0, init_inst);
- var code = try gen_scope.finish();
- defer code.deinit(mod.gpa);
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
- }
-
- var sema: Sema = .{
- .mod = mod,
- .gpa = mod.gpa,
- .arena = &gen_scope_arena.allocator,
- .code = code,
- .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
- // The result location guarantees the type coercion.
- const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref);
- // The is_comptime in the Scope.Block guarantees the result is comptime-known.
- const val = analyzed_init_inst.value().?;
-
- break :vi .{
- .ty = try analyzed_init_inst.ty.copy(&decl_arena.allocator),
- .val = try val.copy(&decl_arena.allocator),
- };
- } else if (!is_extern) {
- return mod.failTok(
- &decl_scope.base,
- var_decl.ast.mut_token,
- "variables must be initialized",
- .{},
- );
- } else if (var_decl.ast.type_node != 0) vi: {
- var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
- defer type_scope_arena.deinit();
-
- var astgen = try AstGen.init(mod, decl, &type_scope_arena.allocator);
- defer astgen.deinit();
-
- var type_scope: Scope.GenZir = .{
- .force_comptime = true,
- .parent = &decl.namespace.base,
- .astgen = &astgen,
- };
- defer type_scope.instructions.deinit(mod.gpa);
-
- const var_type = try AstGen.typeExpr(&type_scope, &type_scope.base, var_decl.ast.type_node);
- _ = try type_scope.addBreak(.break_inline, 0, var_type);
-
- var code = try type_scope.finish();
- defer code.deinit(mod.gpa);
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
- }
-
- var sema: Sema = .{
- .mod = mod,
- .gpa = mod.gpa,
- .arena = &type_scope_arena.allocator,
- .code = code,
- .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- const ty = try sema.rootAsType(&block_scope);
-
- break :vi .{
- .ty = try ty.copy(&decl_arena.allocator),
- .val = null,
- };
- } else {
- return mod.failTok(
- &decl_scope.base,
- var_decl.ast.mut_token,
- "unable to infer variable type",
- .{},
- );
- };
-
- if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
- return mod.failTok(
- &decl_scope.base,
- var_decl.ast.mut_token,
- "variable of type '{}' must be const",
- .{var_info.ty},
- );
- }
-
- var type_changed = true;
- if (decl.typedValueManaged()) |tvm| {
- type_changed = !tvm.typed_value.ty.eql(var_info.ty);
-
- tvm.deinit(mod.gpa);
- }
-
- const new_variable = try decl_arena.allocator.create(Var);
- new_variable.* = .{
- .owner_decl = decl,
- .init = var_info.val orelse undefined,
- .is_extern = is_extern,
- .is_mutable = is_mutable,
- .is_threadlocal = is_threadlocal,
- };
- const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
-
- decl_arena_state.* = decl_arena.state;
- decl.typed_value = .{
- .most_recent = .{
- .typed_value = .{
- .ty = var_info.ty,
- .val = var_val,
- },
- .arena = decl_arena_state,
- },
- };
- decl.analysis = .complete;
- decl.generation = mod.generation;
-
- if (var_decl.extern_export_token) |maybe_export_token| {
- if (token_tags[maybe_export_token] == .keyword_export) {
- const export_src = decl.tokSrcLoc(maybe_export_token);
- const name_token = var_decl.ast.mut_token + 1;
- const name = tree.tokenSlice(name_token); // TODO identifierTokenString
- // The scope needs to have the decl in it.
- try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
- }
- }
- return type_changed;
+ @panic("TODO implement semaDecl");
}
/// Returns the depender's index of the dependee.
-pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 {
+pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);
try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1);
@@ -3287,61 +2662,7 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3
}
dependee.dependants.putAssumeCapacity(depender, {});
- const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);
- return @intCast(u32, gop.index);
-}
-
-pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree {
- const tracy = trace(@src());
- defer tracy.end();
-
- switch (file.status) {
- .never_loaded, .unloaded_success => {
- const gpa = mod.gpa;
-
- try mod.failed_files.ensureCapacity(gpa, mod.failed_files.items().len + 1);
-
- const source = try file.getSource(gpa);
-
- var keep_tree = false;
- file.tree = try std.zig.parse(gpa, source);
- defer if (!keep_tree) file.tree.deinit(gpa);
-
- const tree = &file.tree;
-
- if (tree.errors.len != 0) {
- const parse_err = tree.errors[0];
-
- var msg = std.ArrayList(u8).init(gpa);
- defer msg.deinit();
-
- const token_starts = tree.tokens.items(.start);
-
- try tree.renderError(parse_err, msg.writer());
- const err_msg = try gpa.create(ErrorMsg);
- err_msg.* = .{
- .src_loc = .{
- .container = .{ .file_scope = file },
- .lazy = .{ .byte_abs = token_starts[parse_err.token] },
- },
- .msg = msg.toOwnedSlice(),
- };
-
- mod.failed_files.putAssumeCapacityNoClobber(file, err_msg);
- file.status = .unloaded_parse_failure;
- return error.AnalysisFail;
- }
-
- file.status = .loaded_success;
- keep_tree = true;
-
- return tree;
- },
-
- .unloaded_parse_failure => return error.AnalysisFail,
-
- .loaded_success => return &file.tree,
- }
+ depender.dependencies.putAssumeCapacity(dependee, {});
}
pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*Scope.File {
@@ -3375,136 +2696,21 @@ pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*
.sub_file_path = resolved_path,
.source = undefined,
.source_loaded = false,
+ .tree_loaded = false,
+ .zir_loaded = false,
.stat_size = undefined,
.stat_inode = undefined,
.stat_mtime = undefined,
.tree = undefined,
+ .zir = undefined,
.status = .never_loaded,
.pkg = found_pkg orelse cur_pkg,
.namespace = undefined,
};
keep_resolved_path = true;
-
- const tree = try mod.getAstTree(new_file);
-
- const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg|
- pkg.namespace_hash
- else
- std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
-
- // We need a Decl to pass to AstGen and collect dependencies. But ultimately we
- // want to pass them on to the Decl for the struct that represents the file.
- var tmp_namespace: Scope.Namespace = .{
- .parent = null,
- .file_scope = new_file,
- .parent_name_hash = parent_name_hash,
- .ty = Type.initTag(.type),
- };
-
- const top_decl = try mod.createNewDecl(
- &tmp_namespace,
- resolved_path,
- 0,
- parent_name_hash,
- std.zig.hashSrc(tree.source),
- );
- defer {
- mod.decl_table.removeAssertDiscard(parent_name_hash);
- top_decl.destroy(mod);
- }
-
- var gen_scope_arena = std.heap.ArenaAllocator.init(gpa);
- defer gen_scope_arena.deinit();
-
- var astgen = try AstGen.init(mod, top_decl, &gen_scope_arena.allocator);
- defer astgen.deinit();
-
- var gen_scope: Scope.GenZir = .{
- .force_comptime = true,
- .parent = &new_file.base,
- .astgen = &astgen,
- };
- defer gen_scope.instructions.deinit(gpa);
-
- const container_decl: ast.full.ContainerDecl = .{
- .layout_token = null,
- .ast = .{
- .main_token = undefined,
- .enum_token = null,
- .members = tree.rootDecls(),
- .arg = 0,
- },
- };
-
- const struct_decl_ref = try AstGen.structDeclInner(
- &gen_scope,
- &gen_scope.base,
- 0,
- container_decl,
- .struct_decl,
- );
- _ = try gen_scope.addBreak(.break_inline, 0, struct_decl_ref);
-
- var code = try gen_scope.finish();
- defer code.deinit(gpa);
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(gpa, "import", &gen_scope.base, 0) catch {};
- }
-
- var sema: Sema = .{
- .mod = mod,
- .gpa = gpa,
- .arena = &gen_scope_arena.allocator,
- .code = code,
- .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
- .owner_decl = top_decl,
- .namespace = top_decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = top_decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(gpa);
-
- const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
- const analyzed_struct_inst = try sema.resolveInst(init_inst_zir_ref);
- assert(analyzed_struct_inst.ty.zigTypeTag() == .Type);
- const val = analyzed_struct_inst.value().?;
- const struct_ty = try val.toType(&gen_scope_arena.allocator);
- const struct_decl = struct_ty.getOwnerDecl();
-
- struct_decl.contents_hash = top_decl.contents_hash;
- new_file.namespace = struct_ty.getNamespace().?;
- new_file.namespace.parent = null;
- //new_file.namespace.parent_name_hash = tmp_namespace.parent_name_hash;
-
- // Transfer the dependencies to `owner_decl`.
- assert(top_decl.dependants.count() == 0);
- for (top_decl.dependencies.items()) |entry| {
- const dep = entry.key;
- dep.removeDependant(top_decl);
- if (dep == struct_decl) continue;
- _ = try mod.declareDeclDependency(struct_decl, dep);
- }
-
return new_file;
}
-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);
-}
-
pub fn analyzeNamespace(
mod: *Module,
namespace: *Scope.Namespace,
@@ -3515,7 +2721,7 @@ pub fn analyzeNamespace(
// We may be analyzing it for the first time, or this may be
// an incremental update. This code handles both cases.
- assert(namespace.file_scope.status == .loaded_success); // Caller must ensure tree loaded.
+ assert(namespace.file_scope.tree_loaded); // Caller must ensure tree loaded.
const tree: *const ast.Tree = &namespace.file_scope.tree;
const node_tags = tree.nodes.items(.tag);
const node_datas = tree.nodes.items(.data);
@@ -4449,20 +3655,6 @@ pub fn fail(
return mod.failWithOwnedErrorMsg(scope, err_msg);
}
-/// Same as `fail`, except given an absolute byte offset, and the function sets up the `LazySrcLoc`
-/// for pointing at it relatively by subtracting from the containing `Decl`.
-pub fn failOff(
- mod: *Module,
- scope: *Scope,
- byte_offset: u32,
- comptime format: []const u8,
- args: anytype,
-) InnerError {
- const decl_byte_offset = scope.srcDecl().?.srcByteOffset();
- const src: LazySrcLoc = .{ .byte_offset = byte_offset - decl_byte_offset };
- return mod.fail(scope, src, format, args);
-}
-
/// Same as `fail`, except given a token index, and the function sets up the `LazySrcLoc`
/// for pointing at it relatively by subtracting from the containing `Decl`.
pub fn failTok(
@@ -4491,6 +3683,7 @@ pub fn failNode(
pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {
@setCold(true);
+
{
errdefer err_msg.destroy(mod.gpa);
try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1);
@@ -4507,24 +3700,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In
}
mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg);
},
- .gen_zir => {
- const gen_zir = scope.cast(Scope.GenZir).?;
- gen_zir.astgen.decl.analysis = .sema_failure;
- gen_zir.astgen.decl.generation = mod.generation;
- mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
- },
- .local_val => {
- const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
- gen_zir.astgen.decl.analysis = .sema_failure;
- gen_zir.astgen.decl.generation = mod.generation;
- mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
- },
- .local_ptr => {
- const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
- gen_zir.astgen.decl.analysis = .sema_failure;
- gen_zir.astgen.decl.generation = mod.generation;
- mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
- },
+ .gen_zir, .local_val, .local_ptr => unreachable,
.file => unreachable,
.namespace => unreachable,
.decl_ref => {
@@ -4873,132 +4049,3 @@ pub fn getTarget(mod: Module) Target {
pub fn optimizeMode(mod: Module) std.builtin.Mode {
return mod.comp.bin_file.options.optimize_mode;
}
-
-/// Given an identifier token, obtain the string for it.
-/// If the token uses @"" syntax, parses as a string, reports errors if applicable,
-/// and allocates the result within `scope.arena()`.
-/// Otherwise, returns a reference to the source code bytes directly.
-/// See also `appendIdentStr` and `parseStrLit`.
-pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
- const tree = scope.tree();
- const token_tags = tree.tokens.items(.tag);
- assert(token_tags[token] == .identifier);
- const ident_name = tree.tokenSlice(token);
- if (!mem.startsWith(u8, ident_name, "@")) {
- return ident_name;
- }
- var buf: ArrayListUnmanaged(u8) = .{};
- defer buf.deinit(mod.gpa);
- try parseStrLit(mod, scope, token, &buf, ident_name, 1);
- const duped = try scope.arena().dupe(u8, buf.items);
- return duped;
-}
-
-/// `scope` is only used for error reporting.
-/// The string is stored in `arena` regardless of whether it uses @"" syntax.
-pub fn identifierTokenStringTreeArena(
- mod: *Module,
- scope: *Scope,
- token: ast.TokenIndex,
- tree: *const ast.Tree,
- arena: *Allocator,
-) InnerError![]u8 {
- const token_tags = tree.tokens.items(.tag);
- assert(token_tags[token] == .identifier);
- const ident_name = tree.tokenSlice(token);
- if (!mem.startsWith(u8, ident_name, "@")) {
- return arena.dupe(u8, ident_name);
- }
- var buf: ArrayListUnmanaged(u8) = .{};
- defer buf.deinit(mod.gpa);
- try parseStrLit(mod, scope, token, &buf, ident_name, 1);
- return arena.dupe(u8, buf.items);
-}
-
-/// Given an identifier token, obtain the string for it (possibly parsing as a string
-/// literal if it is @"" syntax), and append the string to `buf`.
-/// See also `identifierTokenString` and `parseStrLit`.
-pub fn appendIdentStr(
- mod: *Module,
- scope: *Scope,
- token: ast.TokenIndex,
- buf: *ArrayListUnmanaged(u8),
-) InnerError!void {
- const tree = scope.tree();
- const token_tags = tree.tokens.items(.tag);
- assert(token_tags[token] == .identifier);
- const ident_name = tree.tokenSlice(token);
- if (!mem.startsWith(u8, ident_name, "@")) {
- return buf.appendSlice(mod.gpa, ident_name);
- } else {
- return mod.parseStrLit(scope, token, buf, ident_name, 1);
- }
-}
-
-/// Appends the result to `buf`.
-pub fn parseStrLit(
- mod: *Module,
- scope: *Scope,
- token: ast.TokenIndex,
- buf: *ArrayListUnmanaged(u8),
- bytes: []const u8,
- offset: u32,
-) InnerError!void {
- const tree = scope.tree();
- const token_starts = tree.tokens.items(.start);
- const raw_string = bytes[offset..];
- var buf_managed = buf.toManaged(mod.gpa);
- const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string);
- buf.* = buf_managed.toUnmanaged();
- switch (try result) {
- .success => return,
- .invalid_character => |bad_index| {
- return mod.failOff(
- scope,
- token_starts[token] + offset + @intCast(u32, bad_index),
- "invalid string literal character: '{c}'",
- .{raw_string[bad_index]},
- );
- },
- .expected_hex_digits => |bad_index| {
- return mod.failOff(
- scope,
- token_starts[token] + offset + @intCast(u32, bad_index),
- "expected hex digits after '\\x'",
- .{},
- );
- },
- .invalid_hex_escape => |bad_index| {
- return mod.failOff(
- scope,
- token_starts[token] + offset + @intCast(u32, bad_index),
- "invalid hex digit: '{c}'",
- .{raw_string[bad_index]},
- );
- },
- .invalid_unicode_escape => |bad_index| {
- return mod.failOff(
- scope,
- token_starts[token] + offset + @intCast(u32, bad_index),
- "invalid unicode digit: '{c}'",
- .{raw_string[bad_index]},
- );
- },
- .missing_matching_rbrace => |bad_index| {
- return mod.failOff(
- scope,
- token_starts[token] + offset + @intCast(u32, bad_index),
- "missing matching '}}' character",
- .{},
- );
- },
- .expected_unicode_digits => |bad_index| {
- return mod.failOff(
- scope,
- token_starts[token] + offset + @intCast(u32, bad_index),
- "expected unicode digits after '\\u'",
- .{},
- );
- },
- }
-}