aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig1805
1 files changed, 772 insertions, 1033 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 283a4f75cc..f857d0997b 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -107,8 +107,17 @@ intern_pool: InternPool = .{},
/// a Decl can have a failed_decls entry but have analysis status of success.
failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
/// Keep track of one `@compileLog` callsite per owner Decl.
-/// The value is the AST node index offset from the Decl.
-compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, i32) = .{},
+/// The value is the source location of the `@compileLog` call, convertible to a `LazySrcLoc`.
+compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, extern struct {
+ base_node_inst: InternPool.TrackedInst.Index,
+ node_offset: i32,
+ pub fn src(self: @This()) LazySrcLoc {
+ return .{
+ .base_node_inst = self.base_node_inst,
+ .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset),
+ };
+ }
+}) = .{},
/// Using a map here for consistency with the other fields here.
/// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator.
failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
@@ -257,9 +266,6 @@ pub const Export = struct {
src: LazySrcLoc,
/// The Decl that performs the export. Note that this is *not* the Decl being exported.
owner_decl: Decl.Index,
- /// The Decl containing the export statement. Inline function calls
- /// may cause this to be different from the owner_decl.
- src_decl: Decl.Index,
exported: Exported,
status: enum {
in_progress,
@@ -278,12 +284,7 @@ pub const Export = struct {
};
pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc {
- const src_decl = mod.declPtr(exp.src_decl);
- return .{
- .file_scope = src_decl.getFileScope(mod),
- .parent_decl_node = src_decl.src_node,
- .lazy = exp.src,
- };
+ return exp.src.upgrade(mod);
}
};
@@ -343,9 +344,6 @@ pub const Decl = struct {
/// there is no parent.
src_namespace: Namespace.Index,
- /// The AST node index of this declaration.
- /// Must be recomputed when the corresponding source file is modified.
- src_node: Ast.Node.Index,
/// Line number corresponding to `src_node`. Stored separately so that source files
/// do not need to be loaded into memory in order to compute debug line numbers.
/// This value is absolute.
@@ -417,26 +415,6 @@ pub const Decl = struct {
return extra.data.getBodies(@intCast(extra.end), zir);
}
- pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
- return @bitCast(offset + @as(i32, @bitCast(decl.src_node)));
- }
-
- pub fn nodeIndexToRelative(decl: Decl, node_index: Ast.Node.Index) i32 {
- return @as(i32, @bitCast(node_index)) - @as(i32, @bitCast(decl.src_node));
- }
-
- pub fn srcLoc(decl: Decl, zcu: *Zcu) SrcLoc {
- return decl.nodeOffsetSrcLoc(0, zcu);
- }
-
- pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32, zcu: *Zcu) SrcLoc {
- return .{
- .file_scope = decl.getFileScope(zcu),
- .parent_decl_node = decl.src_node,
- .lazy = LazySrcLoc.nodeOffset(node_offset),
- };
- }
-
pub fn renderFullyQualifiedName(decl: Decl, zcu: *Zcu, writer: anytype) !void {
if (decl.name_fully_qualified) {
try writer.print("{}", .{decl.name.fmt(&zcu.intern_pool)});
@@ -551,101 +529,6 @@ pub const Decl = struct {
return decl.typeOf(zcu).abiAlignment(zcu);
}
- /// Upgrade a `LazySrcLoc` to a `SrcLoc` based on the `Decl` provided.
- pub fn toSrcLoc(decl: *Decl, lazy: LazySrcLoc, mod: *Module) SrcLoc {
- return switch (lazy) {
- .unneeded,
- .entire_file,
- .byte_abs,
- .token_abs,
- .node_abs,
- => .{
- .file_scope = decl.getFileScope(mod),
- .parent_decl_node = 0,
- .lazy = lazy,
- },
-
- .byte_offset,
- .token_offset,
- .node_offset,
- .node_offset_main_token,
- .node_offset_initializer,
- .node_offset_var_decl_ty,
- .node_offset_var_decl_align,
- .node_offset_var_decl_section,
- .node_offset_var_decl_addrspace,
- .node_offset_var_decl_init,
- .node_offset_builtin_call_arg0,
- .node_offset_builtin_call_arg1,
- .node_offset_builtin_call_arg2,
- .node_offset_builtin_call_arg3,
- .node_offset_builtin_call_arg4,
- .node_offset_builtin_call_arg5,
- .node_offset_ptrcast_operand,
- .node_offset_array_access_index,
- .node_offset_slice_ptr,
- .node_offset_slice_start,
- .node_offset_slice_end,
- .node_offset_slice_sentinel,
- .node_offset_call_func,
- .node_offset_field_name,
- .node_offset_field_name_init,
- .node_offset_deref_ptr,
- .node_offset_asm_source,
- .node_offset_asm_ret_ty,
- .node_offset_if_cond,
- .node_offset_bin_op,
- .node_offset_bin_lhs,
- .node_offset_bin_rhs,
- .node_offset_switch_operand,
- .node_offset_switch_special_prong,
- .node_offset_switch_range,
- .node_offset_switch_prong_capture,
- .node_offset_switch_prong_tag_capture,
- .node_offset_fn_type_align,
- .node_offset_fn_type_addrspace,
- .node_offset_fn_type_section,
- .node_offset_fn_type_cc,
- .node_offset_fn_type_ret_ty,
- .node_offset_param,
- .token_offset_param,
- .node_offset_anyframe_type,
- .node_offset_lib_name,
- .node_offset_array_type_len,
- .node_offset_array_type_sentinel,
- .node_offset_array_type_elem,
- .node_offset_un_op,
- .node_offset_ptr_elem,
- .node_offset_ptr_sentinel,
- .node_offset_ptr_align,
- .node_offset_ptr_addrspace,
- .node_offset_ptr_bitoffset,
- .node_offset_ptr_hostsize,
- .node_offset_container_tag,
- .node_offset_field_default,
- .node_offset_init_ty,
- .node_offset_store_ptr,
- .node_offset_store_operand,
- .node_offset_return_operand,
- .for_input,
- .for_capture_from_input,
- .array_cat_lhs,
- .array_cat_rhs,
- => .{
- .file_scope = decl.getFileScope(mod),
- .parent_decl_node = decl.src_node,
- .lazy = lazy,
- },
- inline .call_arg,
- .fn_proto_param,
- => |x| .{
- .file_scope = decl.getFileScope(mod),
- .parent_decl_node = mod.declPtr(x.decl).src_node,
- .lazy = lazy,
- },
- };
- }
-
pub fn declPtrType(decl: Decl, zcu: *Zcu) !Type {
assert(decl.has_tv);
const decl_ty = decl.typeOf(zcu);
@@ -661,6 +544,23 @@ pub const Decl = struct {
},
});
}
+
+ /// Returns the source location of this `Decl`.
+ /// Asserts that this `Decl` corresponds to what will in future be a `Nav` (Named
+ /// Addressable Value): a source-level declaration or generic instantiation.
+ pub fn navSrcLoc(decl: Decl, zcu: *Zcu) LazySrcLoc {
+ return .{
+ .base_node_inst = decl.zir_decl_index.unwrap() orelse inst: {
+ // generic instantiation
+ assert(decl.has_tv);
+ assert(decl.owns_tv);
+ const owner = zcu.funcInfo(decl.val.toIntern()).generic_owner;
+ const generic_owner_decl = zcu.declPtr(zcu.funcInfo(owner).owner_decl);
+ break :inst generic_owner_decl.zir_decl_index.unwrap().?;
+ },
+ .offset = LazySrcLoc.Offset.nodeOffset(0),
+ };
+ }
};
/// This state is attached to every Decl when Module emit_h is non-null.
@@ -1137,18 +1037,17 @@ pub const ErrorMsg = struct {
/// Canonical reference to a position within a source file.
pub const SrcLoc = struct {
file_scope: *File,
- /// Might be 0 depending on tag of `lazy`.
- parent_decl_node: Ast.Node.Index,
- /// Relative to `parent_decl_node`.
- lazy: LazySrcLoc,
+ base_node: Ast.Node.Index,
+ /// Relative to `base_node`.
+ lazy: LazySrcLoc.Offset,
- pub fn declSrcToken(src_loc: SrcLoc) Ast.TokenIndex {
+ pub fn baseSrcToken(src_loc: SrcLoc) Ast.TokenIndex {
const tree = src_loc.file_scope.tree;
- return tree.firstToken(src_loc.parent_decl_node);
+ return tree.firstToken(src_loc.base_node);
}
- pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.Node.Index {
- return @bitCast(offset + @as(i32, @bitCast(src_loc.parent_decl_node)));
+ pub fn relativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.Node.Index {
+ return @bitCast(offset + @as(i32, @bitCast(src_loc.base_node)));
}
pub const Span = Ast.Span;
@@ -1172,14 +1071,14 @@ pub const SrcLoc = struct {
},
.byte_offset => |byte_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const tok_index = src_loc.declSrcToken();
+ const tok_index = src_loc.baseSrcToken();
const start = tree.tokens.items(.start)[tok_index] + byte_off;
const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
return Span{ .start = start, .end = end, .main = start };
},
.token_offset => |tok_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const tok_index = src_loc.declSrcToken() + tok_off;
+ const tok_index = src_loc.baseSrcToken() + tok_off;
const start = tree.tokens.items(.start)[tok_index];
const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
return Span{ .start = start, .end = end, .main = start };
@@ -1187,25 +1086,25 @@ pub const SrcLoc = struct {
.node_offset => |traced_off| {
const node_off = traced_off.x;
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
assert(src_loc.file_scope.tree_loaded);
return tree.nodeToSpan(node);
},
.node_offset_main_token => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const main_token = tree.nodes.items(.main_token)[node];
return tree.tokensToSpan(main_token, main_token, main_token);
},
.node_offset_bin_op => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
assert(src_loc.file_scope.tree_loaded);
return tree.nodeToSpan(node);
},
.node_offset_initializer => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
return tree.tokensToSpan(
tree.firstToken(node) - 3,
tree.lastToken(node),
@@ -1214,7 +1113,7 @@ pub const SrcLoc = struct {
},
.node_offset_var_decl_ty => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const node_tags = tree.nodes.items(.tag);
const full = switch (node_tags[node]) {
.global_var_decl,
@@ -1238,41 +1137,51 @@ pub const SrcLoc = struct {
},
.node_offset_var_decl_align => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullVarDecl(node).?;
return tree.nodeToSpan(full.ast.align_node);
},
.node_offset_var_decl_section => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullVarDecl(node).?;
return tree.nodeToSpan(full.ast.section_node);
},
.node_offset_var_decl_addrspace => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullVarDecl(node).?;
return tree.nodeToSpan(full.ast.addrspace_node);
},
.node_offset_var_decl_init => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullVarDecl(node).?;
return tree.nodeToSpan(full.ast.init_node);
},
- .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0),
- .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1),
- .node_offset_builtin_call_arg2 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 2),
- .node_offset_builtin_call_arg3 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 3),
- .node_offset_builtin_call_arg4 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 4),
- .node_offset_builtin_call_arg5 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 5),
+ .node_offset_builtin_call_arg => |builtin_arg| {
+ const tree = try src_loc.file_scope.getTree(gpa);
+ const node_datas = tree.nodes.items(.data);
+ const node_tags = tree.nodes.items(.tag);
+ const node = src_loc.relativeToNodeIndex(builtin_arg.builtin_call_node);
+ const param = switch (node_tags[node]) {
+ .builtin_call_two, .builtin_call_two_comma => switch (builtin_arg.arg_index) {
+ 0 => node_datas[node].lhs,
+ 1 => node_datas[node].rhs,
+ else => unreachable,
+ },
+ .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + builtin_arg.arg_index],
+ else => unreachable,
+ };
+ return tree.nodeToSpan(param);
+ },
.node_offset_ptrcast_operand => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const main_tokens = tree.nodes.items(.main_token);
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
- var node = src_loc.declRelativeToNodeIndex(node_off);
+ var node = src_loc.relativeToNodeIndex(node_off);
while (true) {
switch (node_tags[node]) {
.builtin_call_two, .builtin_call_two_comma => {},
@@ -1304,7 +1213,7 @@ pub const SrcLoc = struct {
.node_offset_array_access_index => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const node_datas = tree.nodes.items(.data);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
return tree.nodeToSpan(node_datas[node].rhs);
},
.node_offset_slice_ptr,
@@ -1313,7 +1222,7 @@ pub const SrcLoc = struct {
.node_offset_slice_sentinel,
=> |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullSlice(node).?;
const part_node = switch (src_loc.lazy) {
.node_offset_slice_ptr => full.ast.sliced,
@@ -1326,7 +1235,7 @@ pub const SrcLoc = struct {
},
.node_offset_call_func => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullCall(&buf, node).?;
return tree.nodeToSpan(full.ast.fn_expr);
@@ -1335,7 +1244,7 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const tok_index = switch (node_tags[node]) {
.field_access => node_datas[node].rhs,
@@ -1359,7 +1268,7 @@ pub const SrcLoc = struct {
},
.node_offset_field_name_init => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const tok_index = tree.firstToken(node) - 2;
const start = tree.tokens.items(.start)[tok_index];
const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
@@ -1367,18 +1276,18 @@ pub const SrcLoc = struct {
},
.node_offset_deref_ptr => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
return tree.nodeToSpan(node);
},
.node_offset_asm_source => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullAsm(node).?;
return tree.nodeToSpan(full.ast.template);
},
.node_offset_asm_ret_ty => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullAsm(node).?;
const asm_output = full.outputs[0];
const node_datas = tree.nodes.items(.data);
@@ -1387,7 +1296,7 @@ pub const SrcLoc = struct {
.node_offset_if_cond => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const node_tags = tree.nodes.items(.tag);
const src_node = switch (node_tags[node]) {
.if_simple,
@@ -1416,7 +1325,7 @@ pub const SrcLoc = struct {
},
.for_input => |for_input| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset);
+ const node = src_loc.relativeToNodeIndex(for_input.for_node_offset);
const for_full = tree.fullFor(node).?;
const src_node = for_full.ast.inputs[for_input.input_index];
return tree.nodeToSpan(src_node);
@@ -1424,7 +1333,7 @@ pub const SrcLoc = struct {
.for_capture_from_input => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const token_tags = tree.tokens.items(.tag);
- const input_node = src_loc.declRelativeToNodeIndex(node_off);
+ const input_node = src_loc.relativeToNodeIndex(node_off);
// We have to actually linear scan the whole AST to find the for loop
// that contains this input.
const node_tags = tree.nodes.items(.tag);
@@ -1465,7 +1374,7 @@ pub const SrcLoc = struct {
},
.call_arg => |call_arg| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(call_arg.call_node_offset);
+ const node = src_loc.relativeToNodeIndex(call_arg.call_node_offset);
var buf: [2]Ast.Node.Index = undefined;
const call_full = tree.fullCall(buf[0..1], node) orelse {
const node_tags = tree.nodes.items(.tag);
@@ -1501,43 +1410,49 @@ pub const SrcLoc = struct {
};
return tree.nodeToSpan(call_full.ast.params[call_arg.arg_index]);
},
- .fn_proto_param => |fn_proto_param| {
+ .fn_proto_param, .fn_proto_param_type => |fn_proto_param| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(fn_proto_param.fn_proto_node_offset);
+ const node = src_loc.relativeToNodeIndex(fn_proto_param.fn_proto_node_offset);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
var it = full.iterate(tree);
var i: usize = 0;
while (it.next()) |param| : (i += 1) {
- if (i == fn_proto_param.param_index) {
- if (param.anytype_ellipsis3) |token| return tree.tokenToSpan(token);
- const first_token = param.comptime_noalias orelse
- param.name_token orelse
- tree.firstToken(param.type_expr);
- return tree.tokensToSpan(
- first_token,
- tree.lastToken(param.type_expr),
- first_token,
- );
+ if (i != fn_proto_param.param_index) continue;
+
+ switch (src_loc.lazy) {
+ .fn_proto_param_type => if (param.anytype_ellipsis3) |tok| {
+ return tree.tokenToSpan(tok);
+ } else {
+ return tree.nodeToSpan(param.type_expr);
+ },
+ .fn_proto_param => if (param.anytype_ellipsis3) |tok| {
+ const first = param.comptime_noalias orelse param.name_token orelse tok;
+ return tree.tokensToSpan(first, tok, first);
+ } else {
+ const first = param.comptime_noalias orelse param.name_token orelse tree.firstToken(param.type_expr);
+ return tree.tokensToSpan(first, tree.lastToken(param.type_expr), first);
+ },
+ else => unreachable,
}
}
unreachable;
},
.node_offset_bin_lhs => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const node_datas = tree.nodes.items(.data);
return tree.nodeToSpan(node_datas[node].lhs);
},
.node_offset_bin_rhs => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const node_datas = tree.nodes.items(.data);
return tree.nodeToSpan(node_datas[node].rhs);
},
.array_cat_lhs, .array_cat_rhs => |cat| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(cat.array_cat_offset);
+ const node = src_loc.relativeToNodeIndex(cat.array_cat_offset);
const node_datas = tree.nodes.items(.data);
const arr_node = if (src_loc.lazy == .array_cat_lhs)
node_datas[node].lhs
@@ -1565,14 +1480,14 @@ pub const SrcLoc = struct {
.node_offset_switch_operand => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const node_datas = tree.nodes.items(.data);
return tree.nodeToSpan(node_datas[node].lhs);
},
.node_offset_switch_special_prong => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const switch_node = src_loc.declRelativeToNodeIndex(node_off);
+ const switch_node = src_loc.relativeToNodeIndex(node_off);
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
@@ -1592,7 +1507,7 @@ pub const SrcLoc = struct {
.node_offset_switch_range => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const switch_node = src_loc.declRelativeToNodeIndex(node_off);
+ const switch_node = src_loc.relativeToNodeIndex(node_off);
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
@@ -1613,56 +1528,30 @@ pub const SrcLoc = struct {
}
} else unreachable;
},
- .node_offset_switch_prong_capture,
- .node_offset_switch_prong_tag_capture,
- => |node_off| {
- const tree = try src_loc.file_scope.getTree(gpa);
- const case_node = src_loc.declRelativeToNodeIndex(node_off);
- const case = tree.fullSwitchCase(case_node).?;
- const token_tags = tree.tokens.items(.tag);
- const start_tok = switch (src_loc.lazy) {
- .node_offset_switch_prong_capture => case.payload_token.?,
- .node_offset_switch_prong_tag_capture => blk: {
- var tok = case.payload_token.?;
- if (token_tags[tok] == .asterisk) tok += 1;
- tok += 2; // skip over comma
- break :blk tok;
- },
- else => unreachable,
- };
- const end_tok = switch (token_tags[start_tok]) {
- .asterisk => start_tok + 1,
- else => start_tok,
- };
- const start = tree.tokens.items(.start)[start_tok];
- const end_start = tree.tokens.items(.start)[end_tok];
- const end = end_start + @as(u32, @intCast(tree.tokenSlice(end_tok).len));
- return Span{ .start = start, .end = end, .main = start };
- },
.node_offset_fn_type_align => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return tree.nodeToSpan(full.ast.align_expr);
},
.node_offset_fn_type_addrspace => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return tree.nodeToSpan(full.ast.addrspace_expr);
},
.node_offset_fn_type_section => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return tree.nodeToSpan(full.ast.section_expr);
},
.node_offset_fn_type_cc => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return tree.nodeToSpan(full.ast.callconv_expr);
@@ -1670,7 +1559,7 @@ pub const SrcLoc = struct {
.node_offset_fn_type_ret_ty => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return tree.nodeToSpan(full.ast.return_type);
@@ -1678,7 +1567,7 @@ pub const SrcLoc = struct {
.node_offset_param => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const token_tags = tree.tokens.items(.tag);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
var first_tok = tree.firstToken(node);
while (true) switch (token_tags[first_tok - 1]) {
@@ -1694,7 +1583,7 @@ pub const SrcLoc = struct {
.token_offset_param => |token_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const token_tags = tree.tokens.items(.tag);
- const main_token = tree.nodes.items(.main_token)[src_loc.parent_decl_node];
+ const main_token = tree.nodes.items(.main_token)[src_loc.base_node];
const tok_index = @as(Ast.TokenIndex, @bitCast(token_off + @as(i32, @bitCast(main_token))));
var first_tok = tok_index;
@@ -1712,13 +1601,13 @@ pub const SrcLoc = struct {
.node_offset_anyframe_type => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const node_datas = tree.nodes.items(.data);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
return tree.nodeToSpan(node_datas[parent_node].rhs);
},
.node_offset_lib_name => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, parent_node).?;
const tok_index = full.lib_name.?;
@@ -1729,21 +1618,21 @@ pub const SrcLoc = struct {
.node_offset_array_type_len => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullArrayType(parent_node).?;
return tree.nodeToSpan(full.ast.elem_count);
},
.node_offset_array_type_sentinel => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullArrayType(parent_node).?;
return tree.nodeToSpan(full.ast.sentinel);
},
.node_offset_array_type_elem => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullArrayType(parent_node).?;
return tree.nodeToSpan(full.ast.elem_type);
@@ -1751,48 +1640,48 @@ pub const SrcLoc = struct {
.node_offset_un_op => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const node_datas = tree.nodes.items(.data);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
return tree.nodeToSpan(node_datas[node].lhs);
},
.node_offset_ptr_elem => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullPtrType(parent_node).?;
return tree.nodeToSpan(full.ast.child_type);
},
.node_offset_ptr_sentinel => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullPtrType(parent_node).?;
return tree.nodeToSpan(full.ast.sentinel);
},
.node_offset_ptr_align => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullPtrType(parent_node).?;
return tree.nodeToSpan(full.ast.align_node);
},
.node_offset_ptr_addrspace => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullPtrType(parent_node).?;
return tree.nodeToSpan(full.ast.addrspace_node);
},
.node_offset_ptr_bitoffset => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullPtrType(parent_node).?;
return tree.nodeToSpan(full.ast.bit_range_start);
},
.node_offset_ptr_hostsize => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full = tree.fullPtrType(parent_node).?;
return tree.nodeToSpan(full.ast.bit_range_end);
@@ -1800,7 +1689,7 @@ pub const SrcLoc = struct {
.node_offset_container_tag => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const node_tags = tree.nodes.items(.tag);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
switch (node_tags[parent_node]) {
.container_decl_arg, .container_decl_arg_trailing => {
@@ -1822,7 +1711,7 @@ pub const SrcLoc = struct {
.node_offset_field_default => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const node_tags = tree.nodes.items(.tag);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
const full: Ast.full.ContainerField = switch (node_tags[parent_node]) {
.container_field => tree.containerField(parent_node),
@@ -1833,7 +1722,7 @@ pub const SrcLoc = struct {
},
.node_offset_init_ty => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const parent_node = src_loc.declRelativeToNodeIndex(node_off);
+ const parent_node = src_loc.relativeToNodeIndex(node_off);
var buf: [2]Ast.Node.Index = undefined;
const type_expr = if (tree.fullArrayInit(&buf, parent_node)) |array_init|
@@ -1846,7 +1735,7 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node_tags = tree.nodes.items(.tag);
const node_datas = tree.nodes.items(.data);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
switch (node_tags[node]) {
.assign => {
@@ -1859,7 +1748,7 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node_tags = tree.nodes.items(.tag);
const node_datas = tree.nodes.items(.data);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
switch (node_tags[node]) {
.assign => {
@@ -1870,7 +1759,7 @@ pub const SrcLoc = struct {
},
.node_offset_return_operand => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
- const node = src_loc.declRelativeToNodeIndex(node_off);
+ const node = src_loc.relativeToNodeIndex(node_off);
const node_tags = tree.nodes.items(.tag);
const node_datas = tree.nodes.items(.data);
if (node_tags[node] == .@"return" and node_datas[node].lhs != 0) {
@@ -1878,381 +1767,629 @@ pub const SrcLoc = struct {
}
return tree.nodeToSpan(node);
},
- }
- }
+ .container_field_name,
+ .container_field_value,
+ .container_field_type,
+ .container_field_align,
+ => |field_idx| {
+ const tree = try src_loc.file_scope.getTree(gpa);
+ const node = src_loc.relativeToNodeIndex(0);
+ var buf: [2]Ast.Node.Index = undefined;
+ const container_decl = tree.fullContainerDecl(&buf, node) orelse
+ return tree.nodeToSpan(node);
+
+ var cur_field_idx: usize = 0;
+ for (container_decl.ast.members) |member_node| {
+ const field = tree.fullContainerField(member_node) orelse continue;
+ if (cur_field_idx < field_idx) {
+ cur_field_idx += 1;
+ continue;
+ }
+ const field_component_node = switch (src_loc.lazy) {
+ .container_field_name => 0,
+ .container_field_value => field.ast.value_expr,
+ .container_field_type => field.ast.type_expr,
+ .container_field_align => field.ast.align_expr,
+ else => unreachable,
+ };
+ if (field_component_node == 0) {
+ return tree.tokenToSpan(field.ast.main_token);
+ } else {
+ return tree.nodeToSpan(field_component_node);
+ }
+ } else unreachable;
+ },
+ .init_elem => |init_elem| {
+ const tree = try src_loc.file_scope.getTree(gpa);
+ const init_node = src_loc.relativeToNodeIndex(init_elem.init_node_offset);
+ var buf: [2]Ast.Node.Index = undefined;
+ if (tree.fullArrayInit(&buf, init_node)) |full| {
+ const elem_node = full.ast.elements[init_elem.elem_index];
+ return tree.nodeToSpan(elem_node);
+ } else if (tree.fullStructInit(&buf, init_node)) |full| {
+ const field_node = full.ast.fields[init_elem.elem_index];
+ return tree.tokensToSpan(
+ tree.firstToken(field_node) - 3,
+ tree.lastToken(field_node),
+ tree.nodes.items(.main_token)[field_node] - 2,
+ );
+ } else unreachable;
+ },
+ .init_field_name,
+ .init_field_linkage,
+ .init_field_section,
+ .init_field_visibility,
+ .init_field_rw,
+ .init_field_locality,
+ .init_field_cache,
+ .init_field_library,
+ .init_field_thread_local,
+ => |builtin_call_node| {
+ const wanted = switch (src_loc.lazy) {
+ .init_field_name => "name",
+ .init_field_linkage => "linkage",
+ .init_field_section => "section",
+ .init_field_visibility => "visibility",
+ .init_field_rw => "rw",
+ .init_field_locality => "locality",
+ .init_field_cache => "cache",
+ .init_field_library => "library",
+ .init_field_thread_local => "thread_local",
+ else => unreachable,
+ };
+ const tree = try src_loc.file_scope.getTree(gpa);
+ const node_datas = tree.nodes.items(.data);
+ const node_tags = tree.nodes.items(.tag);
+ const node = src_loc.relativeToNodeIndex(builtin_call_node);
+ const arg_node = switch (node_tags[node]) {
+ .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs,
+ .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1],
+ else => unreachable,
+ };
+ var buf: [2]Ast.Node.Index = undefined;
+ const full = tree.fullStructInit(&buf, arg_node) orelse
+ return tree.nodeToSpan(arg_node);
+ for (full.ast.fields) |field_node| {
+ // . IDENTIFIER = field_node
+ const name_token = tree.firstToken(field_node) - 2;
+ const name = tree.tokenSlice(name_token);
+ if (std.mem.eql(u8, name, wanted)) {
+ return tree.tokensToSpan(
+ name_token - 1,
+ tree.lastToken(field_node),
+ tree.nodes.items(.main_token)[field_node] - 2,
+ );
+ }
+ }
+ return tree.nodeToSpan(arg_node);
+ },
+ .switch_case_item,
+ .switch_case_item_range_first,
+ .switch_case_item_range_last,
+ .switch_capture,
+ .switch_tag_capture,
+ => {
+ const switch_node_offset, const want_case_idx = switch (src_loc.lazy) {
+ .switch_case_item,
+ .switch_case_item_range_first,
+ .switch_case_item_range_last,
+ => |x| .{ x.switch_node_offset, x.case_idx },
+ .switch_capture,
+ .switch_tag_capture,
+ => |x| .{ x.switch_node_offset, x.case_idx },
+ else => unreachable,
+ };
- pub fn byteOffsetBuiltinCallArg(
- src_loc: SrcLoc,
- gpa: Allocator,
- node_off: i32,
- arg_index: u32,
- ) !Span {
- const tree = try src_loc.file_scope.getTree(gpa);
- const node_datas = tree.nodes.items(.data);
- const node_tags = tree.nodes.items(.tag);
- const node = src_loc.declRelativeToNodeIndex(node_off);
- const param = switch (node_tags[node]) {
- .builtin_call_two, .builtin_call_two_comma => switch (arg_index) {
- 0 => node_datas[node].lhs,
- 1 => node_datas[node].rhs,
- else => unreachable,
+ const tree = try src_loc.file_scope.getTree(gpa);
+ const node_datas = tree.nodes.items(.data);
+ const node_tags = tree.nodes.items(.tag);
+ const main_tokens = tree.nodes.items(.main_token);
+ const switch_node = src_loc.relativeToNodeIndex(switch_node_offset);
+ const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
+ const case_nodes = tree.extra_data[extra.start..extra.end];
+
+ var multi_i: u32 = 0;
+ var scalar_i: u32 = 0;
+ const case = for (case_nodes) |case_node| {
+ const case = tree.fullSwitchCase(case_node).?;
+ const is_special = special: {
+ if (case.ast.values.len == 0) break :special true;
+ if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .identifier) {
+ break :special mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_");
+ }
+ break :special false;
+ };
+ if (is_special) {
+ if (want_case_idx.isSpecial()) {
+ break case;
+ }
+ }
+
+ const is_multi = case.ast.values.len != 1 or
+ node_tags[case.ast.values[0]] == .switch_range;
+
+ if (!want_case_idx.isSpecial()) switch (want_case_idx.kind) {
+ .scalar => if (!is_multi and want_case_idx.index == scalar_i) break case,
+ .multi => if (is_multi and want_case_idx.index == multi_i) break case,
+ };
+
+ if (is_multi) {
+ multi_i += 1;
+ } else {
+ scalar_i += 1;
+ }
+ } else unreachable;
+
+ const want_item = switch (src_loc.lazy) {
+ .switch_case_item,
+ .switch_case_item_range_first,
+ .switch_case_item_range_last,
+ => |x| x.item_idx,
+ .switch_capture, .switch_tag_capture => {
+ const token_tags = tree.tokens.items(.tag);
+ const start = switch (src_loc.lazy) {
+ .switch_capture => case.payload_token.?,
+ .switch_tag_capture => tok: {
+ var tok = case.payload_token.?;
+ if (token_tags[tok] == .asterisk) tok += 1;
+ tok += 2; // skip over comma
+ break :tok tok;
+ },
+ else => unreachable,
+ };
+ const end = switch (token_tags[start]) {
+ .asterisk => start + 1,
+ else => start,
+ };
+ return tree.tokensToSpan(start, end, start);
+ },
+ else => unreachable,
+ };
+
+ switch (want_item.kind) {
+ .single => {
+ var item_i: u32 = 0;
+ for (case.ast.values) |item_node| {
+ if (node_tags[item_node] == .switch_range) continue;
+ if (item_i != want_item.index) {
+ item_i += 1;
+ continue;
+ }
+ return tree.nodeToSpan(item_node);
+ } else unreachable;
+ },
+ .range => {
+ var range_i: u32 = 0;
+ for (case.ast.values) |item_node| {
+ if (node_tags[item_node] != .switch_range) continue;
+ if (range_i != want_item.index) {
+ range_i += 1;
+ continue;
+ }
+ return switch (src_loc.lazy) {
+ .switch_case_item => tree.nodeToSpan(item_node),
+ .switch_case_item_range_first => tree.nodeToSpan(node_datas[item_node].lhs),
+ .switch_case_item_range_last => tree.nodeToSpan(node_datas[item_node].rhs),
+ else => unreachable,
+ };
+ } else unreachable;
+ },
+ }
},
- .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index],
- else => unreachable,
- };
- return tree.nodeToSpan(param);
+ }
}
};
-/// Resolving a source location into a byte offset may require doing work
-/// that we would rather not do unless the error actually occurs.
-/// Therefore we need a data structure that contains the information necessary
-/// to lazily produce a `SrcLoc` as required.
-/// Most of the offsets in this data structure are relative to the containing Decl.
-/// This makes the source location resolve properly even when a Decl gets
-/// shifted up or down in the file, as long as the Decl's contents itself
-/// do not change.
-pub const LazySrcLoc = union(enum) {
- /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
- /// that all code paths which would need to resolve the source location are
- /// unreachable. If you are debugging this tag incorrectly being this value,
- /// 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.
- byte_abs: u32,
- /// The source location points to a token within a source file,
- /// offset from 0. The source file is determined contextually.
- /// Inside a `SrcLoc`, the `file_scope` union field will be active.
- token_abs: u32,
- /// The source location points to an AST node within a source file,
- /// offset from 0. The source file is determined contextually.
- /// Inside a `SrcLoc`, the `file_scope` union field will be active.
- node_abs: u32,
- /// The source location points to a byte offset within a source file,
- /// offset from the byte offset of the Decl within the file.
- /// The Decl is determined contextually.
- byte_offset: u32,
- /// This data is the offset into the token list from the Decl token.
- /// The Decl is determined contextually.
- token_offset: u32,
- /// The source location points to an AST node, which is this value offset
- /// from its containing Decl node AST index.
- /// The Decl is determined contextually.
- node_offset: TracedOffset,
- /// The source location points to the main token of an AST node, found
- /// by taking this AST node index offset from the containing Decl AST node.
- /// The Decl is determined contextually.
- node_offset_main_token: i32,
- /// The source location points to the beginning of a struct initializer.
- /// The Decl is determined contextually.
- node_offset_initializer: i32,
- /// The source location points to a variable declaration type expression,
- /// found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a variable declaration AST node. Next, navigate
- /// to the type expression.
- /// The Decl is determined contextually.
- node_offset_var_decl_ty: i32,
- /// The source location points to the alignment expression of a var decl.
- /// The Decl is determined contextually.
- node_offset_var_decl_align: i32,
- /// The source location points to the linksection expression of a var decl.
- /// The Decl is determined contextually.
- node_offset_var_decl_section: i32,
- /// The source location points to the addrspace expression of a var decl.
- /// The Decl is determined contextually.
- node_offset_var_decl_addrspace: i32,
- /// The source location points to the initializer of a var decl.
- /// The Decl is determined contextually.
- node_offset_var_decl_init: i32,
- /// The source location points to the first parameter of a builtin
- /// function call, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a builtin call AST node. Next, navigate
- /// to the first parameter.
- /// The Decl is determined contextually.
- node_offset_builtin_call_arg0: i32,
- /// Same as `node_offset_builtin_call_arg0` except arg index 1.
- node_offset_builtin_call_arg1: i32,
- node_offset_builtin_call_arg2: i32,
- node_offset_builtin_call_arg3: i32,
- node_offset_builtin_call_arg4: i32,
- node_offset_builtin_call_arg5: i32,
- /// Like `node_offset_builtin_call_arg0` but recurses through arbitrarily many calls
- /// to pointer cast builtins.
- node_offset_ptrcast_operand: i32,
- /// The source location points to the index expression of an array access
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to an array access AST node. Next, navigate
- /// to the index expression.
- /// The Decl is determined contextually.
- node_offset_array_access_index: i32,
- /// The source location points to the LHS of a slice expression
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a slice AST node. Next, navigate
- /// to the sentinel expression.
- /// The Decl is determined contextually.
- node_offset_slice_ptr: i32,
- /// The source location points to start expression of a slice expression
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a slice AST node. Next, navigate
- /// to the sentinel expression.
- /// The Decl is determined contextually.
- node_offset_slice_start: i32,
- /// The source location points to the end expression of a slice
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a slice AST node. Next, navigate
- /// to the sentinel expression.
- /// The Decl is determined contextually.
- node_offset_slice_end: i32,
- /// The source location points to the sentinel expression of a slice
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a slice AST node. Next, navigate
- /// to the sentinel expression.
- /// The Decl is determined contextually.
- node_offset_slice_sentinel: i32,
- /// The source location points to the callee expression of a function
- /// call expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a function call AST node. Next, navigate
- /// to the callee expression.
- /// The Decl is determined contextually.
- node_offset_call_func: i32,
- /// The payload is offset from the containing Decl AST node.
- /// The source location points to the field name of:
- /// * a field access expression (`a.b`), or
- /// * the callee of a method call (`a.b()`)
- /// The Decl is determined contextually.
- node_offset_field_name: i32,
- /// The payload is offset from the containing Decl AST node.
- /// The source location points to the field name of the operand ("b" node)
- /// of a field initialization expression (`.a = b`)
- /// The Decl is determined contextually.
- node_offset_field_name_init: i32,
- /// The source location points to the pointer of a pointer deref expression,
- /// found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a pointer deref AST node. Next, navigate
- /// to the pointer expression.
- /// The Decl is determined contextually.
- node_offset_deref_ptr: i32,
- /// The source location points to the assembly source code of an inline assembly
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to inline assembly AST node. Next, navigate
- /// to the asm template source code.
- /// The Decl is determined contextually.
- node_offset_asm_source: i32,
- /// The source location points to the return type of an inline assembly
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to inline assembly AST node. Next, navigate
- /// to the return type expression.
- /// The Decl is determined contextually.
- node_offset_asm_ret_ty: i32,
- /// The source location points to the condition expression of an if
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to an if expression AST node. Next, navigate
- /// to the condition expression.
- /// The Decl is determined contextually.
- node_offset_if_cond: i32,
- /// The source location points to a binary expression, such as `a + b`, found
- /// by taking this AST node index offset from the containing Decl AST node.
- /// The Decl is determined contextually.
- node_offset_bin_op: i32,
- /// The source location points to the LHS of a binary expression, found
- /// by taking this AST node index offset from the containing Decl AST node,
- /// which points to a binary expression AST node. Next, navigate to the LHS.
- /// The Decl is determined contextually.
- node_offset_bin_lhs: i32,
- /// The source location points to the RHS of a binary expression, found
- /// by taking this AST node index offset from the containing Decl AST node,
- /// which points to a binary expression AST node. Next, navigate to the RHS.
- /// The Decl is determined contextually.
- node_offset_bin_rhs: i32,
- /// The source location points to the operand of a switch expression, found
- /// by taking this AST node index offset from the containing Decl AST node,
- /// which points to a switch expression AST node. Next, navigate to the operand.
- /// The Decl is determined contextually.
- node_offset_switch_operand: i32,
- /// The source location points to the else/`_` prong of a switch expression, found
- /// by taking this AST node index offset from the containing Decl AST node,
- /// which points to a switch expression AST node. Next, navigate to the else/`_` prong.
- /// The Decl is determined contextually.
- node_offset_switch_special_prong: i32,
- /// The source location points to all the ranges of a switch expression, found
- /// by taking this AST node index offset from the containing Decl AST node,
- /// which points to a switch expression AST node. Next, navigate to any of the
- /// range nodes. The error applies to all of them.
- /// The Decl is determined contextually.
- node_offset_switch_range: i32,
- /// The source location points to the capture of a switch_prong.
- /// The Decl is determined contextually.
- node_offset_switch_prong_capture: i32,
- /// The source location points to the tag capture of a switch_prong.
- /// The Decl is determined contextually.
- node_offset_switch_prong_tag_capture: i32,
- /// The source location points to the align expr of a function type
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a function type AST node. Next, navigate to
- /// the calling convention node.
- /// The Decl is determined contextually.
- node_offset_fn_type_align: i32,
- /// The source location points to the addrspace expr of a function type
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a function type AST node. Next, navigate to
- /// the calling convention node.
- /// The Decl is determined contextually.
- node_offset_fn_type_addrspace: i32,
- /// The source location points to the linksection expr of a function type
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a function type AST node. Next, navigate to
- /// the calling convention node.
- /// The Decl is determined contextually.
- node_offset_fn_type_section: i32,
- /// The source location points to the calling convention of a function type
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a function type AST node. Next, navigate to
- /// the calling convention node.
- /// The Decl is determined contextually.
- node_offset_fn_type_cc: i32,
- /// The source location points to the return type of a function type
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a function type AST node. Next, navigate to
- /// the return type node.
- /// The Decl is determined contextually.
- node_offset_fn_type_ret_ty: i32,
- node_offset_param: i32,
- token_offset_param: i32,
- /// The source location points to the type expression of an `anyframe->T`
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate
- /// to the type expression.
- /// The Decl is determined contextually.
- node_offset_anyframe_type: i32,
- /// The source location points to the string literal of `extern "foo"`, found
- /// by taking this AST node index offset from the containing
- /// Decl AST node, which points to a function prototype or variable declaration
- /// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
- /// The Decl is determined contextually.
- node_offset_lib_name: i32,
- /// The source location points to the len expression of an `[N:S]T`
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
- /// to the len expression.
- /// The Decl is determined contextually.
- node_offset_array_type_len: i32,
- /// The source location points to the sentinel expression of an `[N:S]T`
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
- /// to the sentinel expression.
- /// The Decl is determined contextually.
- node_offset_array_type_sentinel: i32,
- /// The source location points to the elem expression of an `[N:S]T`
- /// expression, found by taking this AST node index offset from the containing
- /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
- /// to the elem expression.
- /// The Decl is determined contextually.
- node_offset_array_type_elem: i32,
- /// The source location points to the operand of an unary expression.
- /// The Decl is determined contextually.
- node_offset_un_op: i32,
- /// The source location points to the elem type of a pointer.
- /// The Decl is determined contextually.
- node_offset_ptr_elem: i32,
- /// The source location points to the sentinel of a pointer.
- /// The Decl is determined contextually.
- node_offset_ptr_sentinel: i32,
- /// The source location points to the align expr of a pointer.
- /// The Decl is determined contextually.
- node_offset_ptr_align: i32,
- /// The source location points to the addrspace expr of a pointer.
- /// The Decl is determined contextually.
- node_offset_ptr_addrspace: i32,
- /// The source location points to the bit-offset of a pointer.
- /// The Decl is determined contextually.
- node_offset_ptr_bitoffset: i32,
- /// The source location points to the host size of a pointer.
- /// The Decl is determined contextually.
- node_offset_ptr_hostsize: i32,
- /// The source location points to the tag type of an union or an enum.
- /// The Decl is determined contextually.
- node_offset_container_tag: i32,
- /// The source location points to the default value of a field.
- /// The Decl is determined contextually.
- node_offset_field_default: i32,
- /// The source location points to the type of an array or struct initializer.
- /// The Decl is determined contextually.
- node_offset_init_ty: i32,
- /// The source location points to the LHS of an assignment.
- /// The Decl is determined contextually.
- node_offset_store_ptr: i32,
- /// The source location points to the RHS of an assignment.
- /// The Decl is determined contextually.
- node_offset_store_operand: i32,
- /// The source location points to the operand of a `return` statement, or
- /// the `return` itself if there is no explicit operand.
- /// The Decl is determined contextually.
- node_offset_return_operand: i32,
- /// The source location points to a for loop input.
- /// The Decl is determined contextually.
- for_input: struct {
- /// Points to the for loop AST node.
- for_node_offset: i32,
- /// Picks one of the inputs from the condition.
- input_index: u32,
- },
- /// The source location points to one of the captures of a for loop, found
- /// by taking this AST node index offset from the containing
- /// Decl AST node, which points to one of the input nodes of a for loop.
- /// Next, navigate to the corresponding capture.
- /// The Decl is determined contextually.
- for_capture_from_input: i32,
- /// The source location points to the argument node of a function call.
- call_arg: struct {
- decl: Decl.Index,
- /// Points to the function call AST node.
- call_node_offset: i32,
- /// The index of the argument the source location points to.
- arg_index: u32,
- },
- fn_proto_param: struct {
- decl: Decl.Index,
- /// Points to the function prototype AST node.
- fn_proto_node_offset: i32,
- /// The index of the parameter the source location points to.
- param_index: u32,
- },
- array_cat_lhs: ArrayCat,
- array_cat_rhs: ArrayCat,
-
- const ArrayCat = struct {
- /// Points to the array concat AST node.
- array_cat_offset: i32,
- /// The index of the element the source location points to.
- elem_index: u32,
- };
+pub const LazySrcLoc = struct {
+ /// This instruction provides the source node locations are resolved relative to.
+ /// It is a `declaration`, `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl`.
+ /// This must be valid even if `relative` is an absolute value, since it is required to
+ /// determine the file which the `LazySrcLoc` refers to.
+ base_node_inst: InternPool.TrackedInst.Index,
+ /// This field determines the source location relative to `base_node_inst`.
+ offset: Offset,
+
+ pub const Offset = union(enum) {
+ /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
+ /// that all code paths which would need to resolve the source location are
+ /// unreachable. If you are debugging this tag incorrectly being this value,
+ /// look into using reverse-continue with a memory watchpoint to see where the
+ /// value is being set to this tag.
+ /// `base_node_inst` is unused.
+ 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.
+ byte_abs: u32,
+ /// The source location points to a token within a source file,
+ /// offset from 0. The source file is determined contextually.
+ /// Inside a `SrcLoc`, the `file_scope` union field will be active.
+ token_abs: u32,
+ /// The source location points to an AST node within a source file,
+ /// offset from 0. The source file is determined contextually.
+ /// Inside a `SrcLoc`, the `file_scope` union field will be active.
+ node_abs: u32,
+ /// The source location points to a byte offset within a source file,
+ /// offset from the byte offset of the base node within the file.
+ byte_offset: u32,
+ /// This data is the offset into the token list from the base node's first token.
+ token_offset: u32,
+ /// The source location points to an AST node, which is this value offset
+ /// from its containing base node AST index.
+ node_offset: TracedOffset,
+ /// The source location points to the main token of an AST node, found
+ /// by taking this AST node index offset from the containing base node.
+ node_offset_main_token: i32,
+ /// The source location points to the beginning of a struct initializer.
+ node_offset_initializer: i32,
+ /// The source location points to a variable declaration type expression,
+ /// found by taking this AST node index offset from the containing
+ /// base node, which points to a variable declaration AST node. Next, navigate
+ /// to the type expression.
+ node_offset_var_decl_ty: i32,
+ /// The source location points to the alignment expression of a var decl.
+ node_offset_var_decl_align: i32,
+ /// The source location points to the linksection expression of a var decl.
+ node_offset_var_decl_section: i32,
+ /// The source location points to the addrspace expression of a var decl.
+ node_offset_var_decl_addrspace: i32,
+ /// The source location points to the initializer of a var decl.
+ node_offset_var_decl_init: i32,
+ /// The source location points to the given argument of a builtin function call.
+ /// `builtin_call_node` points to the builtin call.
+ /// `arg_index` is the index of the argument which hte source location refers to.
+ node_offset_builtin_call_arg: struct {
+ builtin_call_node: i32,
+ arg_index: u32,
+ },
+ /// Like `node_offset_builtin_call_arg` but recurses through arbitrarily many calls
+ /// to pointer cast builtins (taking the first argument of the most nested).
+ node_offset_ptrcast_operand: i32,
+ /// The source location points to the index expression of an array access
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to an array access AST node. Next, navigate
+ /// to the index expression.
+ node_offset_array_access_index: i32,
+ /// The source location points to the LHS of a slice expression
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a slice AST node. Next, navigate
+ /// to the sentinel expression.
+ node_offset_slice_ptr: i32,
+ /// The source location points to start expression of a slice expression
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a slice AST node. Next, navigate
+ /// to the sentinel expression.
+ node_offset_slice_start: i32,
+ /// The source location points to the end expression of a slice
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a slice AST node. Next, navigate
+ /// to the sentinel expression.
+ node_offset_slice_end: i32,
+ /// The source location points to the sentinel expression of a slice
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a slice AST node. Next, navigate
+ /// to the sentinel expression.
+ node_offset_slice_sentinel: i32,
+ /// The source location points to the callee expression of a function
+ /// call expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a function call AST node. Next, navigate
+ /// to the callee expression.
+ node_offset_call_func: i32,
+ /// The payload is offset from the containing base node.
+ /// The source location points to the field name of:
+ /// * a field access expression (`a.b`), or
+ /// * the callee of a method call (`a.b()`)
+ node_offset_field_name: i32,
+ /// The payload is offset from the containing base node.
+ /// The source location points to the field name of the operand ("b" node)
+ /// of a field initialization expression (`.a = b`)
+ node_offset_field_name_init: i32,
+ /// The source location points to the pointer of a pointer deref expression,
+ /// found by taking this AST node index offset from the containing
+ /// base node, which points to a pointer deref AST node. Next, navigate
+ /// to the pointer expression.
+ node_offset_deref_ptr: i32,
+ /// The source location points to the assembly source code of an inline assembly
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to inline assembly AST node. Next, navigate
+ /// to the asm template source code.
+ node_offset_asm_source: i32,
+ /// The source location points to the return type of an inline assembly
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to inline assembly AST node. Next, navigate
+ /// to the return type expression.
+ node_offset_asm_ret_ty: i32,
+ /// The source location points to the condition expression of an if
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to an if expression AST node. Next, navigate
+ /// to the condition expression.
+ node_offset_if_cond: i32,
+ /// The source location points to a binary expression, such as `a + b`, found
+ /// by taking this AST node index offset from the containing base node.
+ node_offset_bin_op: i32,
+ /// The source location points to the LHS of a binary expression, found
+ /// by taking this AST node index offset from the containing base node,
+ /// which points to a binary expression AST node. Next, navigate to the LHS.
+ node_offset_bin_lhs: i32,
+ /// The source location points to the RHS of a binary expression, found
+ /// by taking this AST node index offset from the containing base node,
+ /// which points to a binary expression AST node. Next, navigate to the RHS.
+ node_offset_bin_rhs: i32,
+ /// The source location points to the operand of a switch expression, found
+ /// by taking this AST node index offset from the containing base node,
+ /// which points to a switch expression AST node. Next, navigate to the operand.
+ node_offset_switch_operand: i32,
+ /// The source location points to the else/`_` prong of a switch expression, found
+ /// by taking this AST node index offset from the containing base node,
+ /// which points to a switch expression AST node. Next, navigate to the else/`_` prong.
+ node_offset_switch_special_prong: i32,
+ /// The source location points to all the ranges of a switch expression, found
+ /// by taking this AST node index offset from the containing base node,
+ /// which points to a switch expression AST node. Next, navigate to any of the
+ /// range nodes. The error applies to all of them.
+ node_offset_switch_range: i32,
+ /// The source location points to the align expr of a function type
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a function type AST node. Next, navigate to
+ /// the calling convention node.
+ node_offset_fn_type_align: i32,
+ /// The source location points to the addrspace expr of a function type
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a function type AST node. Next, navigate to
+ /// the calling convention node.
+ node_offset_fn_type_addrspace: i32,
+ /// The source location points to the linksection expr of a function type
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a function type AST node. Next, navigate to
+ /// the calling convention node.
+ node_offset_fn_type_section: i32,
+ /// The source location points to the calling convention of a function type
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a function type AST node. Next, navigate to
+ /// the calling convention node.
+ node_offset_fn_type_cc: i32,
+ /// The source location points to the return type of a function type
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a function type AST node. Next, navigate to
+ /// the return type node.
+ node_offset_fn_type_ret_ty: i32,
+ node_offset_param: i32,
+ token_offset_param: i32,
+ /// The source location points to the type expression of an `anyframe->T`
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to a `anyframe->T` expression AST node. Next, navigate
+ /// to the type expression.
+ node_offset_anyframe_type: i32,
+ /// The source location points to the string literal of `extern "foo"`, found
+ /// by taking this AST node index offset from the containing
+ /// base node, which points to a function prototype or variable declaration
+ /// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
+ node_offset_lib_name: i32,
+ /// The source location points to the len expression of an `[N:S]T`
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to an `[N:S]T` expression AST node. Next, navigate
+ /// to the len expression.
+ node_offset_array_type_len: i32,
+ /// The source location points to the sentinel expression of an `[N:S]T`
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to an `[N:S]T` expression AST node. Next, navigate
+ /// to the sentinel expression.
+ node_offset_array_type_sentinel: i32,
+ /// The source location points to the elem expression of an `[N:S]T`
+ /// expression, found by taking this AST node index offset from the containing
+ /// base node, which points to an `[N:S]T` expression AST node. Next, navigate
+ /// to the elem expression.
+ node_offset_array_type_elem: i32,
+ /// The source location points to the operand of an unary expression.
+ node_offset_un_op: i32,
+ /// The source location points to the elem type of a pointer.
+ node_offset_ptr_elem: i32,
+ /// The source location points to the sentinel of a pointer.
+ node_offset_ptr_sentinel: i32,
+ /// The source location points to the align expr of a pointer.
+ node_offset_ptr_align: i32,
+ /// The source location points to the addrspace expr of a pointer.
+ node_offset_ptr_addrspace: i32,
+ /// The source location points to the bit-offset of a pointer.
+ node_offset_ptr_bitoffset: i32,
+ /// The source location points to the host size of a pointer.
+ node_offset_ptr_hostsize: i32,
+ /// The source location points to the tag type of an union or an enum.
+ node_offset_container_tag: i32,
+ /// The source location points to the default value of a field.
+ node_offset_field_default: i32,
+ /// The source location points to the type of an array or struct initializer.
+ node_offset_init_ty: i32,
+ /// The source location points to the LHS of an assignment.
+ node_offset_store_ptr: i32,
+ /// The source location points to the RHS of an assignment.
+ node_offset_store_operand: i32,
+ /// The source location points to the operand of a `return` statement, or
+ /// the `return` itself if there is no explicit operand.
+ node_offset_return_operand: i32,
+ /// The source location points to a for loop input.
+ for_input: struct {
+ /// Points to the for loop AST node.
+ for_node_offset: i32,
+ /// Picks one of the inputs from the condition.
+ input_index: u32,
+ },
+ /// The source location points to one of the captures of a for loop, found
+ /// by taking this AST node index offset from the containing
+ /// base node, which points to one of the input nodes of a for loop.
+ /// Next, navigate to the corresponding capture.
+ for_capture_from_input: i32,
+ /// The source location points to the argument node of a function call.
+ call_arg: struct {
+ /// Points to the function call AST node.
+ call_node_offset: i32,
+ /// The index of the argument the source location points to.
+ arg_index: u32,
+ },
+ fn_proto_param: FnProtoParam,
+ fn_proto_param_type: FnProtoParam,
+ array_cat_lhs: ArrayCat,
+ array_cat_rhs: ArrayCat,
+ /// The source location points to the name of the field at the given index
+ /// of the container type declaration at the base node.
+ container_field_name: u32,
+ /// Like `continer_field_name`, but points at the field's default value.
+ container_field_value: u32,
+ /// Like `continer_field_name`, but points at the field's type.
+ container_field_type: u32,
+ /// Like `continer_field_name`, but points at the field's alignment.
+ container_field_align: u32,
+ /// The source location points to the given element/field of a struct or
+ /// array initialization expression.
+ init_elem: struct {
+ /// Points to the AST node of the initialization expression.
+ init_node_offset: i32,
+ /// The index of the field/element the source location points to.
+ elem_index: u32,
+ },
+ // The following source locations are like `init_elem`, but refer to a
+ // field with a specific name. If such a field is not given, the entire
+ // initialization expression is used instead.
+ // The `i32` points to the AST node of a builtin call, whose *second*
+ // argument is the init expression.
+ init_field_name: i32,
+ init_field_linkage: i32,
+ init_field_section: i32,
+ init_field_visibility: i32,
+ init_field_rw: i32,
+ init_field_locality: i32,
+ init_field_cache: i32,
+ init_field_library: i32,
+ init_field_thread_local: i32,
+ /// The source location points to the value of an item in a specific
+ /// case of a `switch`.
+ switch_case_item: SwitchItem,
+ /// The source location points to the "first" value of a range item in
+ /// a specific case of a `switch`.
+ switch_case_item_range_first: SwitchItem,
+ /// The source location points to the "last" value of a range item in
+ /// a specific case of a `switch`.
+ switch_case_item_range_last: SwitchItem,
+ /// The source location points to the main capture of a specific case of
+ /// a `switch`.
+ switch_capture: SwitchCapture,
+ /// The source location points to the "tag" capture (second capture) of
+ /// a specific case of a `switch`.
+ switch_tag_capture: SwitchCapture,
+
+ pub const FnProtoParam = struct {
+ /// The offset of the function prototype AST node.
+ fn_proto_node_offset: i32,
+ /// The index of the parameter the source location points to.
+ param_index: u32,
+ };
- pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
+ pub const SwitchItem = struct {
+ /// The offset of the switch AST node.
+ switch_node_offset: i32,
+ /// The index of the case to point to within this switch.
+ case_idx: SwitchCaseIndex,
+ /// The index of the item to point to within this case.
+ item_idx: SwitchItemIndex,
+ };
- noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
- var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
- result.node_offset.trace.addAddr(@returnAddress(), "init");
- return result;
- }
+ pub const SwitchCapture = struct {
+ /// The offset of the switch AST node.
+ switch_node_offset: i32,
+ /// The index of the case whose capture to point to.
+ case_idx: SwitchCaseIndex,
+ };
- fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
- return .{ .node_offset = .{ .x = node_offset } };
- }
+ pub const SwitchCaseIndex = packed struct(u32) {
+ kind: enum(u1) { scalar, multi },
+ index: u31,
- /// This wraps a simple integer in debug builds so that later on we can find out
- /// where in semantic analysis the value got set.
- pub const TracedOffset = struct {
- x: i32,
- trace: std.debug.Trace = std.debug.Trace.init,
+ pub const special: SwitchCaseIndex = @bitCast(@as(u32, std.math.maxInt(u32)));
+ pub fn isSpecial(idx: SwitchCaseIndex) bool {
+ return @as(u32, @bitCast(idx)) == @as(u32, @bitCast(special));
+ }
+ };
+
+ pub const SwitchItemIndex = packed struct(u32) {
+ kind: enum(u1) { single, range },
+ index: u31,
+ };
+
+ const ArrayCat = struct {
+ /// Points to the array concat AST node.
+ array_cat_offset: i32,
+ /// The index of the element the source location points to.
+ elem_index: u32,
+ };
+
+ pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
+
+ noinline fn nodeOffsetDebug(node_offset: i32) Offset {
+ var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
+ result.node_offset.trace.addAddr(@returnAddress(), "init");
+ return result;
+ }
- const want_tracing = false;
+ fn nodeOffsetRelease(node_offset: i32) Offset {
+ return .{ .node_offset = .{ .x = node_offset } };
+ }
+
+ /// This wraps a simple integer in debug builds so that later on we can find out
+ /// where in semantic analysis the value got set.
+ pub const TracedOffset = struct {
+ x: i32,
+ trace: std.debug.Trace = std.debug.Trace.init,
+
+ const want_tracing = false;
+ };
};
+
+ pub const unneeded: LazySrcLoc = .{
+ .base_node_inst = undefined,
+ .offset = .unneeded,
+ };
+
+ pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) struct { *File, Ast.Node.Index } {
+ const want_path_digest, const zir_inst = inst: {
+ const info = base_node_inst.resolveFull(&zcu.intern_pool);
+ break :inst .{ info.path_digest, info.inst };
+ };
+ // TODO: avoid iterating all files for this!
+ const file = for (zcu.import_table.values()) |file| {
+ if (std.mem.eql(u8, &file.path_digest, &want_path_digest)) break file;
+ } else unreachable;
+ assert(file.zir_loaded);
+
+ const zir = file.zir;
+ const inst = zir.instructions.get(@intFromEnum(zir_inst));
+ const base_node: Ast.Node.Index = switch (inst.tag) {
+ .declaration => inst.data.declaration.src_node,
+ .extended => switch (inst.data.extended.opcode) {
+ .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_node,
+ .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node,
+ .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_node,
+ .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_node,
+ else => unreachable,
+ },
+ else => unreachable,
+ };
+ return .{ file, base_node };
+ }
+
+ /// Resolve the file and AST node of `base_node_inst` to get a resolved `SrcLoc`.
+ /// TODO: it is incorrect to store a `SrcLoc` anywhere due to incremental compilation.
+ /// Probably the type should be removed entirely and this resolution performed on-the-fly when needed.
+ pub fn upgrade(lazy: LazySrcLoc, zcu: *Zcu) SrcLoc {
+ const file, const base_node = resolveBaseNode(lazy.base_node_inst, zcu);
+ return .{
+ .file_scope = file,
+ .base_node = base_node,
+ .lazy = lazy.offset,
+ };
+ }
};
pub const SemaError = error{ OutOfMemory, AnalysisFail };
@@ -2260,11 +2397,6 @@ pub const CompileError = error{
OutOfMemory,
/// When this is returned, the compile error for the failure has already been recorded.
AnalysisFail,
- /// Returned when a compile error needed to be reported but a provided LazySrcLoc was set
- /// to the `unneeded` tag. The source location was, in fact, needed. It is expected that
- /// somewhere up the call stack, the operation will be retried after doing expensive work
- /// to compute a source location.
- NeededSourceLocation,
/// A Type or Value was needed to be used during semantic analysis, but it was not available
/// because the function is generic. This is only seen when analyzing the body of a param
/// instruction.
@@ -3373,7 +3505,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
}
return error.AnalysisFail;
},
- error.NeededSourceLocation => unreachable,
error.GenericPoison => unreachable,
else => |e| {
decl.analysis = .sema_failure;
@@ -3381,7 +3512,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
try mod.retryable_failures.append(mod.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
mod.gpa,
- decl.srcLoc(mod),
+ decl.navSrcLoc(mod).upgrade(mod),
"unable to analyze: {s}",
.{@errorName(e)},
));
@@ -3555,7 +3686,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
decl_index,
try Module.ErrorMsg.create(
gpa,
- decl.srcLoc(zcu),
+ decl.navSrcLoc(zcu).upgrade(zcu),
"invalid liveness: {s}",
.{@errorName(err)},
),
@@ -3579,7 +3710,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
gpa,
- decl.srcLoc(zcu),
+ decl.navSrcLoc(zcu).upgrade(zcu),
"unable to codegen: {s}",
.{@errorName(err)},
));
@@ -3814,7 +3945,7 @@ fn semaFile(mod: *Module, file: *File) SemaError!void {
});
errdefer mod.destroyNamespace(new_namespace_index);
- const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0);
+ const new_decl_index = try mod.allocateNewDecl(new_namespace_index);
const new_decl = mod.declPtr(new_decl_index);
errdefer @panic("TODO error handling");
@@ -3961,7 +4092,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
- var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
+ var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);
defer comptime_err_ret_trace.deinit();
var sema: Sema = .{
@@ -3996,6 +4127,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
.instructions = .{},
.inlining = null,
.is_comptime = true,
+ .src_base_inst = decl.zir_decl_index.unwrap().?,
};
defer block_scope.instructions.deinit(gpa);
@@ -4005,11 +4137,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
// We'll do some other bits with the Sema. Clear the type target index just
// in case they analyze any type.
sema.builtin_type_target_index = .none;
- const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
- const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };
- const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
- const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
- const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
+ const align_src: LazySrcLoc = block_scope.src(.{ .node_offset_var_decl_align = 0 });
+ const section_src: LazySrcLoc = block_scope.src(.{ .node_offset_var_decl_section = 0 });
+ const address_space_src: LazySrcLoc = block_scope.src(.{ .node_offset_var_decl_addrspace = 0 });
+ const ty_src: LazySrcLoc = block_scope.src(.{ .node_offset_var_decl_ty = 0 });
+ const init_src: LazySrcLoc = block_scope.src(.{ .node_offset_var_decl_init = 0 });
const decl_val = try sema.resolveFinalDeclValue(&block_scope, init_src, result_ref);
const decl_ty = decl_val.typeOf(mod);
@@ -4143,7 +4275,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
}
if (decl.is_exported) {
- const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) };
+ const export_src: LazySrcLoc = block_scope.src(.{ .token_offset = @intFromBool(decl.is_pub) });
if (is_inline) return sema.fail(&block_scope, export_src, "export of inline function", .{});
// The scope needs to have the decl in it.
try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
@@ -4697,14 +4829,13 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
const was_exported = decl.is_exported;
assert(decl.kind == kind); // ZIR tracking should preserve this
decl.name = decl_name;
- decl.src_node = inst_data.src_node;
decl.src_line = line;
decl.is_pub = declaration.flags.is_pub;
decl.is_exported = declaration.flags.is_export;
break :decl_index .{ was_exported, decl_index };
} else decl_index: {
// Create and set up a new Decl.
- const new_decl_index = try zcu.allocateNewDecl(namespace_index, inst_data.src_node);
+ const new_decl_index = try zcu.allocateNewDecl(namespace_index);
const new_decl = zcu.declPtr(new_decl_index);
new_decl.kind = kind;
new_decl.name = decl_name;
@@ -4858,7 +4989,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
- var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
+ var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);
defer comptime_err_ret_trace.deinit();
// In the case of a generic function instance, this is the type of the
@@ -4913,6 +5044,14 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
.instructions = .{},
.inlining = null,
.is_comptime = false,
+ .src_base_inst = inst: {
+ const owner_info = if (func.generic_owner == .none)
+ func
+ else
+ mod.funcInfo(func.generic_owner);
+ const orig_decl = mod.declPtr(owner_info.owner_decl);
+ break :inst orig_decl.zir_decl_index.unwrap().?;
+ },
};
defer inner_block.instructions.deinit(gpa);
@@ -4954,7 +5093,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
runtime_param_index += 1;
const opt_opv = sema.typeHasOnePossibleValue(Type.fromInterned(param_ty)) catch |err| switch (err) {
- error.NeededSourceLocation => unreachable,
error.GenericPoison => unreachable,
error.ComptimeReturn => unreachable,
error.ComptimeBreak => unreachable,
@@ -4988,7 +5126,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) {
// TODO make these unreachable instead of @panic
- error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
else => |e| return e,
@@ -5010,7 +5147,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
{
sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) {
// TODO make these unreachable instead of @panic
- error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"),
@@ -5031,8 +5167,10 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
// state to success, so that "unable to resolve inferred error set" errors
// can be emitted here.
if (sema.fn_ret_ty_ies) |ies| {
- sema.resolveInferredErrorSetPtr(&inner_block, LazySrcLoc.nodeOffset(0), ies) catch |err| switch (err) {
- error.NeededSourceLocation => unreachable,
+ sema.resolveInferredErrorSetPtr(&inner_block, .{
+ .base_node_inst = inner_block.src_base_inst,
+ .offset = LazySrcLoc.Offset.nodeOffset(0),
+ }, ies) catch |err| switch (err) {
error.GenericPoison => unreachable,
error.ComptimeReturn => unreachable,
error.ComptimeBreak => unreachable,
@@ -5056,7 +5194,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
// so that dependencies on the function body will now be satisfied rather than
// result in circular dependency errors.
sema.resolveFnTypes(fn_ty) catch |err| switch (err) {
- error.NeededSourceLocation => unreachable,
error.GenericPoison => unreachable,
error.ComptimeReturn => unreachable,
error.ComptimeBreak => unreachable,
@@ -5073,7 +5210,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
// the backends.
for (sema.types_to_resolve.keys()) |ty| {
sema.resolveTypeFully(Type.fromInterned(ty)) catch |err| switch (err) {
- error.NeededSourceLocation => unreachable,
error.GenericPoison => unreachable,
error.ComptimeReturn => unreachable,
error.ComptimeBreak => unreachable,
@@ -5101,17 +5237,11 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void {
return mod.intern_pool.destroyNamespace(mod.gpa, index);
}
-pub fn allocateNewDecl(
- mod: *Module,
- namespace: Namespace.Index,
- src_node: Ast.Node.Index,
-) !Decl.Index {
- const ip = &mod.intern_pool;
- const gpa = mod.gpa;
- const decl_index = try ip.createDecl(gpa, .{
+pub fn allocateNewDecl(zcu: *Zcu, namespace: Namespace.Index) !Decl.Index {
+ const gpa = zcu.gpa;
+ const decl_index = try zcu.intern_pool.createDecl(gpa, .{
.name = undefined,
.src_namespace = namespace,
- .src_node = src_node,
.src_line = undefined,
.has_tv = false,
.owns_tv = false,
@@ -5126,10 +5256,10 @@ pub fn allocateNewDecl(
.kind = .anon,
});
- if (mod.emit_h) |mod_emit_h| {
- if (@intFromEnum(decl_index) >= mod_emit_h.allocated_emit_h.len) {
- try mod_emit_h.allocated_emit_h.append(gpa, .{});
- assert(@intFromEnum(decl_index) == mod_emit_h.allocated_emit_h.len);
+ if (zcu.emit_h) |zcu_emit_h| {
+ if (@intFromEnum(decl_index) >= zcu_emit_h.allocated_emit_h.len) {
+ try zcu_emit_h.allocated_emit_h.append(gpa, .{});
+ assert(@intFromEnum(decl_index) == zcu_emit_h.allocated_emit_h.len);
}
}
@@ -5223,376 +5353,6 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
}
}
-pub const SwitchProngSrc = union(enum) {
- /// The item for a scalar prong.
- scalar: u32,
- /// A given single item for a multi prong.
- multi: Multi,
- /// A given range item for a multi prong.
- range: Multi,
- /// The item for the special prong.
- special,
- /// The main capture for a scalar prong.
- scalar_capture: u32,
- /// The main capture for a multi prong.
- multi_capture: u32,
- /// The main capture for the special prong.
- special_capture,
- /// The tag capture for a scalar prong.
- scalar_tag_capture: u32,
- /// The tag capture for a multi prong.
- multi_tag_capture: u32,
- /// The tag capture for the special prong.
- special_tag_capture,
-
- pub const Multi = struct {
- prong: u32,
- item: u32,
- };
-
- pub const RangeExpand = enum { none, first, last };
-
- /// This function is intended to be called only when it is certain that we need
- /// the LazySrcLoc in order to emit a compile error.
- pub fn resolve(
- prong_src: SwitchProngSrc,
- mod: *Module,
- decl: *Decl,
- switch_node_offset: i32,
- /// Ignored if `prong_src` is not `.range`
- range_expand: RangeExpand,
- ) LazySrcLoc {
- @setCold(true);
- const gpa = mod.gpa;
- const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
- // In this case we emit a warning + a less precise source location.
- log.warn("unable to load {s}: {s}", .{
- decl.getFileScope(mod).sub_file_path, @errorName(err),
- });
- return LazySrcLoc.nodeOffset(0);
- };
- const switch_node = decl.relativeToNodeIndex(switch_node_offset);
- const main_tokens = tree.nodes.items(.main_token);
- const node_datas = tree.nodes.items(.data);
- const node_tags = tree.nodes.items(.tag);
- const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
- const case_nodes = tree.extra_data[extra.start..extra.end];
-
- var multi_i: u32 = 0;
- var scalar_i: u32 = 0;
- const case_node = for (case_nodes) |case_node| {
- const case = tree.fullSwitchCase(case_node).?;
-
- const is_special = special: {
- if (case.ast.values.len == 0) break :special true;
- if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .identifier) {
- break :special mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_");
- }
- break :special false;
- };
-
- if (is_special) {
- switch (prong_src) {
- .special, .special_capture, .special_tag_capture => break case_node,
- else => continue,
- }
- }
-
- const is_multi = case.ast.values.len != 1 or
- node_tags[case.ast.values[0]] == .switch_range;
-
- switch (prong_src) {
- .scalar,
- .scalar_capture,
- .scalar_tag_capture,
- => |i| if (!is_multi and i == scalar_i) break case_node,
-
- .multi_capture,
- .multi_tag_capture,
- => |i| if (is_multi and i == multi_i) break case_node,
-
- .multi,
- .range,
- => |m| if (is_multi and m.prong == multi_i) break case_node,
-
- .special,
- .special_capture,
- .special_tag_capture,
- => {},
- }
-
- if (is_multi) {
- multi_i += 1;
- } else {
- scalar_i += 1;
- }
- } else unreachable;
-
- const case = tree.fullSwitchCase(case_node).?;
-
- switch (prong_src) {
- .scalar, .special => return LazySrcLoc.nodeOffset(
- decl.nodeIndexToRelative(case.ast.values[0]),
- ),
- .multi => |m| {
- var item_i: u32 = 0;
- for (case.ast.values) |item_node| {
- if (node_tags[item_node] == .switch_range) continue;
- if (item_i == m.item) return LazySrcLoc.nodeOffset(
- decl.nodeIndexToRelative(item_node),
- );
- item_i += 1;
- }
- unreachable;
- },
- .range => |m| {
- var range_i: u32 = 0;
- for (case.ast.values) |range| {
- if (node_tags[range] != .switch_range) continue;
- if (range_i == m.item) switch (range_expand) {
- .none => return LazySrcLoc.nodeOffset(
- decl.nodeIndexToRelative(range),
- ),
- .first => return LazySrcLoc.nodeOffset(
- decl.nodeIndexToRelative(node_datas[range].lhs),
- ),
- .last => return LazySrcLoc.nodeOffset(
- decl.nodeIndexToRelative(node_datas[range].rhs),
- ),
- };
- range_i += 1;
- }
- unreachable;
- },
- .scalar_capture, .multi_capture, .special_capture => {
- return .{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
- },
- .scalar_tag_capture, .multi_tag_capture, .special_tag_capture => {
- return .{ .node_offset_switch_prong_tag_capture = decl.nodeIndexToRelative(case_node) };
- },
- }
- }
-};
-
-pub const PeerTypeCandidateSrc = union(enum) {
- /// Do not print out error notes for candidate sources
- none: void,
- /// When we want to know the the src of candidate i, look up at
- /// index i in this slice
- override: []const ?LazySrcLoc,
- /// resolvePeerTypes originates from a @TypeOf(...) call
- typeof_builtin_call_node_offset: i32,
-
- pub fn resolve(
- self: PeerTypeCandidateSrc,
- mod: *Module,
- decl: *Decl,
- candidate_i: usize,
- ) ?LazySrcLoc {
- @setCold(true);
- const gpa = mod.gpa;
-
- switch (self) {
- .none => {
- return null;
- },
- .override => |candidate_srcs| {
- if (candidate_i >= candidate_srcs.len)
- return null;
- return candidate_srcs[candidate_i];
- },
- .typeof_builtin_call_node_offset => |node_offset| {
- switch (candidate_i) {
- 0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = node_offset },
- 1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = node_offset },
- 2 => return LazySrcLoc{ .node_offset_builtin_call_arg2 = node_offset },
- 3 => return LazySrcLoc{ .node_offset_builtin_call_arg3 = node_offset },
- 4 => return LazySrcLoc{ .node_offset_builtin_call_arg4 = node_offset },
- 5 => return LazySrcLoc{ .node_offset_builtin_call_arg5 = node_offset },
- else => {},
- }
-
- const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
- // In this case we emit a warning + a less precise source location.
- log.warn("unable to load {s}: {s}", .{
- decl.getFileScope(mod).sub_file_path, @errorName(err),
- });
- return LazySrcLoc.nodeOffset(0);
- };
- const node = decl.relativeToNodeIndex(node_offset);
- const node_datas = tree.nodes.items(.data);
- const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
-
- return LazySrcLoc{ .node_abs = params[candidate_i] };
- },
- }
- }
-};
-
-const FieldSrcQuery = struct {
- index: usize,
- range: enum { name, type, value, alignment } = .name,
-};
-
-fn queryFieldSrc(
- tree: Ast,
- query: FieldSrcQuery,
- file_scope: *File,
- container_decl: Ast.full.ContainerDecl,
-) SrcLoc {
- var field_index: usize = 0;
- for (container_decl.ast.members) |member_node| {
- const field = tree.fullContainerField(member_node) orelse continue;
- if (field_index == query.index) {
- return switch (query.range) {
- .name => .{
- .file_scope = file_scope,
- .parent_decl_node = 0,
- .lazy = .{ .token_abs = field.ast.main_token },
- },
- .type => .{
- .file_scope = file_scope,
- .parent_decl_node = 0,
- .lazy = .{ .node_abs = field.ast.type_expr },
- },
- .value => .{
- .file_scope = file_scope,
- .parent_decl_node = 0,
- .lazy = .{ .node_abs = field.ast.value_expr },
- },
- .alignment => .{
- .file_scope = file_scope,
- .parent_decl_node = 0,
- .lazy = .{ .node_abs = field.ast.align_expr },
- },
- };
- }
- field_index += 1;
- }
- unreachable;
-}
-
-pub fn paramSrc(
- func_node_offset: i32,
- mod: *Module,
- decl: *Decl,
- param_i: usize,
-) LazySrcLoc {
- @setCold(true);
- const gpa = mod.gpa;
- const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
- // In this case we emit a warning + a less precise source location.
- log.warn("unable to load {s}: {s}", .{
- decl.getFileScope(mod).sub_file_path, @errorName(err),
- });
- return LazySrcLoc.nodeOffset(0);
- };
- const node = decl.relativeToNodeIndex(func_node_offset);
- var buf: [1]Ast.Node.Index = undefined;
- const full = tree.fullFnProto(&buf, node).?;
- var it = full.iterate(tree);
- var i: usize = 0;
- while (it.next()) |param| : (i += 1) {
- if (i == param_i) {
- if (param.anytype_ellipsis3) |some| {
- const main_token = tree.nodes.items(.main_token)[decl.src_node];
- return .{ .token_offset_param = @as(i32, @bitCast(some)) - @as(i32, @bitCast(main_token)) };
- }
- return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };
- }
- }
- unreachable;
-}
-
-pub fn initSrc(
- mod: *Module,
- init_node_offset: i32,
- decl: *Decl,
- init_index: usize,
-) LazySrcLoc {
- @setCold(true);
- const gpa = mod.gpa;
- const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
- // In this case we emit a warning + a less precise source location.
- log.warn("unable to load {s}: {s}", .{
- decl.getFileScope(mod).sub_file_path, @errorName(err),
- });
- return LazySrcLoc.nodeOffset(0);
- };
- const node_tags = tree.nodes.items(.tag);
- const node = decl.relativeToNodeIndex(init_node_offset);
- var buf: [2]Ast.Node.Index = undefined;
- switch (node_tags[node]) {
- .array_init_one,
- .array_init_one_comma,
- .array_init_dot_two,
- .array_init_dot_two_comma,
- .array_init_dot,
- .array_init_dot_comma,
- .array_init,
- .array_init_comma,
- => {
- const full = tree.fullArrayInit(&buf, node).?.ast.elements;
- return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full[init_index]));
- },
- .struct_init_one,
- .struct_init_one_comma,
- .struct_init_dot_two,
- .struct_init_dot_two_comma,
- .struct_init_dot,
- .struct_init_dot_comma,
- .struct_init,
- .struct_init_comma,
- => {
- const full = tree.fullStructInit(&buf, node).?.ast.fields;
- return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(full[init_index]) };
- },
- else => return LazySrcLoc.nodeOffset(init_node_offset),
- }
-}
-
-pub fn optionsSrc(mod: *Module, decl: *Decl, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc {
- @setCold(true);
- const gpa = mod.gpa;
- const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
- // In this case we emit a warning + a less precise source location.
- log.warn("unable to load {s}: {s}", .{
- decl.getFileScope(mod).sub_file_path, @errorName(err),
- });
- return LazySrcLoc.nodeOffset(0);
- };
-
- const o_i: struct { off: i32, i: u8 } = switch (base_src) {
- .node_offset_builtin_call_arg0 => |n| .{ .off = n, .i = 0 },
- .node_offset_builtin_call_arg1 => |n| .{ .off = n, .i = 1 },
- else => unreachable,
- };
-
- const node = decl.relativeToNodeIndex(o_i.off);
- const node_datas = tree.nodes.items(.data);
- const node_tags = tree.nodes.items(.tag);
- const arg_node = switch (node_tags[node]) {
- .builtin_call_two, .builtin_call_two_comma => switch (o_i.i) {
- 0 => node_datas[node].lhs,
- 1 => node_datas[node].rhs,
- else => unreachable,
- },
- .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + o_i.i],
- else => unreachable,
- };
- var buf: [2]std.zig.Ast.Node.Index = undefined;
- const init_nodes = if (tree.fullStructInit(&buf, arg_node)) |struct_init| struct_init.ast.fields else return base_src;
- for (init_nodes) |init_node| {
- // . IDENTIFIER = init_node
- const name_token = tree.firstToken(init_node) - 2;
- const name = tree.tokenSlice(name_token);
- if (std.mem.eql(u8, name, wanted)) {
- return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(init_node) };
- }
- }
- return base_src;
-}
-
/// Called from `Compilation.update`, after everything is done, just before
/// reporting compile errors. In this function we emit exported symbol collision
/// errors and communicate exported symbols to the linker backend.
@@ -5826,7 +5586,7 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
gpa,
- decl.srcLoc(zcu),
+ decl.navSrcLoc(zcu).upgrade(zcu),
"unable to codegen: {s}",
.{@errorName(err)},
));
@@ -5857,7 +5617,7 @@ fn reportRetryableFileError(
mod.gpa,
.{
.file_scope = file,
- .parent_decl_node = 0,
+ .base_node = 0,
.lazy = .entire_file,
},
format,
@@ -6432,27 +6192,6 @@ pub fn funcInfo(mod: *Module, func_index: InternPool.Index) InternPool.Key.Func
return mod.intern_pool.indexToKey(func_index).func;
}
-pub fn fieldSrcLoc(mod: *Module, owner_decl_index: Decl.Index, query: FieldSrcQuery) SrcLoc {
- @setCold(true);
- const owner_decl = mod.declPtr(owner_decl_index);
- const file = owner_decl.getFileScope(mod);
- const tree = file.getTree(mod.gpa) catch |err| {
- // In this case we emit a warning + a less precise source location.
- log.warn("unable to load {s}: {s}", .{
- file.sub_file_path, @errorName(err),
- });
- return owner_decl.srcLoc(mod);
- };
- const node = owner_decl.relativeToNodeIndex(0);
- var buf: [2]Ast.Node.Index = undefined;
- if (tree.fullContainerDecl(&buf, node)) |container_decl| {
- return queryFieldSrc(tree.*, query, file, container_decl);
- } else {
- // This type was generated using @Type
- return owner_decl.srcLoc(mod);
- }
-}
-
pub fn toEnum(mod: *Module, comptime E: type, val: Value) E {
return mod.intern_pool.toEnum(E, val.toIntern());
}