srctree

Andrew Kelley parent 27f589de 97f2a8b5 6f7354a0
Merge pull request #19102 from ziglang/decouple-zir

JIT zig fmt and zig reduce

inlinesplit
CMakeLists.txt added: 1602, removed: 1475, total 127
@@ -505,6 +505,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/unicode.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/Ast.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/AstGen.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/AstRlAnnotate.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/c_builtins.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/Parse.zig"
@@ -515,8 +516,8 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/zig/system/NativePaths.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/system/x86.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
"${CMAKE_SOURCE_DIR}/lib/std/zig/Zir.zig"
"${CMAKE_SOURCE_DIR}/src/Air.zig"
"${CMAKE_SOURCE_DIR}/src/AstGen.zig"
"${CMAKE_SOURCE_DIR}/src/Compilation.zig"
"${CMAKE_SOURCE_DIR}/src/Compilation/Config.zig"
"${CMAKE_SOURCE_DIR}/src/Liveness.zig"
@@ -527,7 +528,6 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/Sema.zig"
"${CMAKE_SOURCE_DIR}/src/TypedValue.zig"
"${CMAKE_SOURCE_DIR}/src/Value.zig"
"${CMAKE_SOURCE_DIR}/src/Zir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Mir.zig"
 
build.zig added: 1602, removed: 1475, total 127
@@ -34,7 +34,6 @@ pub fn build(b: *std.Build) !void {
const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files;
const skip_install_autodocs = b.option(bool, "no-autodocs", "skip copying of standard library autodocs to the installation prefix") orelse skip_install_lib_files;
const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false;
const only_reduce = b.option(bool, "only-reduce", "only build zig reduce") orelse false;
 
const docgen_exe = b.addExecutable(.{
.name = "docgen",
@@ -245,7 +244,6 @@ pub fn build(b: *std.Build) !void {
exe_options.addOption(bool, "force_gpa", force_gpa);
exe_options.addOption(bool, "only_c", only_c);
exe_options.addOption(bool, "only_core_functionality", only_c);
exe_options.addOption(bool, "only_reduce", only_reduce);
 
if (link_libc) {
exe.linkLibC();
@@ -407,7 +405,6 @@ pub fn build(b: *std.Build) !void {
test_cases_options.addOption(bool, "force_gpa", force_gpa);
test_cases_options.addOption(bool, "only_c", only_c);
test_cases_options.addOption(bool, "only_core_functionality", true);
test_cases_options.addOption(bool, "only_reduce", false);
test_cases_options.addOption(bool, "enable_qemu", b.enable_qemu);
test_cases_options.addOption(bool, "enable_wine", b.enable_wine);
test_cases_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime);
@@ -599,7 +596,6 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
exe_options.addOption(bool, "enable_tracy_allocation", false);
exe_options.addOption(bool, "value_tracing", false);
exe_options.addOption(bool, "only_core_functionality", true);
exe_options.addOption(bool, "only_reduce", false);
 
const run_opt = b.addSystemCommand(&.{
"wasm-opt",
 
lib/build_runner.zig added: 1602, removed: 1475, total 127
@@ -13,7 +13,7 @@ const Step = std.Build.Step;
pub const dependencies = @import("@dependencies");
 
pub fn main() !void {
// Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,
// Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived,
// one shot program. We don't need to waste time freeing memory and finding places to squish
// bytes into. So we free everything all at once at the very end.
var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
 
filename was Deleted added: 1602, removed: 1475, total 127
@@ -0,0 +1,342 @@
const std = @import("std");
const mem = std.mem;
const fs = std.fs;
const process = std.process;
const Allocator = std.mem.Allocator;
const warn = std.log.warn;
const Color = std.zig.Color;
 
const usage_fmt =
\\Usage: zig fmt [file]...
\\
\\ Formats the input files and modifies them in-place.
\\ Arguments can be files or directories, which are searched
\\ recursively.
\\
\\Options:
\\ -h, --help Print this help and exit
\\ --color [auto|off|on] Enable or disable colored error messages
\\ --stdin Format code from stdin; output to stdout
\\ --check List non-conforming files and exit with an error
\\ if the list is non-empty
\\ --ast-check Run zig ast-check on every file
\\ --exclude [file] Exclude file or directory from formatting
\\
\\
;
 
const Fmt = struct {
seen: SeenMap,
any_error: bool,
check_ast: bool,
color: Color,
gpa: Allocator,
arena: Allocator,
out_buffer: std.ArrayList(u8),
 
const SeenMap = std.AutoHashMap(fs.File.INode, void);
};
 
pub fn main() !void {
var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_instance.deinit();
const arena = arena_instance.allocator();
const gpa = arena;
 
const args = try process.argsAlloc(arena);
 
var color: Color = .auto;
var stdin_flag: bool = false;
var check_flag: bool = false;
var check_ast_flag: bool = false;
var input_files = std.ArrayList([]const u8).init(gpa);
defer input_files.deinit();
var excluded_files = std.ArrayList([]const u8).init(gpa);
defer excluded_files.deinit();
 
{
var i: usize = 1;
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
const stdout = std.io.getStdOut().writer();
try stdout.writeAll(usage_fmt);
return process.cleanExit();
} else if (mem.eql(u8, arg, "--color")) {
if (i + 1 >= args.len) {
fatal("expected [auto|on|off] after --color", .{});
}
i += 1;
const next_arg = args[i];
color = std.meta.stringToEnum(Color, next_arg) orelse {
fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
};
} else if (mem.eql(u8, arg, "--stdin")) {
stdin_flag = true;
} else if (mem.eql(u8, arg, "--check")) {
check_flag = true;
} else if (mem.eql(u8, arg, "--ast-check")) {
check_ast_flag = true;
} else if (mem.eql(u8, arg, "--exclude")) {
if (i + 1 >= args.len) {
fatal("expected parameter after --exclude", .{});
}
i += 1;
const next_arg = args[i];
try excluded_files.append(next_arg);
} else {
fatal("unrecognized parameter: '{s}'", .{arg});
}
} else {
try input_files.append(arg);
}
}
}
 
if (stdin_flag) {
if (input_files.items.len != 0) {
fatal("cannot use --stdin with positional arguments", .{});
}
 
const stdin = std.io.getStdIn();
const source_code = std.zig.readSourceFileToEndAlloc(gpa, stdin, null) catch |err| {
fatal("unable to read stdin: {}", .{err});
};
defer gpa.free(source_code);
 
var tree = std.zig.Ast.parse(gpa, source_code, .zig) catch |err| {
fatal("error parsing stdin: {}", .{err});
};
defer tree.deinit(gpa);
 
if (check_ast_flag) {
var zir = try std.zig.AstGen.generate(gpa, tree);
 
if (zir.hasCompileErrors()) {
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
try wip_errors.init(gpa);
defer wip_errors.deinit();
try wip_errors.addZirErrorMessages(zir, tree, source_code, "<stdin>");
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(color.renderOptions());
process.exit(2);
}
} else if (tree.errors.len != 0) {
try std.zig.printAstErrorsToStderr(gpa, tree, "<stdin>", color);
process.exit(2);
}
const formatted = try tree.render(gpa);
defer gpa.free(formatted);
 
if (check_flag) {
const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
process.exit(code);
}
 
return std.io.getStdOut().writeAll(formatted);
}
 
if (input_files.items.len == 0) {
fatal("expected at least one source file argument", .{});
}
 
var fmt = Fmt{
.gpa = gpa,
.arena = arena,
.seen = Fmt.SeenMap.init(gpa),
.any_error = false,
.check_ast = check_ast_flag,
.color = color,
.out_buffer = std.ArrayList(u8).init(gpa),
};
defer fmt.seen.deinit();
defer fmt.out_buffer.deinit();
 
// Mark any excluded files/directories as already seen,
// so that they are skipped later during actual processing
for (excluded_files.items) |file_path| {
const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
error.FileNotFound => continue,
// On Windows, statFile does not work for directories
error.IsDir => dir: {
var dir = try fs.cwd().openDir(file_path, .{});
defer dir.close();
break :dir try dir.stat();
},
else => |e| return e,
};
try fmt.seen.put(stat.inode, {});
}
 
for (input_files.items) |file_path| {
try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
}
if (fmt.any_error) {
process.exit(1);
}
}
 
const FmtError = error{
SystemResources,
OperationAborted,
IoPending,
BrokenPipe,
Unexpected,
WouldBlock,
FileClosed,
DestinationAddressRequired,
DiskQuota,
FileTooBig,
InputOutput,
NoSpaceLeft,
AccessDenied,
OutOfMemory,
RenameAcrossMountPoints,
ReadOnlyFileSystem,
LinkQuotaExceeded,
FileBusy,
EndOfStream,
Unseekable,
NotOpenForWriting,
UnsupportedEncoding,
ConnectionResetByPeer,
SocketNotConnected,
LockViolation,
NetNameDeleted,
InvalidArgument,
} || fs.File.OpenError;
 
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
else => {
warn("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
fmt.any_error = true;
return;
},
};
}
 
fn fmtPathDir(
fmt: *Fmt,
file_path: []const u8,
check_mode: bool,
parent_dir: fs.Dir,
parent_sub_path: []const u8,
) FmtError!void {
var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
defer dir.close();
 
const stat = try dir.stat();
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
 
var dir_it = dir.iterate();
while (try dir_it.next()) |entry| {
const is_dir = entry.kind == .directory;
 
if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
 
if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
defer fmt.gpa.free(full_path);
 
if (is_dir) {
try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
} else {
fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
fmt.any_error = true;
return;
};
}
}
}
}
 
fn fmtPathFile(
fmt: *Fmt,
file_path: []const u8,
check_mode: bool,
dir: fs.Dir,
sub_path: []const u8,
) FmtError!void {
const source_file = try dir.openFile(sub_path, .{});
var file_closed = false;
errdefer if (!file_closed) source_file.close();
 
const stat = try source_file.stat();
 
if (stat.kind == .directory)
return error.IsDir;
 
const gpa = fmt.gpa;
const source_code = try std.zig.readSourceFileToEndAlloc(
gpa,
source_file,
std.math.cast(usize, stat.size) orelse return error.FileTooBig,
);
defer gpa.free(source_code);
 
source_file.close();
file_closed = true;
 
// Add to set after no longer possible to get error.IsDir.
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
 
var tree = try std.zig.Ast.parse(gpa, source_code, .zig);
defer tree.deinit(gpa);
 
if (tree.errors.len != 0) {
try std.zig.printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
fmt.any_error = true;
return;
}
 
if (fmt.check_ast) {
if (stat.size > std.zig.max_src_size)
return error.FileTooBig;
 
var zir = try std.zig.AstGen.generate(gpa, tree);
defer zir.deinit(gpa);
 
if (zir.hasCompileErrors()) {
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
try wip_errors.init(gpa);
defer wip_errors.deinit();
try wip_errors.addZirErrorMessages(zir, tree, source_code, file_path);
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(fmt.color.renderOptions());
fmt.any_error = true;
}
}
 
// As a heuristic, we make enough capacity for the same as the input source.
fmt.out_buffer.shrinkRetainingCapacity(0);
try fmt.out_buffer.ensureTotalCapacity(source_code.len);
 
try tree.renderToArrayList(&fmt.out_buffer, .{});
if (mem.eql(u8, fmt.out_buffer.items, source_code))
return;
 
if (check_mode) {
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}\n", .{file_path});
fmt.any_error = true;
} else {
var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
defer af.deinit();
 
try af.file.writeAll(fmt.out_buffer.items);
try af.finish();
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}\n", .{file_path});
}
}
 
fn fatal(comptime format: []const u8, args: anytype) noreturn {
std.log.err(format, args);
process.exit(1);
}
 
src/reduce.zig added: 1602, removed: 1475, total 127
@@ -2,11 +2,10 @@ const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const fatal = @import("./main.zig").fatal;
const Ast = std.zig.Ast;
const Walk = @import("reduce/Walk.zig");
const AstGen = @import("AstGen.zig");
const Zir = @import("Zir.zig");
const AstGen = std.zig.AstGen;
const Zir = std.zig.Zir;
 
const usage =
\\zig reduce [options] ./checker root_source_file.zig [-- [argv]]
@@ -47,7 +46,16 @@ const Interestingness = enum { interesting, unknown, boring };
// - reduce flags sent to the compiler
// - integrate with the build system?
 
pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
pub fn main() !void {
var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_instance.deinit();
const arena = arena_instance.allocator();
 
var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
const gpa = general_purpose_allocator.allocator();
 
const args = try std.process.argsAlloc(arena);
 
var opt_checker_path: ?[]const u8 = null;
var opt_root_source_file_path: ?[]const u8 = null;
var argv: []const []const u8 = &.{};
@@ -55,7 +63,7 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
var skip_smoke_test = false;
 
{
var i: usize = 2; // skip over "zig" and "reduce"
var i: usize = 1;
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
@@ -411,3 +419,8 @@ fn parse(gpa: Allocator, file_path: []const u8) !Ast {
 
return tree;
}
 
fn fatal(comptime format: []const u8, args: anytype) noreturn {
std.log.err(format, args);
std.process.exit(1);
}
 
filename was Deleted added: 1602, removed: 1475, total 127
 
filename was Deleted added: 1602, removed: 1475, total 127
 
lib/std/std.zig added: 1602, removed: 1475, total 127
@@ -193,7 +193,9 @@ pub const valgrind = @import("valgrind.zig");
/// Constants and types representing the Wasm binary format.
pub const wasm = @import("wasm.zig");
 
/// Tokenizing and parsing of Zig code and other Zig-specific language tooling.
/// Builds of the Zig compiler are distributed partly in source form. That
/// source lives here. These APIs are provided as-is and have absolutely no API
/// guarantees whatsoever.
pub const zig = @import("zig.zig");
 
pub const start = @import("start.zig");
 
lib/std/zig.zig added: 1602, removed: 1475, total 127
@@ -1,17 +1,14 @@
pub const fmt = @import("zig/fmt.zig");
 
pub const ErrorBundle = @import("zig/ErrorBundle.zig");
pub const Server = @import("zig/Server.zig");
pub const Client = @import("zig/Client.zig");
pub const Token = tokenizer.Token;
pub const Tokenizer = tokenizer.Tokenizer;
pub const fmtId = fmt.fmtId;
pub const fmtEscapes = fmt.fmtEscapes;
pub const isValidId = fmt.isValidId;
pub const string_literal = @import("zig/string_literal.zig");
pub const number_literal = @import("zig/number_literal.zig");
pub const primitives = @import("zig/primitives.zig");
pub const Ast = @import("zig/Ast.zig");
pub const AstGen = @import("zig/AstGen.zig");
pub const Zir = @import("zig/Zir.zig");
pub const system = @import("zig/system.zig");
/// Deprecated: use `std.Target.Query`.
pub const CrossTarget = std.Target.Query;
@@ -30,6 +27,36 @@ pub const c_translation = @import("zig/c_translation.zig");
pub const SrcHasher = std.crypto.hash.Blake3;
pub const SrcHash = [16]u8;
 
pub const Color = enum {
/// Determine whether stderr is a terminal or not automatically.
auto,
/// Assume stderr is not a terminal.
off,
/// Assume stderr is a terminal.
on,
 
pub fn get_tty_conf(color: Color) std.io.tty.Config {
return switch (color) {
.auto => std.io.tty.detectConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
}
 
pub fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {
const ttyconf = get_tty_conf(color);
return .{
.ttyconf = ttyconf,
.include_source_line = ttyconf != .no_color,
.include_reference_trace = ttyconf != .no_color,
};
}
};
 
/// There are many assumptions in the entire codebase that Zig source files can
/// be byte-indexed with a u32 integer.
pub const max_src_size = std.math.maxInt(u32);
 
pub fn hashSrc(src: []const u8) SrcHash {
var out: SrcHash = undefined;
SrcHasher.hash(src, &out, .{});
@@ -315,11 +342,573 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
return buffer.toOwnedSlice();
}
 
pub const DeclIndex = enum(u32) {
_,
 
pub fn toOptional(i: DeclIndex) OptionalDeclIndex {
return @enumFromInt(@intFromEnum(i));
}
};
 
pub const OptionalDeclIndex = enum(u32) {
none = std.math.maxInt(u32),
_,
 
pub fn init(oi: ?DeclIndex) OptionalDeclIndex {
return @enumFromInt(@intFromEnum(oi orelse return .none));
}
 
pub fn unwrap(oi: OptionalDeclIndex) ?DeclIndex {
if (oi == .none) return null;
return @enumFromInt(@intFromEnum(oi));
}
};
 
/// 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: DeclIndex,
/// 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: DeclIndex,
/// 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 nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
 
noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
result.node_offset.trace.addAddr(@returnAddress(), "init");
return result;
}
 
fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
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 = .{},
 
const want_tracing = false;
};
};
 
const std = @import("std.zig");
const tokenizer = @import("zig/tokenizer.zig");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
 
test {
@import("std").testing.refAllDecls(@This());
/// Return a Formatter for a Zig identifier
pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
return .{ .data = bytes };
}
 
/// Print the string as a Zig identifier escaping it with @"" syntax if needed.
fn formatId(
bytes: []const u8,
comptime unused_format_string: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = unused_format_string;
if (isValidId(bytes)) {
return writer.writeAll(bytes);
}
try writer.writeAll("@\"");
try stringEscape(bytes, "", options, writer);
try writer.writeByte('"');
}
 
/// Return a Formatter for Zig Escapes of a double quoted string.
/// The format specifier must be one of:
/// * `{}` treats contents as a double-quoted string.
/// * `{'}` treats contents as a single-quoted string.
pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) {
return .{ .data = bytes };
}
 
test "escape invalid identifiers" {
const expectFmt = std.testing.expectFmt;
try expectFmt("@\"while\"", "{}", .{fmtId("while")});
try expectFmt("hello", "{}", .{fmtId("hello")});
try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")});
try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
try expectFmt(
\\" \\ hi \x07 \x11 " derp \'"
, "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
try expectFmt(
\\" \\ hi \x07 \x11 \" derp '"
, "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
}
 
/// Print the string as escaped contents of a double quoted or single-quoted string.
/// Format `{}` treats contents as a double-quoted string.
/// Format `{'}` treats contents as a single-quoted string.
pub fn stringEscape(
bytes: []const u8,
comptime f: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = options;
for (bytes) |byte| switch (byte) {
'\n' => try writer.writeAll("\\n"),
'\r' => try writer.writeAll("\\r"),
'\t' => try writer.writeAll("\\t"),
'\\' => try writer.writeAll("\\\\"),
'"' => {
if (f.len == 1 and f[0] == '\'') {
try writer.writeByte('"');
} else if (f.len == 0) {
try writer.writeAll("\\\"");
} else {
@compileError("expected {} or {'}, found {" ++ f ++ "}");
}
},
'\'' => {
if (f.len == 1 and f[0] == '\'') {
try writer.writeAll("\\'");
} else if (f.len == 0) {
try writer.writeByte('\'');
} else {
@compileError("expected {} or {'}, found {" ++ f ++ "}");
}
},
' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
// Use hex escapes for rest any unprintable characters.
else => {
try writer.writeAll("\\x");
try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
},
};
}
 
pub fn isValidId(bytes: []const u8) bool {
if (bytes.len == 0) return false;
if (std.mem.eql(u8, bytes, "_")) return false;
for (bytes, 0..) |c, i| {
switch (c) {
'_', 'a'...'z', 'A'...'Z' => {},
'0'...'9' => if (i == 0) return false,
else => return false,
}
}
return std.zig.Token.getKeyword(bytes) == null;
}
 
test isValidId {
try std.testing.expect(!isValidId(""));
try std.testing.expect(isValidId("foobar"));
try std.testing.expect(!isValidId("a b c"));
try std.testing.expect(!isValidId("3d"));
try std.testing.expect(!isValidId("enum"));
try std.testing.expect(isValidId("i386"));
}
 
pub fn readSourceFileToEndAlloc(
allocator: Allocator,
input: std.fs.File,
size_hint: ?usize,
) ![:0]u8 {
const source_code = input.readToEndAllocOptions(
allocator,
max_src_size,
size_hint,
@alignOf(u16),
0,
) catch |err| switch (err) {
error.ConnectionResetByPeer => unreachable,
error.ConnectionTimedOut => unreachable,
error.NotOpenForReading => unreachable,
else => |e| return e,
};
errdefer allocator.free(source_code);
 
// Detect unsupported file types with their Byte Order Mark
const unsupported_boms = [_][]const u8{
"\xff\xfe\x00\x00", // UTF-32 little endian
"\xfe\xff\x00\x00", // UTF-32 big endian
"\xfe\xff", // UTF-16 big endian
};
for (unsupported_boms) |bom| {
if (std.mem.startsWith(u8, source_code, bom)) {
return error.UnsupportedEncoding;
}
}
 
// If the file starts with a UTF-16 little endian BOM, translate it to UTF-8
if (std.mem.startsWith(u8, source_code, "\xff\xfe")) {
const source_code_utf16_le = std.mem.bytesAsSlice(u16, source_code);
const source_code_utf8 = std.unicode.utf16LeToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) {
error.DanglingSurrogateHalf => error.UnsupportedEncoding,
error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,
error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,
else => |e| return e,
};
 
allocator.free(source_code);
return source_code_utf8;
}
 
return source_code;
}
 
pub fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
try wip_errors.init(gpa);
defer wip_errors.deinit();
 
try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
 
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(color.renderOptions());
}
 
pub fn putAstErrorsIntoBundle(
gpa: Allocator,
tree: Ast,
path: []const u8,
wip_errors: *std.zig.ErrorBundle.Wip,
) Allocator.Error!void {
var zir = try AstGen.generate(gpa, tree);
defer zir.deinit(gpa);
 
try wip_errors.addZirErrorMessages(zir, tree, tree.source, path);
}
 
test {
_ = Ast;
_ = AstRlAnnotate;
_ = BuiltinFn;
_ = Client;
_ = ErrorBundle;
_ = Server;
_ = number_literal;
_ = primitives;
_ = string_literal;
_ = system;
}
 
lib/std/zig/Ast.zig added: 1602, removed: 1475, total 127
@@ -32,6 +32,12 @@ pub const Location = struct {
line_end: usize,
};
 
pub const Span = struct {
start: u32,
end: u32,
main: u32,
};
 
pub fn deinit(tree: *Ast, gpa: Allocator) void {
tree.tokens.deinit(gpa);
tree.nodes.deinit(gpa);
@@ -105,9 +111,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A
};
}
 
/// `gpa` is used for allocating the resulting formatted source code, as well as
/// for allocating extra stack memory if needed, because this function utilizes recursion.
/// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006.
/// `gpa` is used for allocating the resulting formatted source code.
/// Caller owns the returned slice of bytes, allocated with `gpa`.
pub fn render(tree: Ast, gpa: Allocator) RenderError![]u8 {
var buffer = std.ArrayList(u8).init(gpa);
@@ -3535,6 +3539,39 @@ pub const Node = struct {
};
};
 
pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
return tokensToSpan(
tree,
tree.firstToken(node),
tree.lastToken(node),
tree.nodes.items(.main_token)[node],
);
}
 
pub fn tokenToSpan(tree: *const Ast, token: Ast.TokenIndex) Span {
return tokensToSpan(tree, token, token, token);
}
 
pub fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span {
const token_starts = tree.tokens.items(.start);
var start_tok = start;
var end_tok = end;
 
if (tree.tokensOnSameLine(start, end)) {
// do nothing
} else if (tree.tokensOnSameLine(start, main)) {
end_tok = main;
} else if (tree.tokensOnSameLine(main, end)) {
start_tok = main;
} else {
start_tok = main;
end_tok = main;
}
const start_off = token_starts[start_tok];
const end_off = token_starts[end_tok] + @as(u32, @intCast(tree.tokenSlice(end_tok).len));
return Span{ .start = start_off, .end = end_off, .main = token_starts[main] };
}
 
const std = @import("../std.zig");
const assert = std.debug.assert;
const testing = std.testing;
@@ -3546,5 +3583,6 @@ const Parse = @import("Parse.zig");
const private_render = @import("./render.zig");
 
test {
testing.refAllDecls(@This());
_ = Parse;
_ = private_render;
}
 
src/AstGen.zig added: 1602, removed: 1475, total 127
@@ -12,7 +12,7 @@ const StringIndexContext = std.hash_map.StringIndexContext;
 
const isPrimitive = std.zig.primitives.isPrimitive;
 
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const BuiltinFn = std.zig.BuiltinFn;
const AstRlAnnotate = std.zig.AstRlAnnotate;
 
 
lib/std/zig/ErrorBundle.zig added: 1602, removed: 1475, total 127
@@ -459,6 +459,90 @@ pub const Wip = struct {
return @intCast(wip.extra.items.len - notes_len);
}
 
pub fn addZirErrorMessages(
eb: *ErrorBundle.Wip,
zir: std.zig.Zir,
tree: std.zig.Ast,
source: [:0]const u8,
src_path: []const u8,
) !void {
const Zir = std.zig.Zir;
const payload_index = zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
assert(payload_index != 0);
 
const header = zir.extraData(Zir.Inst.CompileErrors, payload_index);
const items_len = header.data.items_len;
var extra_index = header.end;
for (0..items_len) |_| {
const item = zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
extra_index = item.end;
const err_span = blk: {
if (item.data.node != 0) {
break :blk tree.nodeToSpan(item.data.node);
}
const token_starts = tree.tokens.items(.start);
const start = token_starts[item.data.token] + item.data.byte_offset;
const end = start + @as(u32, @intCast(tree.tokenSlice(item.data.token).len)) - item.data.byte_offset;
break :blk std.zig.Ast.Span{ .start = start, .end = end, .main = start };
};
const err_loc = std.zig.findLineColumn(source, err_span.main);
 
{
const msg = zir.nullTerminatedString(item.data.msg);
try eb.addRootErrorMessage(.{
.msg = try eb.addString(msg),
.src_loc = try eb.addSourceLocation(.{
.src_path = try eb.addString(src_path),
.span_start = err_span.start,
.span_main = err_span.main,
.span_end = err_span.end,
.line = @intCast(err_loc.line),
.column = @intCast(err_loc.column),
.source_line = try eb.addString(err_loc.source_line),
}),
.notes_len = item.data.notesLen(zir),
});
}
 
if (item.data.notes != 0) {
const notes_start = try eb.reserveNotes(item.data.notes);
const block = zir.extraData(Zir.Inst.Block, item.data.notes);
const body = zir.extra[block.end..][0..block.data.body_len];
for (notes_start.., body) |note_i, body_elem| {
const note_item = zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
const msg = zir.nullTerminatedString(note_item.data.msg);
const span = blk: {
if (note_item.data.node != 0) {
break :blk tree.nodeToSpan(note_item.data.node);
}
const token_starts = tree.tokens.items(.start);
const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
const end = start + @as(u32, @intCast(tree.tokenSlice(note_item.data.token).len)) - item.data.byte_offset;
break :blk std.zig.Ast.Span{ .start = start, .end = end, .main = start };
};
const loc = std.zig.findLineColumn(source, span.main);
 
eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
.msg = try eb.addString(msg),
.src_loc = try eb.addSourceLocation(.{
.src_path = try eb.addString(src_path),
.span_start = span.start,
.span_main = span.main,
.span_end = span.end,
.line = @intCast(loc.line),
.column = @intCast(loc.column),
.source_line = if (loc.eql(err_loc))
0
else
try eb.addString(loc.source_line),
}),
.notes_len = 0, // TODO rework this function to be recursive
}));
}
}
}
}
 
fn addOtherMessage(wip: *Wip, other: ErrorBundle, msg_index: MessageIndex) !MessageIndex {
const other_msg = other.getErrorMessage(msg_index);
const src_loc = try wip.addOtherSourceLocation(other, other_msg.src_loc);
 
src/Zir.zig added: 1602, removed: 1475, total 127
@@ -19,10 +19,8 @@ const BigIntConst = std.math.big.int.Const;
const BigIntMutable = std.math.big.int.Mutable;
const Ast = std.zig.Ast;
 
const InternPool = @import("InternPool.zig");
const Zir = @This();
const Module = @import("Module.zig");
const LazySrcLoc = Module.LazySrcLoc;
const LazySrcLoc = std.zig.LazySrcLoc;
 
instructions: std.MultiArrayList(Inst).Slice,
/// In order to store references to strings in fewer bytes, we copy all
@@ -2093,9 +2091,11 @@ pub const Inst = struct {
/// ZIR is structured so that the outermost "main" struct of any file
/// is always at index 0.
main_struct_inst = 0,
ref_start_index = InternPool.static_len,
ref_start_index = static_len,
_,
 
pub const static_len = 84;
 
pub fn toRef(i: Index) Inst.Ref {
return @enumFromInt(@intFromEnum(Index.ref_start_index) + @intFromEnum(i));
}
@@ -2109,7 +2109,7 @@ pub const Inst = struct {
/// ZIR is structured so that the outermost "main" struct of any file
/// is always at index 0.
main_struct_inst = 0,
ref_start_index = InternPool.static_len,
ref_start_index = Index.static_len,
none = std.math.maxInt(u32),
_,
 
@@ -2127,97 +2127,98 @@ pub const Inst = struct {
/// The tag type is specified so that it is safe to bitcast between `[]u32`
/// and `[]Ref`.
pub const Ref = enum(u32) {
u0_type = @intFromEnum(InternPool.Index.u0_type),
i0_type = @intFromEnum(InternPool.Index.i0_type),
u1_type = @intFromEnum(InternPool.Index.u1_type),
u8_type = @intFromEnum(InternPool.Index.u8_type),
i8_type = @intFromEnum(InternPool.Index.i8_type),
u16_type = @intFromEnum(InternPool.Index.u16_type),
i16_type = @intFromEnum(InternPool.Index.i16_type),
u29_type = @intFromEnum(InternPool.Index.u29_type),
u32_type = @intFromEnum(InternPool.Index.u32_type),
i32_type = @intFromEnum(InternPool.Index.i32_type),
u64_type = @intFromEnum(InternPool.Index.u64_type),
i64_type = @intFromEnum(InternPool.Index.i64_type),
u80_type = @intFromEnum(InternPool.Index.u80_type),
u128_type = @intFromEnum(InternPool.Index.u128_type),
i128_type = @intFromEnum(InternPool.Index.i128_type),
usize_type = @intFromEnum(InternPool.Index.usize_type),
isize_type = @intFromEnum(InternPool.Index.isize_type),
c_char_type = @intFromEnum(InternPool.Index.c_char_type),
c_short_type = @intFromEnum(InternPool.Index.c_short_type),
c_ushort_type = @intFromEnum(InternPool.Index.c_ushort_type),
c_int_type = @intFromEnum(InternPool.Index.c_int_type),
c_uint_type = @intFromEnum(InternPool.Index.c_uint_type),
c_long_type = @intFromEnum(InternPool.Index.c_long_type),
c_ulong_type = @intFromEnum(InternPool.Index.c_ulong_type),
c_longlong_type = @intFromEnum(InternPool.Index.c_longlong_type),
c_ulonglong_type = @intFromEnum(InternPool.Index.c_ulonglong_type),
c_longdouble_type = @intFromEnum(InternPool.Index.c_longdouble_type),
f16_type = @intFromEnum(InternPool.Index.f16_type),
f32_type = @intFromEnum(InternPool.Index.f32_type),
f64_type = @intFromEnum(InternPool.Index.f64_type),
f80_type = @intFromEnum(InternPool.Index.f80_type),
f128_type = @intFromEnum(InternPool.Index.f128_type),
anyopaque_type = @intFromEnum(InternPool.Index.anyopaque_type),
bool_type = @intFromEnum(InternPool.Index.bool_type),
void_type = @intFromEnum(InternPool.Index.void_type),
type_type = @intFromEnum(InternPool.Index.type_type),
anyerror_type = @intFromEnum(InternPool.Index.anyerror_type),
comptime_int_type = @intFromEnum(InternPool.Index.comptime_int_type),
comptime_float_type = @intFromEnum(InternPool.Index.comptime_float_type),
noreturn_type = @intFromEnum(InternPool.Index.noreturn_type),
anyframe_type = @intFromEnum(InternPool.Index.anyframe_type),
null_type = @intFromEnum(InternPool.Index.null_type),
undefined_type = @intFromEnum(InternPool.Index.undefined_type),
enum_literal_type = @intFromEnum(InternPool.Index.enum_literal_type),
atomic_order_type = @intFromEnum(InternPool.Index.atomic_order_type),
atomic_rmw_op_type = @intFromEnum(InternPool.Index.atomic_rmw_op_type),
calling_convention_type = @intFromEnum(InternPool.Index.calling_convention_type),
address_space_type = @intFromEnum(InternPool.Index.address_space_type),
float_mode_type = @intFromEnum(InternPool.Index.float_mode_type),
reduce_op_type = @intFromEnum(InternPool.Index.reduce_op_type),
call_modifier_type = @intFromEnum(InternPool.Index.call_modifier_type),
prefetch_options_type = @intFromEnum(InternPool.Index.prefetch_options_type),
export_options_type = @intFromEnum(InternPool.Index.export_options_type),
extern_options_type = @intFromEnum(InternPool.Index.extern_options_type),
type_info_type = @intFromEnum(InternPool.Index.type_info_type),
manyptr_u8_type = @intFromEnum(InternPool.Index.manyptr_u8_type),
manyptr_const_u8_type = @intFromEnum(InternPool.Index.manyptr_const_u8_type),
manyptr_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.manyptr_const_u8_sentinel_0_type),
single_const_pointer_to_comptime_int_type = @intFromEnum(InternPool.Index.single_const_pointer_to_comptime_int_type),
slice_const_u8_type = @intFromEnum(InternPool.Index.slice_const_u8_type),
slice_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.slice_const_u8_sentinel_0_type),
optional_noreturn_type = @intFromEnum(InternPool.Index.optional_noreturn_type),
anyerror_void_error_union_type = @intFromEnum(InternPool.Index.anyerror_void_error_union_type),
adhoc_inferred_error_set_type = @intFromEnum(InternPool.Index.adhoc_inferred_error_set_type),
generic_poison_type = @intFromEnum(InternPool.Index.generic_poison_type),
empty_struct_type = @intFromEnum(InternPool.Index.empty_struct_type),
undef = @intFromEnum(InternPool.Index.undef),
zero = @intFromEnum(InternPool.Index.zero),
zero_usize = @intFromEnum(InternPool.Index.zero_usize),
zero_u8 = @intFromEnum(InternPool.Index.zero_u8),
one = @intFromEnum(InternPool.Index.one),
one_usize = @intFromEnum(InternPool.Index.one_usize),
one_u8 = @intFromEnum(InternPool.Index.one_u8),
four_u8 = @intFromEnum(InternPool.Index.four_u8),
negative_one = @intFromEnum(InternPool.Index.negative_one),
calling_convention_c = @intFromEnum(InternPool.Index.calling_convention_c),
calling_convention_inline = @intFromEnum(InternPool.Index.calling_convention_inline),
void_value = @intFromEnum(InternPool.Index.void_value),
unreachable_value = @intFromEnum(InternPool.Index.unreachable_value),
null_value = @intFromEnum(InternPool.Index.null_value),
bool_true = @intFromEnum(InternPool.Index.bool_true),
bool_false = @intFromEnum(InternPool.Index.bool_false),
empty_struct = @intFromEnum(InternPool.Index.empty_struct),
generic_poison = @intFromEnum(InternPool.Index.generic_poison),
u0_type,
i0_type,
u1_type,
u8_type,
i8_type,
u16_type,
i16_type,
u29_type,
u32_type,
i32_type,
u64_type,
i64_type,
u80_type,
u128_type,
i128_type,
usize_type,
isize_type,
c_char_type,
c_short_type,
c_ushort_type,
c_int_type,
c_uint_type,
c_long_type,
c_ulong_type,
c_longlong_type,
c_ulonglong_type,
c_longdouble_type,
f16_type,
f32_type,
f64_type,
f80_type,
f128_type,
anyopaque_type,
bool_type,
void_type,
type_type,
anyerror_type,
comptime_int_type,
comptime_float_type,
noreturn_type,
anyframe_type,
null_type,
undefined_type,
enum_literal_type,
atomic_order_type,
atomic_rmw_op_type,
calling_convention_type,
address_space_type,
float_mode_type,
reduce_op_type,
call_modifier_type,
prefetch_options_type,
export_options_type,
extern_options_type,
type_info_type,
manyptr_u8_type,
manyptr_const_u8_type,
manyptr_const_u8_sentinel_0_type,
single_const_pointer_to_comptime_int_type,
slice_const_u8_type,
slice_const_u8_sentinel_0_type,
optional_noreturn_type,
anyerror_void_error_union_type,
adhoc_inferred_error_set_type,
generic_poison_type,
empty_struct_type,
undef,
zero,
zero_usize,
zero_u8,
one,
one_usize,
one_u8,
four_u8,
negative_one,
calling_convention_c,
calling_convention_inline,
void_value,
unreachable_value,
null_value,
bool_true,
bool_false,
empty_struct,
generic_poison,
 
/// This tag is here to match Air and InternPool, however it is unused
/// for ZIR purposes.
var_args_param_type = @intFromEnum(InternPool.Index.var_args_param_type),
var_args_param_type = std.math.maxInt(u32) - 1,
/// This Ref does not correspond to any ZIR instruction or constant
/// value and may instead be used as a sentinel to indicate null.
none = @intFromEnum(InternPool.Index.none),
none = std.math.maxInt(u32),
 
_,
 
pub fn toIndex(inst: Ref) ?Index {
 
ev/null added: 1602, removed: 1475, total 127
@@ -1,110 +0,0 @@
const std = @import("std");
const mem = std.mem;
 
/// Print the string as a Zig identifier escaping it with @"" syntax if needed.
fn formatId(
bytes: []const u8,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = fmt;
if (isValidId(bytes)) {
return writer.writeAll(bytes);
}
try writer.writeAll("@\"");
try stringEscape(bytes, "", options, writer);
try writer.writeByte('"');
}
 
/// Return a Formatter for a Zig identifier
pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
return .{ .data = bytes };
}
 
pub fn isValidId(bytes: []const u8) bool {
if (bytes.len == 0) return false;
if (mem.eql(u8, bytes, "_")) return false;
for (bytes, 0..) |c, i| {
switch (c) {
'_', 'a'...'z', 'A'...'Z' => {},
'0'...'9' => if (i == 0) return false,
else => return false,
}
}
return std.zig.Token.getKeyword(bytes) == null;
}
 
test "isValidId" {
try std.testing.expect(!isValidId(""));
try std.testing.expect(isValidId("foobar"));
try std.testing.expect(!isValidId("a b c"));
try std.testing.expect(!isValidId("3d"));
try std.testing.expect(!isValidId("enum"));
try std.testing.expect(isValidId("i386"));
}
 
/// Print the string as escaped contents of a double quoted or single-quoted string.
/// Format `{}` treats contents as a double-quoted string.
/// Format `{'}` treats contents as a single-quoted string.
pub fn stringEscape(
bytes: []const u8,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = options;
for (bytes) |byte| switch (byte) {
'\n' => try writer.writeAll("\\n"),
'\r' => try writer.writeAll("\\r"),
'\t' => try writer.writeAll("\\t"),
'\\' => try writer.writeAll("\\\\"),
'"' => {
if (fmt.len == 1 and fmt[0] == '\'') {
try writer.writeByte('"');
} else if (fmt.len == 0) {
try writer.writeAll("\\\"");
} else {
@compileError("expected {} or {'}, found {" ++ fmt ++ "}");
}
},
'\'' => {
if (fmt.len == 1 and fmt[0] == '\'') {
try writer.writeAll("\\'");
} else if (fmt.len == 0) {
try writer.writeByte('\'');
} else {
@compileError("expected {} or {'}, found {" ++ fmt ++ "}");
}
},
' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
// Use hex escapes for rest any unprintable characters.
else => {
try writer.writeAll("\\x");
try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
},
};
}
 
/// Return a Formatter for Zig Escapes of a double quoted string.
/// The format specifier must be one of:
/// * `{}` treats contents as a double-quoted string.
/// * `{'}` treats contents as a single-quoted string.
pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) {
return .{ .data = bytes };
}
 
test "escape invalid identifiers" {
const expectFmt = std.testing.expectFmt;
try expectFmt("@\"while\"", "{}", .{fmtId("while")});
try expectFmt("hello", "{}", .{fmtId("hello")});
try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")});
try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
try expectFmt(
\\" \\ hi \x07 \x11 " derp \'"
, "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
try expectFmt(
\\" \\ hi \x07 \x11 \" derp '"
, "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
}
 
src/Autodoc.zig added: 1602, removed: 1475, total 127
@@ -9,7 +9,7 @@ const File = Zcu.File;
const Module = @import("Package.zig").Module;
const Tokenizer = std.zig.Tokenizer;
const InternPool = @import("InternPool.zig");
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const Ref = Zir.Inst.Ref;
const log = std.log.scoped(.autodoc);
const renderer = @import("autodoc/render_source.zig");
 
src/Builtin.zig added: 1602, removed: 1475, total 127
@@ -296,7 +296,7 @@ const Allocator = std.mem.Allocator;
const build_options = @import("build_options");
const Module = @import("Package/Module.zig");
const assert = std.debug.assert;
const AstGen = @import("AstGen.zig");
const AstGen = std.zig.AstGen;
const File = @import("Module.zig").File;
const Compilation = @import("Compilation.zig");
const log = std.log.scoped(.builtin);
 
src/Compilation.zig added: 1602, removed: 1475, total 127
@@ -35,7 +35,7 @@ const InternPool = @import("InternPool.zig");
const Cache = std.Build.Cache;
const c_codegen = @import("codegen/c.zig");
const libtsan = @import("libtsan.zig");
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const Autodoc = @import("Autodoc.zig");
const resinator = @import("resinator.zig");
const Builtin = @import("Builtin.zig");
@@ -3322,85 +3322,10 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
assert(file.zir_loaded);
assert(file.tree_loaded);
assert(file.source_loaded);
const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
assert(payload_index != 0);
const gpa = eb.gpa;
 
const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
const items_len = header.data.items_len;
var extra_index = header.end;
for (0..items_len) |_| {
const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
extra_index = item.end;
const err_span = blk: {
if (item.data.node != 0) {
break :blk Module.SrcLoc.nodeToSpan(&file.tree, item.data.node);
}
const token_starts = file.tree.tokens.items(.start);
const start = token_starts[item.data.token] + item.data.byte_offset;
const end = start + @as(u32, @intCast(file.tree.tokenSlice(item.data.token).len)) - item.data.byte_offset;
break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
};
const err_loc = std.zig.findLineColumn(file.source, err_span.main);
 
{
const msg = file.zir.nullTerminatedString(item.data.msg);
const src_path = try file.fullPath(gpa);
defer gpa.free(src_path);
try eb.addRootErrorMessage(.{
.msg = try eb.addString(msg),
.src_loc = try eb.addSourceLocation(.{
.src_path = try eb.addString(src_path),
.span_start = err_span.start,
.span_main = err_span.main,
.span_end = err_span.end,
.line = @as(u32, @intCast(err_loc.line)),
.column = @as(u32, @intCast(err_loc.column)),
.source_line = try eb.addString(err_loc.source_line),
}),
.notes_len = item.data.notesLen(file.zir),
});
}
 
if (item.data.notes != 0) {
const notes_start = try eb.reserveNotes(item.data.notes);
const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
const body = file.zir.extra[block.end..][0..block.data.body_len];
for (notes_start.., body) |note_i, body_elem| {
const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
const msg = file.zir.nullTerminatedString(note_item.data.msg);
const span = blk: {
if (note_item.data.node != 0) {
break :blk Module.SrcLoc.nodeToSpan(&file.tree, note_item.data.node);
}
const token_starts = file.tree.tokens.items(.start);
const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
const end = start + @as(u32, @intCast(file.tree.tokenSlice(note_item.data.token).len)) - item.data.byte_offset;
break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
};
const loc = std.zig.findLineColumn(file.source, span.main);
const src_path = try file.fullPath(gpa);
defer gpa.free(src_path);
 
eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
.msg = try eb.addString(msg),
.src_loc = try eb.addSourceLocation(.{
.src_path = try eb.addString(src_path),
.span_start = span.start,
.span_main = span.main,
.span_end = span.end,
.line = @as(u32, @intCast(loc.line)),
.column = @as(u32, @intCast(loc.column)),
.source_line = if (loc.eql(err_loc))
0
else
try eb.addString(loc.source_line),
}),
.notes_len = 0, // TODO rework this function to be recursive
}));
}
}
}
const src_path = try file.fullPath(gpa);
defer gpa.free(src_path);
return eb.addZirErrorMessages(file.zir, file.tree, file.source, src_path);
}
 
pub fn performAllTheWork(
 
src/InternPool.zig added: 1602, removed: 1475, total 127
@@ -338,7 +338,7 @@ const Hash = std.hash.Wyhash;
const InternPool = @This();
const Module = @import("Module.zig");
const Zcu = Module;
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
 
const KeyAdapter = struct {
intern_pool: *const InternPool,
@@ -383,27 +383,8 @@ pub const RuntimeIndex = enum(u32) {
}
};
 
pub const DeclIndex = enum(u32) {
_,
 
pub fn toOptional(i: DeclIndex) OptionalDeclIndex {
return @enumFromInt(@intFromEnum(i));
}
};
 
pub const OptionalDeclIndex = enum(u32) {
none = std.math.maxInt(u32),
_,
 
pub fn init(oi: ?DeclIndex) OptionalDeclIndex {
return @enumFromInt(@intFromEnum(oi orelse return .none));
}
 
pub fn unwrap(oi: OptionalDeclIndex) ?DeclIndex {
if (oi == .none) return null;
return @enumFromInt(@intFromEnum(oi));
}
};
pub const DeclIndex = std.zig.DeclIndex;
pub const OptionalDeclIndex = std.zig.OptionalDeclIndex;
 
pub const NamespaceIndex = enum(u32) {
_,
@@ -2877,7 +2858,7 @@ pub const static_keys = [_]Key{
/// This is specified with an integer literal and a corresponding comptime
/// assert below to break an unfortunate and arguably incorrect dependency loop
/// when compiling.
pub const static_len = 84;
pub const static_len = Zir.Inst.Index.static_len;
comptime {
//@compileLog(static_keys.len);
assert(static_len == static_keys.len);
 
src/Module.zig added: 1602, removed: 1475, total 127
@@ -13,6 +13,7 @@ const BigIntConst = std.math.big.int.Const;
const BigIntMutable = std.math.big.int.Mutable;
const Target = std.Target;
const Ast = std.zig.Ast;
const LazySrcLoc = std.zig.LazySrcLoc;
 
/// Deprecated, use `Zcu`.
const Module = Zcu;
@@ -25,9 +26,9 @@ const TypedValue = @import("TypedValue.zig");
const Package = @import("Package.zig");
const link = @import("link.zig");
const Air = @import("Air.zig");
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const trace = @import("tracy.zig").trace;
const AstGen = @import("AstGen.zig");
const AstGen = std.zig.AstGen;
const Sema = @import("Sema.zig");
const target_util = @import("target.zig");
const build_options = @import("build_options");
@@ -664,6 +665,101 @@ pub const Decl = struct {
if (decl.alignment != .none) return decl.alignment;
return decl.ty.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,
},
};
}
};
 
/// This state is attached to every Decl when Module emit_h is non-null.
@@ -1159,11 +1255,7 @@ pub const SrcLoc = struct {
return @bitCast(offset + @as(i32, @bitCast(src_loc.parent_decl_node)));
}
 
pub const Span = struct {
start: u32,
end: u32,
main: u32,
};
pub const Span = Ast.Span;
 
pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {
switch (src_loc.lazy) {
@@ -1180,7 +1272,7 @@ pub const SrcLoc = struct {
},
.node_abs => |node| {
const tree = try src_loc.file_scope.getTree(gpa);
return nodeToSpan(tree, node);
return tree.nodeToSpan(node);
},
.byte_offset => |byte_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1201,25 +1293,24 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.declRelativeToNodeIndex(node_off);
assert(src_loc.file_scope.tree_loaded);
return nodeToSpan(tree, node);
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 main_token = tree.nodes.items(.main_token)[node];
return tokensToSpan(tree, main_token, main_token, main_token);
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);
assert(src_loc.file_scope.tree_loaded);
return nodeToSpan(tree, node);
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);
return tokensToSpan(
tree,
return tree.tokensToSpan(
tree.firstToken(node) - 3,
tree.lastToken(node),
tree.nodes.items(.main_token)[node] - 2,
@@ -1237,12 +1328,12 @@ pub const SrcLoc = struct {
=> tree.fullVarDecl(node).?,
.@"usingnamespace" => {
const node_data = tree.nodes.items(.data);
return nodeToSpan(tree, node_data[node].lhs);
return tree.nodeToSpan(node_data[node].lhs);
},
else => unreachable,
};
if (full.ast.type_node != 0) {
return nodeToSpan(tree, full.ast.type_node);
return tree.nodeToSpan(full.ast.type_node);
}
const tok_index = full.ast.mut_token + 1; // the name token
const start = tree.tokens.items(.start)[tok_index];
@@ -1253,25 +1344,25 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.declRelativeToNodeIndex(node_off);
const full = tree.fullVarDecl(node).?;
return nodeToSpan(tree, full.ast.align_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 full = tree.fullVarDecl(node).?;
return nodeToSpan(tree, full.ast.section_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 full = tree.fullVarDecl(node).?;
return nodeToSpan(tree, full.ast.addrspace_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 full = tree.fullVarDecl(node).?;
return nodeToSpan(tree, full.ast.init_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),
@@ -1312,13 +1403,13 @@ pub const SrcLoc = struct {
node = node_datas[node].lhs;
}
 
return nodeToSpan(tree, node);
return tree.nodeToSpan(node);
},
.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);
return nodeToSpan(tree, node_datas[node].rhs);
return tree.nodeToSpan(node_datas[node].rhs);
},
.node_offset_slice_ptr,
.node_offset_slice_start,
@@ -1335,14 +1426,14 @@ pub const SrcLoc = struct {
.node_offset_slice_sentinel => full.ast.sentinel,
else => unreachable,
};
return nodeToSpan(tree, part_node);
return tree.nodeToSpan(part_node);
},
.node_offset_call_func => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.declRelativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullCall(&buf, node).?;
return nodeToSpan(tree, full.ast.fn_expr);
return tree.nodeToSpan(full.ast.fn_expr);
},
.node_offset_field_name => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1381,13 +1472,13 @@ 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);
return nodeToSpan(tree, node);
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 full = tree.fullAsm(node).?;
return nodeToSpan(tree, full.ast.template);
return tree.nodeToSpan(full.ast.template);
},
.node_offset_asm_ret_ty => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1395,7 +1486,7 @@ pub const SrcLoc = struct {
const full = tree.fullAsm(node).?;
const asm_output = full.outputs[0];
const node_datas = tree.nodes.items(.data);
return nodeToSpan(tree, node_datas[asm_output].lhs);
return tree.nodeToSpan(node_datas[asm_output].lhs);
},
 
.node_offset_if_cond => |node_off| {
@@ -1418,21 +1509,21 @@ pub const SrcLoc = struct {
const inputs = tree.fullFor(node).?.ast.inputs;
const start = tree.firstToken(inputs[0]);
const end = tree.lastToken(inputs[inputs.len - 1]);
return tokensToSpan(tree, start, end, start);
return tree.tokensToSpan(start, end, start);
},
 
.@"orelse" => node,
.@"catch" => node,
else => unreachable,
};
return nodeToSpan(tree, src_node);
return tree.nodeToSpan(src_node);
},
.for_input => |for_input| {
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset);
const for_full = tree.fullFor(node).?;
const src_node = for_full.ast.inputs[for_input.input_index];
return nodeToSpan(tree, src_node);
return tree.nodeToSpan(src_node);
},
.for_capture_from_input => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1458,12 +1549,12 @@ pub const SrcLoc = struct {
},
.identifier => {
if (count == 0)
return tokensToSpan(tree, tok, tok + 1, tok);
return tree.tokensToSpan(tok, tok + 1, tok);
tok += 1;
},
.asterisk => {
if (count == 0)
return tokensToSpan(tree, tok, tok + 2, tok);
return tree.tokensToSpan(tok, tok + 2, tok);
tok += 1;
},
else => unreachable,
@@ -1495,7 +1586,7 @@ pub const SrcLoc = struct {
.array_init_comma,
=> {
const full = tree.fullArrayInit(&buf, call_args_node).?.ast.elements;
return nodeToSpan(tree, full[call_arg.arg_index]);
return tree.nodeToSpan(full[call_arg.arg_index]);
},
.struct_init_one,
.struct_init_one_comma,
@@ -1507,12 +1598,12 @@ pub const SrcLoc = struct {
.struct_init_comma,
=> {
const full = tree.fullStructInit(&buf, call_args_node).?.ast.fields;
return nodeToSpan(tree, full[call_arg.arg_index]);
return tree.nodeToSpan(full[call_arg.arg_index]);
},
else => return nodeToSpan(tree, call_args_node),
else => return tree.nodeToSpan(call_args_node),
}
};
return nodeToSpan(tree, call_full.ast.params[call_arg.arg_index]);
return tree.nodeToSpan(call_full.ast.params[call_arg.arg_index]);
},
.fn_proto_param => |fn_proto_param| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1523,12 +1614,11 @@ pub const SrcLoc = struct {
var i: usize = 0;
while (it.next()) |param| : (i += 1) {
if (i == fn_proto_param.param_index) {
if (param.anytype_ellipsis3) |token| return tokenToSpan(tree, token);
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 tokensToSpan(
tree,
return tree.tokensToSpan(
first_token,
tree.lastToken(param.type_expr),
first_token,
@@ -1541,13 +1631,13 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.declRelativeToNodeIndex(node_off);
const node_datas = tree.nodes.items(.data);
return nodeToSpan(tree, node_datas[node].lhs);
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_datas = tree.nodes.items(.data);
return nodeToSpan(tree, node_datas[node].rhs);
return tree.nodeToSpan(node_datas[node].rhs);
},
.array_cat_lhs, .array_cat_rhs => |cat| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1571,9 +1661,9 @@ pub const SrcLoc = struct {
.array_init_comma,
=> {
const full = tree.fullArrayInit(&buf, arr_node).?.ast.elements;
return nodeToSpan(tree, full[cat.elem_index]);
return tree.nodeToSpan(full[cat.elem_index]);
},
else => return nodeToSpan(tree, arr_node),
else => return tree.nodeToSpan(arr_node),
}
},
 
@@ -1581,7 +1671,7 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.declRelativeToNodeIndex(node_off);
const node_datas = tree.nodes.items(.data);
return nodeToSpan(tree, node_datas[node].lhs);
return tree.nodeToSpan(node_datas[node].lhs);
},
 
.node_offset_switch_special_prong => |node_off| {
@@ -1600,7 +1690,7 @@ pub const SrcLoc = struct {
mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"));
if (!is_special) continue;
 
return nodeToSpan(tree, case_node);
return tree.nodeToSpan(case_node);
} else unreachable;
},
 
@@ -1622,7 +1712,7 @@ pub const SrcLoc = struct {
 
for (case.ast.values) |item_node| {
if (node_tags[item_node] == .switch_range) {
return nodeToSpan(tree, item_node);
return tree.nodeToSpan(item_node);
}
}
} else unreachable;
@@ -1658,28 +1748,28 @@ pub const SrcLoc = struct {
const node = src_loc.declRelativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return nodeToSpan(tree, full.ast.align_expr);
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);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return nodeToSpan(tree, full.ast.addrspace_expr);
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);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return nodeToSpan(tree, full.ast.section_expr);
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);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return nodeToSpan(tree, full.ast.callconv_expr);
return tree.nodeToSpan(full.ast.callconv_expr);
},
 
.node_offset_fn_type_ret_ty => |node_off| {
@@ -1687,7 +1777,7 @@ pub const SrcLoc = struct {
const node = src_loc.declRelativeToNodeIndex(node_off);
var buf: [1]Ast.Node.Index = undefined;
const full = tree.fullFnProto(&buf, node).?;
return nodeToSpan(tree, full.ast.return_type);
return tree.nodeToSpan(full.ast.return_type);
},
.node_offset_param => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1699,8 +1789,7 @@ pub const SrcLoc = struct {
.colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
else => break,
};
return tokensToSpan(
tree,
return tree.tokensToSpan(
first_tok,
tree.lastToken(node),
first_tok,
@@ -1717,8 +1806,7 @@ pub const SrcLoc = struct {
.colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1,
else => break,
};
return tokensToSpan(
tree,
return tree.tokensToSpan(
first_tok,
tok_index,
first_tok,
@@ -1729,7 +1817,7 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node_datas = tree.nodes.items(.data);
const parent_node = src_loc.declRelativeToNodeIndex(node_off);
return nodeToSpan(tree, node_datas[parent_node].rhs);
return tree.nodeToSpan(node_datas[parent_node].rhs);
},
 
.node_offset_lib_name => |node_off| {
@@ -1748,70 +1836,70 @@ pub const SrcLoc = struct {
const parent_node = src_loc.declRelativeToNodeIndex(node_off);
 
const full = tree.fullArrayType(parent_node).?;
return nodeToSpan(tree, full.ast.elem_count);
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 full = tree.fullArrayType(parent_node).?;
return nodeToSpan(tree, full.ast.sentinel);
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 full = tree.fullArrayType(parent_node).?;
return nodeToSpan(tree, full.ast.elem_type);
return tree.nodeToSpan(full.ast.elem_type);
},
.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);
 
return nodeToSpan(tree, node_datas[node].lhs);
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 full = tree.fullPtrType(parent_node).?;
return nodeToSpan(tree, full.ast.child_type);
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 full = tree.fullPtrType(parent_node).?;
return nodeToSpan(tree, full.ast.sentinel);
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 full = tree.fullPtrType(parent_node).?;
return nodeToSpan(tree, full.ast.align_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 full = tree.fullPtrType(parent_node).?;
return nodeToSpan(tree, full.ast.addrspace_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 full = tree.fullPtrType(parent_node).?;
return nodeToSpan(tree, full.ast.bit_range_start);
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 full = tree.fullPtrType(parent_node).?;
return nodeToSpan(tree, full.ast.bit_range_end);
return tree.nodeToSpan(full.ast.bit_range_end);
},
.node_offset_container_tag => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1821,13 +1909,12 @@ pub const SrcLoc = struct {
switch (node_tags[parent_node]) {
.container_decl_arg, .container_decl_arg_trailing => {
const full = tree.containerDeclArg(parent_node);
return nodeToSpan(tree, full.ast.arg);
return tree.nodeToSpan(full.ast.arg);
},
.tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {
const full = tree.taggedUnionEnumTag(parent_node);
 
return tokensToSpan(
tree,
return tree.tokensToSpan(
tree.firstToken(full.ast.arg) - 2,
tree.lastToken(full.ast.arg) + 1,
tree.nodes.items(.main_token)[full.ast.arg],
@@ -1846,7 +1933,7 @@ pub const SrcLoc = struct {
.container_field_init => tree.containerFieldInit(parent_node),
else => unreachable,
};
return nodeToSpan(tree, full.ast.value_expr);
return tree.nodeToSpan(full.ast.value_expr);
},
.node_offset_init_ty => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1854,7 +1941,7 @@ pub const SrcLoc = struct {
 
var buf: [2]Ast.Node.Index = undefined;
const full = tree.fullArrayInit(&buf, parent_node).?;
return nodeToSpan(tree, full.ast.type_expr);
return tree.nodeToSpan(full.ast.type_expr);
},
.node_offset_store_ptr => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
@@ -1864,9 +1951,9 @@ pub const SrcLoc = struct {
 
switch (node_tags[node]) {
.assign => {
return nodeToSpan(tree, node_datas[node].lhs);
return tree.nodeToSpan(node_datas[node].lhs);
},
else => return nodeToSpan(tree, node),
else => return tree.nodeToSpan(node),
}
},
.node_offset_store_operand => |node_off| {
@@ -1877,9 +1964,9 @@ pub const SrcLoc = struct {
 
switch (node_tags[node]) {
.assign => {
return nodeToSpan(tree, node_datas[node].rhs);
return tree.nodeToSpan(node_datas[node].rhs);
},
else => return nodeToSpan(tree, node),
else => return tree.nodeToSpan(node),
}
},
.node_offset_return_operand => |node_off| {
@@ -1888,9 +1975,9 @@ pub const SrcLoc = struct {
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) {
return nodeToSpan(tree, node_datas[node].lhs);
return tree.nodeToSpan(node_datas[node].lhs);
}
return nodeToSpan(tree, node);
return tree.nodeToSpan(node);
},
}
}
@@ -1914,486 +2001,7 @@ pub const SrcLoc = struct {
.builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index],
else => unreachable,
};
return nodeToSpan(tree, param);
}
 
pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
return tokensToSpan(
tree,
tree.firstToken(node),
tree.lastToken(node),
tree.nodes.items(.main_token)[node],
);
}
 
fn tokenToSpan(tree: *const Ast, token: Ast.TokenIndex) Span {
return tokensToSpan(tree, token, token, token);
}
 
fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span {
const token_starts = tree.tokens.items(.start);
var start_tok = start;
var end_tok = end;
 
if (tree.tokensOnSameLine(start, end)) {
// do nothing
} else if (tree.tokensOnSameLine(start, main)) {
end_tok = main;
} else if (tree.tokensOnSameLine(main, end)) {
start_tok = main;
} else {
start_tok = main;
end_tok = main;
}
const start_off = token_starts[start_tok];
const end_off = token_starts[end_tok] + @as(u32, @intCast(tree.tokenSlice(end_tok).len));
return Span{ .start = start_off, .end = end_off, .main = token_starts[main] };
}
};
 
/// This wraps a simple integer in debug builds so that later on we can find out
/// where in semantic analysis the value got set.
const TracedOffset = struct {
x: i32,
trace: std.debug.Trace = .{},
 
const want_tracing = build_options.value_tracing;
};
 
/// 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 nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
 
noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
result.node_offset.trace.addAddr(@returnAddress(), "init");
return result;
}
 
fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
return .{ .node_offset = .{ .x = node_offset } };
}
 
/// Upgrade to a `SrcLoc` based on the `Decl` provided.
pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl, 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,
},
};
return tree.nodeToSpan(param);
}
};
 
 
src/Package.zig added: 1602, removed: 1475, total 127
@@ -126,7 +126,7 @@ pub const Path = struct {
) !void {
if (fmt_string.len == 1) {
// Quote-escape the string.
const stringEscape = std.zig.fmt.stringEscape;
const stringEscape = std.zig.stringEscape;
const f = switch (fmt_string[0]) {
'q' => "",
'\'' => '\'',
 
src/Package/Fetch.zig added: 1602, removed: 1475, total 127
@@ -592,7 +592,7 @@ fn loadManifest(f: *Fetch, pkg_root: Package.Path) RunError!void {
 
if (ast.errors.len > 0) {
const file_path = try std.fmt.allocPrint(arena, "{}" ++ Manifest.basename, .{pkg_root});
try main.putAstErrorsIntoBundle(arena, ast.*, file_path, eb);
try std.zig.putAstErrorsIntoBundle(arena, ast.*, file_path, eb);
return error.FetchFailed;
}
 
@@ -1690,7 +1690,6 @@ const Cache = std.Build.Cache;
const ThreadPool = std.Thread.Pool;
const WaitGroup = std.Thread.WaitGroup;
const Fetch = @This();
const main = @import("../main.zig");
const git = @import("Fetch/git.zig");
const Package = @import("../Package.zig");
const Manifest = Package.Manifest;
 
src/Sema.zig added: 1602, removed: 1475, total 127
@@ -148,7 +148,7 @@ const Value = @import("Value.zig");
const Type = @import("type.zig").Type;
const TypedValue = @import("TypedValue.zig");
const Air = @import("Air.zig");
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const Module = @import("Module.zig");
const trace = @import("tracy.zig").trace;
const Namespace = Module.Namespace;
@@ -156,7 +156,7 @@ const CompileError = Module.CompileError;
const SemaError = Module.SemaError;
const Decl = Module.Decl;
const CaptureScope = Module.CaptureScope;
const LazySrcLoc = Module.LazySrcLoc;
const LazySrcLoc = std.zig.LazySrcLoc;
const RangeSet = @import("RangeSet.zig");
const target_util = @import("target.zig");
const Package = @import("Package.zig");
@@ -397,7 +397,7 @@ pub const Block = struct {
break :blk src_loc;
} else blk: {
const src_decl = mod.declPtr(rt.block.src_decl);
break :blk rt.func_src.toSrcLoc(src_decl, mod);
break :blk src_decl.toSrcLoc(rt.func_src, mod);
};
if (rt.return_ty.isGenericPoison()) {
return mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{});
@@ -2421,7 +2421,7 @@ fn errNote(
) error{OutOfMemory}!void {
const mod = sema.mod;
const src_decl = mod.declPtr(block.src_decl);
return mod.errNoteNonLazy(src.toSrcLoc(src_decl, mod), parent, format, args);
return mod.errNoteNonLazy(src_decl.toSrcLoc(src, mod), parent, format, args);
}
 
fn addFieldErrNote(
@@ -2478,7 +2478,7 @@ fn errMsg(
const mod = sema.mod;
if (src == .unneeded) return error.NeededSourceLocation;
const src_decl = mod.declPtr(block.src_decl);
return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl, mod), format, args);
return Module.ErrorMsg.create(sema.gpa, src_decl.toSrcLoc(src, mod), format, args);
}
 
pub fn fail(
@@ -2556,7 +2556,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg)
const decl = mod.declPtr(ref.referencer);
try reference_stack.append(.{
.decl = decl.name,
.src_loc = ref.src.toSrcLoc(decl, mod),
.src_loc = decl.toSrcLoc(ref.src, mod),
});
}
referenced_by = ref.referencer;
@@ -2599,7 +2599,7 @@ fn reparentOwnedErrorMsg(
) !void {
const mod = sema.mod;
const src_decl = mod.declPtr(block.src_decl);
const resolved_src = src.toSrcLoc(src_decl, mod);
const resolved_src = src_decl.toSrcLoc(src, mod);
const msg_str = try std.fmt.allocPrint(mod.gpa, format, args);
 
const orig_notes = msg.notes.len;
@@ -5252,7 +5252,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
errdefer msg.destroy(sema.gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty);
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(src, mod), elem_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
@@ -5716,7 +5716,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
var child_block = parent_block.makeSubBlock();
child_block.label = &label;
child_block.runtime_cond = null;
child_block.runtime_loop = src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
child_block.runtime_loop = mod.declPtr(child_block.src_decl).toSrcLoc(src, mod);
child_block.runtime_index.increment();
const merges = &child_block.label.?.merges;
 
@@ -6058,7 +6058,7 @@ fn analyzeBlockBody(
try mod.errNoteNonLazy(runtime_src, msg, "runtime control flow here", .{});
 
const child_src_decl = mod.declPtr(child_block.src_decl);
try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl, mod), resolved_ty);
try sema.explainWhyTypeIsComptime(msg, child_src_decl.toSrcLoc(type_src, mod), resolved_ty);
 
break :msg msg;
};
@@ -6213,7 +6213,7 @@ pub fn analyzeExport(
errdefer msg.destroy(gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), exported_decl.ty, .other);
 
try sema.addDeclaredHereNote(msg, exported_decl.ty);
break :msg msg;
@@ -8082,7 +8082,7 @@ fn instantiateGenericCall(
};
try child_sema.errNote(&child_block, param_src, msg, "declared here", .{});
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(msg, arg_src.toSrcLoc(src_decl, mod), arg_ty);
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(arg_src, mod), arg_ty);
break :msg msg;
}),
 
@@ -9387,7 +9387,7 @@ fn funcCommon(
errdefer msg.destroy(sema.gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param_ty, .param_ty);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(param_src, mod), param_ty, .param_ty);
 
try sema.addDeclaredHereNote(msg, param_ty);
break :msg msg;
@@ -9402,7 +9402,7 @@ fn funcCommon(
errdefer msg.destroy(sema.gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param_ty);
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(param_src, mod), param_ty);
 
try sema.addDeclaredHereNote(msg, param_ty);
break :msg msg;
@@ -9671,7 +9671,7 @@ fn finishFunc(
errdefer msg.destroy(gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ret_ty_src, mod), return_type, .ret_ty);
 
try sema.addDeclaredHereNote(msg, return_type);
break :msg msg;
@@ -9692,7 +9692,7 @@ fn finishFunc(
"function with comptime-only return type '{}' requires all parameters to be comptime",
.{return_type.fmt(mod)},
);
try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl, mod), return_type);
try sema.explainWhyTypeIsComptime(msg, sema.owner_decl.toSrcLoc(ret_ty_src, mod), return_type);
 
const tags = sema.code.instructions.items(.tag);
const data = sema.code.instructions.items(.data);
@@ -9965,7 +9965,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const msg = try sema.errMsg(block, ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(msg, ptr_src.toSrcLoc(src_decl, mod), pointee_ty);
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(ptr_src, mod), pointee_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
@@ -11492,7 +11492,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
 
var sub_block = child_block.makeSubBlock();
sub_block.runtime_loop = null;
sub_block.runtime_cond = main_operand_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
sub_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(main_operand_src, mod);
sub_block.runtime_index.increment();
defer sub_block.instructions.deinit(gpa);
 
@@ -12227,7 +12227,7 @@ fn analyzeSwitchRuntimeBlock(
 
var case_block = child_block.makeSubBlock();
case_block.runtime_loop = null;
case_block.runtime_cond = operand_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
case_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(operand_src, mod);
case_block.runtime_index.increment();
defer case_block.instructions.deinit(gpa);
 
@@ -13663,7 +13663,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
return sema.fail(block, operand_src, "file path name cannot be empty", .{});
}
 
const src_loc = operand_src.toSrcLoc(mod.declPtr(block.src_decl), mod);
const src_loc = mod.declPtr(block.src_decl).toSrcLoc(operand_src, mod);
const val = mod.embedFile(block.getFileScope(mod), name, src_loc) catch |err| switch (err) {
error.ImportOutsideModulePath => {
return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name});
@@ -18766,7 +18766,7 @@ fn zirBoolBr(
 
var child_block = parent_block.makeSubBlock();
child_block.runtime_loop = null;
child_block.runtime_cond = lhs_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
child_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(lhs_src, mod);
child_block.runtime_index.increment();
defer child_block.instructions.deinit(gpa);
 
@@ -18963,7 +18963,7 @@ fn zirCondbr(
// instructions array in between using it for the then block and else block.
var sub_block = parent_block.makeSubBlock();
sub_block.runtime_loop = null;
sub_block.runtime_cond = cond_src.toSrcLoc(mod.declPtr(parent_block.src_decl), mod);
sub_block.runtime_cond = mod.declPtr(parent_block.src_decl).toSrcLoc(cond_src, mod);
sub_block.runtime_index.increment();
defer sub_block.instructions.deinit(gpa);
 
@@ -19503,7 +19503,7 @@ fn analyzeRet(
 
if (sema.fn_ret_ty.isError(mod) and ret_val.getErrorName(mod) != .none) {
const src_decl = mod.declPtr(block.src_decl);
const src_loc = src.toSrcLoc(src_decl, mod);
const src_loc = src_decl.toSrcLoc(src, mod);
try sema.comptime_err_ret_trace.append(src_loc);
}
return error.ComptimeReturn;
@@ -19660,7 +19660,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
errdefer msg.destroy(sema.gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(elem_ty_src, mod), elem_ty, .other);
 
try sema.addDeclaredHereNote(msg, elem_ty);
break :msg msg;
@@ -21128,7 +21128,7 @@ fn zirReify(
errdefer msg.destroy(gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), elem_ty, .other);
 
try sema.addDeclaredHereNote(msg, elem_ty);
break :msg msg;
@@ -21572,7 +21572,7 @@ fn zirReify(
errdefer msg.destroy(gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
 
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -21584,7 +21584,7 @@ fn zirReify(
errdefer msg.destroy(gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
 
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -21939,7 +21939,7 @@ fn reifyStruct(
errdefer msg.destroy(gpa);
 
const src_decl = sema.mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .struct_field);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .struct_field);
 
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -21951,7 +21951,7 @@ fn reifyStruct(
errdefer msg.destroy(gpa);
 
const src_decl = sema.mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
 
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -22018,7 +22018,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
errdefer msg.destroy(sema.gpa);
 
const src_decl = sema.mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), arg_ty, .param_ty);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ty_src, mod), arg_ty, .param_ty);
 
try sema.addDeclaredHereNote(msg, arg_ty);
break :msg msg;
@@ -25859,7 +25859,7 @@ fn zirBuiltinExtern(
const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), ty, .other);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ty_src, mod), ty, .other);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
@@ -26003,7 +26003,7 @@ fn validateVarType(
const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), var_ty, .other);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
@@ -26026,7 +26026,7 @@ fn validateVarType(
errdefer msg.destroy(sema.gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty);
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(src, mod), var_ty);
if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) {
try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{});
}
@@ -28093,7 +28093,7 @@ fn validateRuntimeElemAccess(
errdefer msg.destroy(sema.gpa);
 
const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty);
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(parent_src, mod), parent_ty);
 
break :msg msg;
};
@@ -28492,7 +28492,7 @@ const CoerceOpts = struct {
.lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param),
};
}
return param_src.toSrcLoc(fn_decl, mod);
return fn_decl.toSrcLoc(param_src, mod);
}
} = .{},
};
@@ -29110,7 +29110,7 @@ fn coerceExtra(
 
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{});
try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "'noreturn' declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
@@ -29145,9 +29145,9 @@ fn coerceExtra(
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
if (inst_ty.isError(mod) and !dest_ty.isError(mod)) {
try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{});
try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function cannot return an error", .{});
} else {
try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function return type declared here", .{});
try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function return type declared here", .{});
}
}
 
@@ -30165,7 +30165,7 @@ fn coerceVarArgParam(
errdefer msg.destroy(sema.gpa);
 
const src_decl = sema.mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl, mod), coerced_ty, .param_ty);
try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(inst_src, mod), coerced_ty, .param_ty);
 
try sema.addDeclaredHereNote(msg, coerced_ty);
break :msg msg;
@@ -37180,7 +37180,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
});
errdefer msg.destroy(sema.gpa);
const decl_ptr = mod.declPtr(tag_info.decl);
try mod.errNoteNonLazy(enum_field_src.toSrcLoc(decl_ptr, mod), msg, "enum field here", .{});
try mod.errNoteNonLazy(decl_ptr.toSrcLoc(enum_field_src, mod), msg, "enum field here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(&block_scope, msg);
 
src/arch/wasm/CodeGen.zig added: 1602, removed: 1475, total 127
@@ -16,7 +16,7 @@ const Decl = Module.Decl;
const Type = @import("../../type.zig").Type;
const Value = @import("../../Value.zig");
const Compilation = @import("../../Compilation.zig");
const LazySrcLoc = Module.LazySrcLoc;
const LazySrcLoc = std.zig.LazySrcLoc;
const link = @import("../../link.zig");
const TypedValue = @import("../../TypedValue.zig");
const Air = @import("../../Air.zig");
@@ -767,8 +767,7 @@ pub fn deinit(func: *CodeGen) void {
/// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError {
const mod = func.bin_file.base.comp.module.?;
const src = LazySrcLoc.nodeOffset(0);
const src_loc = src.toSrcLoc(func.decl, mod);
const src_loc = func.decl.srcLoc(mod);
func.err_msg = try Module.ErrorMsg.create(func.gpa, src_loc, fmt, args);
return error.CodegenFail;
}
 
src/codegen.zig added: 1602, removed: 1475, total 127
@@ -21,7 +21,7 @@ const Target = std.Target;
const Type = @import("type.zig").Type;
const TypedValue = @import("TypedValue.zig");
const Value = @import("Value.zig");
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const Alignment = InternPool.Alignment;
 
pub const Result = union(enum) {
 
src/codegen/c.zig added: 1602, removed: 1475, total 127
@@ -13,7 +13,7 @@ const TypedValue = @import("../TypedValue.zig");
const C = link.File.C;
const Decl = Module.Decl;
const trace = @import("../tracy.zig").trace;
const LazySrcLoc = Module.LazySrcLoc;
const LazySrcLoc = std.zig.LazySrcLoc;
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
const InternPool = @import("../InternPool.zig");
@@ -570,8 +570,7 @@ pub const DeclGen = struct {
const mod = dg.module;
const decl_index = dg.pass.decl;
const decl = mod.declPtr(decl_index);
const src = LazySrcLoc.nodeOffset(0);
const src_loc = src.toSrcLoc(decl, mod);
const src_loc = decl.srcLoc(mod);
dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
return error.AnalysisFail;
}
 
src/codegen/llvm.zig added: 1602, removed: 1475, total 127
@@ -23,7 +23,7 @@ const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
const Value = @import("../Value.zig");
const Type = @import("../type.zig").Type;
const LazySrcLoc = Module.LazySrcLoc;
const LazySrcLoc = std.zig.LazySrcLoc;
const x86_64_abi = @import("../arch/x86_64/abi.zig");
const wasm_c_abi = @import("../arch/wasm/abi.zig");
const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
@@ -4686,7 +4686,7 @@ pub const DeclGen = struct {
const o = dg.object;
const gpa = o.gpa;
const mod = o.module;
const src_loc = LazySrcLoc.nodeOffset(0).toSrcLoc(dg.decl, mod);
const src_loc = dg.decl.srcLoc(mod);
dg.err_msg = try Module.ErrorMsg.create(gpa, src_loc, "TODO (LLVM): " ++ format, args);
return error.CodegenFail;
}
 
src/codegen/spirv.zig added: 1602, removed: 1475, total 127
@@ -8,9 +8,8 @@ const Module = @import("../Module.zig");
const Decl = Module.Decl;
const Type = @import("../type.zig").Type;
const Value = @import("../Value.zig");
const LazySrcLoc = Module.LazySrcLoc;
const LazySrcLoc = std.zig.LazySrcLoc;
const Air = @import("../Air.zig");
const Zir = @import("../Zir.zig");
const Liveness = @import("../Liveness.zig");
const InternPool = @import("../InternPool.zig");
 
@@ -413,8 +412,7 @@ const DeclGen = struct {
pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
@setCold(true);
const mod = self.module;
const src = LazySrcLoc.nodeOffset(0);
const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index), mod);
const src_loc = self.module.declPtr(self.decl_index).srcLoc(mod);
assert(self.error_msg == null);
self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
return error.CodegenFail;
@@ -5270,8 +5268,7 @@ const DeclGen = struct {
// TODO: Translate proper error locations.
assert(as.errors.items.len != 0);
assert(self.error_msg == null);
const loc = LazySrcLoc.nodeOffset(0);
const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index), mod);
const src_loc = self.module.declPtr(self.decl_index).srcLoc(mod);
self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);
 
 
src/crash_report.zig added: 1602, removed: 1475, total 127
@@ -8,7 +8,7 @@ const native_os = builtin.os.tag;
 
const Module = @import("Module.zig");
const Sema = @import("Sema.zig");
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const Decl = Module.Decl;
 
pub const is_enabled = builtin.mode == .Debug;
 
src/introspect.zig added: 1602, removed: 1475, total 127
@@ -153,6 +153,7 @@ pub const EnvVar = enum {
ZIG_VERBOSE_LINK,
ZIG_VERBOSE_CC,
ZIG_BTRFS_WORKAROUND,
ZIG_DEBUG_CMD,
CC,
NO_COLOR,
XDG_CACHE_HOME,
 
src/main.zig added: 1602, removed: 1475, total 127
@@ -8,6 +8,7 @@ const process = std.process;
const Allocator = mem.Allocator;
const ArrayList = std.ArrayList;
const Ast = std.zig.Ast;
const Color = std.zig.Color;
const warn = std.log.warn;
const ThreadPool = std.Thread.Pool;
const cleanExit = std.process.cleanExit;
@@ -25,7 +26,7 @@ const Cache = std.Build.Cache;
const target_util = @import("target.zig");
const crash_report = @import("crash_report.zig");
const Module = @import("Module.zig");
const AstGen = @import("AstGen.zig");
const AstGen = std.zig.AstGen;
const mingw = @import("mingw.zig");
const Server = std.zig.Server;
 
@@ -66,18 +67,8 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
process.exit(1);
}
 
/// There are many assumptions in the entire codebase that Zig source files can
/// be byte-indexed with a u32 integer.
const max_src_size = std.math.maxInt(u32);
 
const debug_extensions_enabled = builtin.mode == .Debug;
 
const Color = enum {
auto,
off,
on,
};
 
const normal_usage =
\\Usage: zig [command] [options]
\\
@@ -212,14 +203,6 @@ pub fn main() anyerror!void {
}
}
 
if (build_options.only_reduce) {
if (mem.eql(u8, args[1], "reduce")) {
return @import("reduce.zig").main(gpa, arena, args);
} else {
@panic("only reduce is supported in a -Donly-reduce build");
}
}
 
return mainArgs(gpa, arena, args);
}
 
@@ -311,7 +294,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
} else if (mem.eql(u8, cmd, "rc")) {
return cmdRc(gpa, arena, args[1..]);
} else if (mem.eql(u8, cmd, "fmt")) {
return cmdFmt(gpa, arena, cmd_args);
return jitCmd(gpa, arena, cmd_args, "fmt", "fmt.zig");
} else if (mem.eql(u8, cmd, "objcopy")) {
return @import("objcopy.zig").cmdObjCopy(gpa, arena, cmd_args);
} else if (mem.eql(u8, cmd, "fetch")) {
@@ -334,7 +317,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
verifyLibcxxCorrectlyLinked();
return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
} else if (mem.eql(u8, cmd, "reduce")) {
return @import("reduce.zig").main(gpa, arena, args);
return jitCmd(gpa, arena, cmd_args, "reduce", "reduce.zig");
} else if (mem.eql(u8, cmd, "zen")) {
return io.getStdOut().writeAll(info_zen);
} else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
@@ -2756,6 +2739,7 @@ fn buildOutputType(
.paths = .{
.root = .{
.root_dir = zig_lib_directory,
.sub_path = "compiler",
},
.root_src_path = "test_runner.zig",
},
@@ -4501,7 +4485,7 @@ fn updateModule(comp: *Compilation, color: Color) !void {
defer errors.deinit(comp.gpa);
 
if (errors.errorMessageCount() > 0) {
errors.renderToStdErr(renderOptions(color));
errors.renderToStdErr(color.renderOptions());
return error.SemanticAnalyzeFail;
}
}
@@ -4601,7 +4585,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
p.errors = errors;
return;
} else {
errors.renderToStdErr(renderOptions(color));
errors.renderToStdErr(color.renderOptions());
process.exit(1);
}
},
@@ -5402,7 +5386,9 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
},
.root_src_path = fs.path.basename(runner),
} else .{
.root = .{ .root_dir = zig_lib_directory },
.root = .{
.root_dir = zig_lib_directory,
},
.root_src_path = "build_runner.zig",
};
 
@@ -5528,7 +5514,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
 
if (fetch.error_bundle.root_list.items.len > 0) {
var errors = try fetch.error_bundle.toOwnedBundle("");
errors.renderToStdErr(renderOptions(color));
errors.renderToStdErr(color.renderOptions());
process.exit(1);
}
 
@@ -5719,470 +5705,165 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
}
}
 
fn readSourceFileToEndAlloc(
allocator: Allocator,
input: *const fs.File,
size_hint: ?usize,
) ![:0]u8 {
const source_code = input.readToEndAllocOptions(
allocator,
max_src_size,
size_hint,
@alignOf(u16),
0,
) catch |err| switch (err) {
error.ConnectionResetByPeer => unreachable,
error.ConnectionTimedOut => unreachable,
error.NotOpenForReading => unreachable,
else => |e| return e,
};
errdefer allocator.free(source_code);
 
// Detect unsupported file types with their Byte Order Mark
const unsupported_boms = [_][]const u8{
"\xff\xfe\x00\x00", // UTF-32 little endian
"\xfe\xff\x00\x00", // UTF-32 big endian
"\xfe\xff", // UTF-16 big endian
};
for (unsupported_boms) |bom| {
if (mem.startsWith(u8, source_code, bom)) {
return error.UnsupportedEncoding;
}
}
 
// If the file starts with a UTF-16 little endian BOM, translate it to UTF-8
if (mem.startsWith(u8, source_code, "\xff\xfe")) {
const source_code_utf16_le = mem.bytesAsSlice(u16, source_code);
const source_code_utf8 = std.unicode.utf16LeToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) {
error.DanglingSurrogateHalf => error.UnsupportedEncoding,
error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,
error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,
else => |e| return e,
};
 
allocator.free(source_code);
return source_code_utf8;
}
 
return source_code;
}
 
const usage_fmt =
\\Usage: zig fmt [file]...
\\
\\ Formats the input files and modifies them in-place.
\\ Arguments can be files or directories, which are searched
\\ recursively.
\\
\\Options:
\\ -h, --help Print this help and exit
\\ --color [auto|off|on] Enable or disable colored error messages
\\ --stdin Format code from stdin; output to stdout
\\ --check List non-conforming files and exit with an error
\\ if the list is non-empty
\\ --ast-check Run zig ast-check on every file
\\ --exclude [file] Exclude file or directory from formatting
\\
\\
;
 
const Fmt = struct {
seen: SeenMap,
any_error: bool,
check_ast: bool,
color: Color,
fn jitCmd(
gpa: Allocator,
arena: Allocator,
out_buffer: std.ArrayList(u8),
args: []const []const u8,
cmd_name: []const u8,
root_src_path: []const u8,
) !void {
const color: Color = .auto;
 
const SeenMap = std.AutoHashMap(fs.File.INode, void);
};
 
fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
var color: Color = .auto;
var stdin_flag: bool = false;
var check_flag: bool = false;
var check_ast_flag: bool = false;
var input_files = ArrayList([]const u8).init(gpa);
defer input_files.deinit();
var excluded_files = ArrayList([]const u8).init(gpa);
defer excluded_files.deinit();
 
{
var i: usize = 0;
while (i < args.len) : (i += 1) {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
const stdout = io.getStdOut().writer();
try stdout.writeAll(usage_fmt);
return cleanExit();
} else if (mem.eql(u8, arg, "--color")) {
if (i + 1 >= args.len) {
fatal("expected [auto|on|off] after --color", .{});
}
i += 1;
const next_arg = args[i];
color = std.meta.stringToEnum(Color, next_arg) orelse {
fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
};
} else if (mem.eql(u8, arg, "--stdin")) {
stdin_flag = true;
} else if (mem.eql(u8, arg, "--check")) {
check_flag = true;
} else if (mem.eql(u8, arg, "--ast-check")) {
check_ast_flag = true;
} else if (mem.eql(u8, arg, "--exclude")) {
if (i + 1 >= args.len) {
fatal("expected parameter after --exclude", .{});
}
i += 1;
const next_arg = args[i];
try excluded_files.append(next_arg);
} else {
fatal("unrecognized parameter: '{s}'", .{arg});
}
} else {
try input_files.append(arg);
}
}
}
 
if (stdin_flag) {
if (input_files.items.len != 0) {
fatal("cannot use --stdin with positional arguments", .{});
}
 
const stdin = io.getStdIn();
const source_code = readSourceFileToEndAlloc(gpa, &stdin, null) catch |err| {
fatal("unable to read stdin: {}", .{err});
};
defer gpa.free(source_code);
 
var tree = Ast.parse(gpa, source_code, .zig) catch |err| {
fatal("error parsing stdin: {}", .{err});
};
defer tree.deinit(gpa);
 
if (check_ast_flag) {
var file: Module.File = .{
.status = .never_loaded,
.source_loaded = true,
.zir_loaded = false,
.sub_file_path = "<stdin>",
.source = source_code,
.stat = undefined,
.tree = tree,
.tree_loaded = true,
.zir = undefined,
.mod = undefined,
.root_decl = .none,
};
 
file.mod = try Package.Module.createLimited(arena, .{
.root = Package.Path.cwd(),
.root_src_path = file.sub_file_path,
.fully_qualified_name = "root",
});
 
file.zir = try AstGen.generate(gpa, file.tree);
file.zir_loaded = true;
defer file.zir.deinit(gpa);
 
if (file.zir.hasCompileErrors()) {
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
try wip_errors.init(gpa);
defer wip_errors.deinit();
try Compilation.addZirErrorMessages(&wip_errors, &file);
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(color));
process.exit(2);
}
} else if (tree.errors.len != 0) {
try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
process.exit(2);
}
const formatted = try tree.render(gpa);
defer gpa.free(formatted);
 
if (check_flag) {
const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
process.exit(code);
}
 
return io.getStdOut().writeAll(formatted);
}
 
if (input_files.items.len == 0) {
fatal("expected at least one source file argument", .{});
}
 
var fmt = Fmt{
.gpa = gpa,
.arena = arena,
.seen = Fmt.SeenMap.init(gpa),
.any_error = false,
.check_ast = check_ast_flag,
.color = color,
.out_buffer = std.ArrayList(u8).init(gpa),
const target_query: std.Target.Query = .{};
const resolved_target: Package.Module.ResolvedTarget = .{
.result = resolveTargetQueryOrFatal(target_query),
.is_native_os = true,
.is_native_abi = true,
};
defer fmt.seen.deinit();
defer fmt.out_buffer.deinit();
 
// Mark any excluded files/directories as already seen,
// so that they are skipped later during actual processing
for (excluded_files.items) |file_path| {
const stat = fs.cwd().statFile(file_path) catch |err| switch (err) {
error.FileNotFound => continue,
// On Windows, statFile does not work for directories
error.IsDir => dir: {
var dir = try fs.cwd().openDir(file_path, .{});
defer dir.close();
break :dir try dir.stat();
},
else => |e| return e,
};
try fmt.seen.put(stat.inode, {});
}
const exe_basename = try std.zig.binNameAlloc(arena, .{
.root_name = cmd_name,
.target = resolved_target.result,
.output_mode = .Exe,
});
const emit_bin: Compilation.EmitLoc = .{
.directory = null, // Use the global zig-cache.
.basename = exe_basename,
};
 
for (input_files.items) |file_path| {
try fmtPath(&fmt, file_path, check_flag, fs.cwd(), file_path);
}
if (fmt.any_error) {
process.exit(1);
}
}
const self_exe_path = introspect.findZigExePath(arena) catch |err| {
fatal("unable to find self exe path: {s}", .{@errorName(err)});
};
 
const FmtError = error{
SystemResources,
OperationAborted,
IoPending,
BrokenPipe,
Unexpected,
WouldBlock,
FileClosed,
DestinationAddressRequired,
DiskQuota,
FileTooBig,
InputOutput,
NoSpaceLeft,
AccessDenied,
OutOfMemory,
RenameAcrossMountPoints,
ReadOnlyFileSystem,
LinkQuotaExceeded,
FileBusy,
EndOfStream,
Unseekable,
NotOpenForWriting,
UnsupportedEncoding,
ConnectionResetByPeer,
SocketNotConnected,
LockViolation,
NetNameDeleted,
InvalidArgument,
} || fs.File.OpenError;
const optimize_mode: std.builtin.OptimizeMode = if (EnvVar.ZIG_DEBUG_CMD.isSet())
.Debug
else
.ReleaseFast;
const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
 
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
else => {
warn("unable to format '{s}': {s}", .{ file_path, @errorName(err) });
fmt.any_error = true;
return;
var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
.path = lib_dir,
.handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
fatal("unable to open zig lib directory from 'zig-lib-dir' argument: '{s}': {s}", .{ lib_dir, @errorName(err) });
},
} else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
};
}
defer zig_lib_directory.handle.close();
 
fn fmtPathDir(
fmt: *Fmt,
file_path: []const u8,
check_mode: bool,
parent_dir: fs.Dir,
parent_sub_path: []const u8,
) FmtError!void {
var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
defer dir.close();
var global_cache_directory: Compilation.Directory = l: {
const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
break :l .{
.handle = try fs.cwd().makeOpenPath(p, .{}),
.path = p,
};
};
defer global_cache_directory.handle.close();
 
const stat = try dir.stat();
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
var thread_pool: ThreadPool = undefined;
try thread_pool.init(.{ .allocator = gpa });
defer thread_pool.deinit();
 
var dir_it = dir.iterate();
while (try dir_it.next()) |entry| {
const is_dir = entry.kind == .directory;
var child_argv: std.ArrayListUnmanaged([]const u8) = .{};
try child_argv.ensureUnusedCapacity(arena, args.len + 1);
 
if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
 
if (is_dir or entry.kind == .file and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
defer fmt.gpa.free(full_path);
 
if (is_dir) {
try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
} else {
fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
warn("unable to format '{s}': {s}", .{ full_path, @errorName(err) });
fmt.any_error = true;
return;
};
}
}
}
}
 
fn fmtPathFile(
fmt: *Fmt,
file_path: []const u8,
check_mode: bool,
dir: fs.Dir,
sub_path: []const u8,
) FmtError!void {
const source_file = try dir.openFile(sub_path, .{});
var file_closed = false;
errdefer if (!file_closed) source_file.close();
 
const stat = try source_file.stat();
 
if (stat.kind == .directory)
return error.IsDir;
 
const gpa = fmt.gpa;
const source_code = try readSourceFileToEndAlloc(
gpa,
&source_file,
std.math.cast(usize, stat.size) orelse return error.FileTooBig,
);
defer gpa.free(source_code);
 
source_file.close();
file_closed = true;
 
// Add to set after no longer possible to get error.IsDir.
if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
 
var tree = try Ast.parse(gpa, source_code, .zig);
defer tree.deinit(gpa);
 
if (tree.errors.len != 0) {
try printAstErrorsToStderr(gpa, tree, file_path, fmt.color);
fmt.any_error = true;
return;
}
 
if (fmt.check_ast) {
var file: Module.File = .{
.status = .never_loaded,
.source_loaded = true,
.zir_loaded = false,
.sub_file_path = file_path,
.source = source_code,
.stat = .{
.size = stat.size,
.inode = stat.inode,
.mtime = stat.mtime,
// We want to release all the locks before executing the child process, so we make a nice
// big block here to ensure the cleanup gets run when we extract out our argv.
{
const main_mod_paths: Package.Module.CreateOptions.Paths = .{
.root = .{
.root_dir = zig_lib_directory,
.sub_path = "compiler",
},
.tree = tree,
.tree_loaded = true,
.zir = undefined,
.mod = undefined,
.root_decl = .none,
.root_src_path = root_src_path,
};
 
file.mod = try Package.Module.createLimited(fmt.arena, .{
.root = Package.Path.cwd(),
.root_src_path = file.sub_file_path,
.fully_qualified_name = "root",
const config = try Compilation.Config.resolve(.{
.output_mode = .Exe,
.root_optimize_mode = optimize_mode,
.resolved_target = resolved_target,
.have_zcu = true,
.emit_bin = true,
.is_test = false,
});
 
if (stat.size > max_src_size)
return error.FileTooBig;
 
file.zir = try AstGen.generate(gpa, file.tree);
file.zir_loaded = true;
defer file.zir.deinit(gpa);
 
if (file.zir.hasCompileErrors()) {
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
try wip_errors.init(gpa);
defer wip_errors.deinit();
try Compilation.addZirErrorMessages(&wip_errors, &file);
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(fmt.color));
fmt.any_error = true;
}
}
 
// As a heuristic, we make enough capacity for the same as the input source.
fmt.out_buffer.shrinkRetainingCapacity(0);
try fmt.out_buffer.ensureTotalCapacity(source_code.len);
 
try tree.renderToArrayList(&fmt.out_buffer, .{});
if (mem.eql(u8, fmt.out_buffer.items, source_code))
return;
 
if (check_mode) {
const stdout = io.getStdOut().writer();
try stdout.print("{s}\n", .{file_path});
fmt.any_error = true;
} else {
var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
defer af.deinit();
 
try af.file.writeAll(fmt.out_buffer.items);
try af.finish();
const stdout = io.getStdOut().writer();
try stdout.print("{s}\n", .{file_path});
}
}
 
fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
try wip_errors.init(gpa);
defer wip_errors.deinit();
 
try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
 
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(color));
}
 
pub fn putAstErrorsIntoBundle(
gpa: Allocator,
tree: Ast,
path: []const u8,
wip_errors: *std.zig.ErrorBundle.Wip,
) Allocator.Error!void {
var file: Module.File = .{
.status = .never_loaded,
.source_loaded = true,
.zir_loaded = false,
.sub_file_path = path,
.source = tree.source,
.stat = .{
.size = 0,
.inode = 0,
.mtime = 0,
},
.tree = tree,
.tree_loaded = true,
.zir = undefined,
.mod = try Package.Module.createLimited(gpa, .{
.root = Package.Path.cwd(),
.root_src_path = path,
const root_mod = try Package.Module.create(arena, .{
.global_cache_directory = global_cache_directory,
.paths = main_mod_paths,
.fully_qualified_name = "root",
}),
.root_decl = .none,
};
defer gpa.destroy(file.mod);
.cc_argv = &.{},
.inherited = .{
.resolved_target = resolved_target,
.optimize_mode = optimize_mode,
},
.global = config,
.parent = null,
.builtin_mod = null,
});
 
file.zir = try AstGen.generate(gpa, file.tree);
file.zir_loaded = true;
defer file.zir.deinit(gpa);
const comp = Compilation.create(gpa, arena, .{
.zig_lib_directory = zig_lib_directory,
.local_cache_directory = global_cache_directory,
.global_cache_directory = global_cache_directory,
.root_name = cmd_name,
.config = config,
.root_mod = root_mod,
.main_mod = root_mod,
.emit_bin = emit_bin,
.emit_h = null,
.self_exe_path = self_exe_path,
.thread_pool = &thread_pool,
.cache_mode = .whole,
}) catch |err| {
fatal("unable to create compilation: {s}", .{@errorName(err)});
};
defer comp.destroy();
 
try Compilation.addZirErrorMessages(wip_errors, &file);
updateModule(comp, color) catch |err| switch (err) {
error.SemanticAnalyzeFail => process.exit(2),
else => |e| return e,
};
 
const exe_path = try global_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
child_argv.appendAssumeCapacity(exe_path);
}
 
child_argv.appendSliceAssumeCapacity(args);
 
if (process.can_execv) {
const err = process.execv(gpa, child_argv.items);
const cmd = try std.mem.join(arena, " ", child_argv.items);
fatal("the following command failed to execve with '{s}':\n{s}", .{
@errorName(err),
cmd,
});
}
 
if (!process.can_spawn) {
const cmd = try std.mem.join(arena, " ", child_argv.items);
fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
@tagName(builtin.os.tag), cmd,
});
}
 
var child = std.ChildProcess.init(child_argv.items, gpa);
child.stdin_behavior = .Inherit;
child.stdout_behavior = .Inherit;
child.stderr_behavior = .Inherit;
 
const term = try child.spawnAndWait();
switch (term) {
.Exited => |code| {
if (code == 0) return cleanExit();
const cmd = try std.mem.join(arena, " ", child_argv.items);
fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
},
else => {
const cmd = try std.mem.join(arena, " ", child_argv.items);
fatal("the following build command crashed:\n{s}", .{cmd});
},
}
}
 
const info_zen =
@@ -6655,7 +6336,7 @@ fn cmdAstCheck(
arena: Allocator,
args: []const []const u8,
) !void {
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
 
var color: Color = .auto;
var want_output_text = false;
@@ -6710,7 +6391,7 @@ fn cmdAstCheck(
 
const stat = try f.stat();
 
if (stat.size > max_src_size)
if (stat.size > std.zig.max_src_size)
return error.FileTooBig;
 
const source = try arena.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
@@ -6728,7 +6409,7 @@ fn cmdAstCheck(
};
} else {
const stdin = io.getStdIn();
const source = readSourceFileToEndAlloc(arena, &stdin, null) catch |err| {
const source = std.zig.readSourceFileToEndAlloc(arena, stdin, null) catch |err| {
fatal("unable to read stdin: {}", .{err});
};
file.sub_file_path = "<stdin>";
@@ -6758,7 +6439,7 @@ fn cmdAstCheck(
try Compilation.addZirErrorMessages(&wip_errors, &file);
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(color));
error_bundle.renderToStdErr(color.renderOptions());
process.exit(1);
}
 
@@ -6817,7 +6498,7 @@ fn cmdDumpZir(
args: []const []const u8,
) !void {
_ = arena;
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
 
const cache_file = args[0];
 
@@ -6877,7 +6558,7 @@ fn cmdChangelist(
args: []const []const u8,
) !void {
const color: Color = .auto;
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
 
const old_source_file = args[0];
const new_source_file = args[1];
@@ -6889,7 +6570,7 @@ fn cmdChangelist(
 
const stat = try f.stat();
 
if (stat.size > max_src_size)
if (stat.size > std.zig.max_src_size)
return error.FileTooBig;
 
var file: Module.File = .{
@@ -6938,7 +6619,7 @@ fn cmdChangelist(
try Compilation.addZirErrorMessages(&wip_errors, &file);
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(color));
error_bundle.renderToStdErr(color.renderOptions());
process.exit(1);
}
 
@@ -6949,7 +6630,7 @@ fn cmdChangelist(
 
const new_stat = try new_f.stat();
 
if (new_stat.size > max_src_size)
if (new_stat.size > std.zig.max_src_size)
return error.FileTooBig;
 
const new_source = try arena.allocSentinel(u8, @as(usize, @intCast(new_stat.size)), 0);
@@ -6973,7 +6654,7 @@ fn cmdChangelist(
try Compilation.addZirErrorMessages(&wip_errors, &file);
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(color));
error_bundle.renderToStdErr(color.renderOptions());
process.exit(1);
}
 
@@ -7241,23 +6922,6 @@ const ClangSearchSanitizer = struct {
};
};
 
fn get_tty_conf(color: Color) std.io.tty.Config {
return switch (color) {
.auto => std.io.tty.detectConfig(std.io.getStdErr()),
.on => .escape_codes,
.off => .no_color,
};
}
 
fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {
const ttyconf = get_tty_conf(color);
return .{
.ttyconf = ttyconf,
.include_source_line = ttyconf != .no_color,
.include_reference_trace = ttyconf != .no_color,
};
}
 
fn accessLibPath(
test_path: *std.ArrayList(u8),
checked_paths: *std.ArrayList(u8),
@@ -7498,7 +7162,7 @@ fn cmdFetch(
 
if (fetch.error_bundle.root_list.items.len > 0) {
var errors = try fetch.error_bundle.toOwnedBundle("");
errors.renderToStdErr(renderOptions(color));
errors.renderToStdErr(color.renderOptions());
process.exit(1);
}
 
@@ -7790,7 +7454,7 @@ fn loadManifest(
errdefer ast.deinit(gpa);
 
if (ast.errors.len > 0) {
try printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);
try std.zig.printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);
process.exit(2);
}
 
@@ -7807,7 +7471,7 @@ fn loadManifest(
 
var error_bundle = try wip_errors.toOwnedBundle("");
defer error_bundle.deinit(gpa);
error_bundle.renderToStdErr(renderOptions(options.color));
error_bundle.renderToStdErr(options.color.renderOptions());
 
process.exit(2);
}
 
src/print_zir.zig added: 1602, removed: 1475, total 127
@@ -5,9 +5,9 @@ const assert = std.debug.assert;
const Ast = std.zig.Ast;
const InternPool = @import("InternPool.zig");
 
const Zir = @import("Zir.zig");
const Zir = std.zig.Zir;
const Module = @import("Module.zig");
const LazySrcLoc = Module.LazySrcLoc;
const LazySrcLoc = std.zig.LazySrcLoc;
 
/// Write human-readable, debug formatted ZIR code to a file.
pub fn renderAsTextToFile(
 
stage1/config.zig.in added: 1602, removed: 1475, total 127
@@ -13,4 +13,3 @@ pub const skip_non_native = false;
pub const only_c = false;
pub const force_gpa = false;
pub const only_core_functionality = true;
pub const only_reduce = false;