From 01b4bf34ea4f37d8b778bb2413ac1fc445f8bead Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 16 Apr 2021 14:44:02 -0700 Subject: stage2: AstGen improvements * AstGen: represent compile errors in ZIR rather than returning `error.AnalysisFail`. * ZIR: remove decl_ref and decl_val instructions. These are replaced by `decl_ref_named` and `decl_val_named`, respectively, which will probably get renamed in the future to the instructions that were just deleted. * AstGen: implement `@This()`, `@fence()`, `@returnAddress()`, and `@src()`. * AstGen: struct_decl improved to support fields_len=0 but have decls. * AstGen: fix missing null bytes after compile error messages. * SrcLoc: no longer depend on `Decl`. Instead have an explicit field `parent_decl_node` which is an absolute AST Node index. * Module: `failed_files` table can have null value, in which case the key, which is a `*Scope.File`, will have ZIR errors in it. * ZIR: implement text rendering of struct decls. * CLI: introduce debug_usage and `zig astgen` command which is enabled when the compiler is built in debug mode. --- src/Module.zig | 220 ++++++++++++++++++++++++--------------------------------- 1 file changed, 91 insertions(+), 129 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 2baa064255..15434fe159 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -70,7 +70,7 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{}, compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{}, /// Using a map here for consistency with the other fields here. /// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator. -failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{}, +failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{}, /// Using a map here for consistency with the other fields here. /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, @@ -267,9 +267,10 @@ pub const Decl = struct { return .{ .node_offset = decl.nodeIndexToRelative(node_index) }; } - pub fn srcLoc(decl: *Decl) SrcLoc { + pub fn srcLoc(decl: Decl) SrcLoc { return .{ - .container = .{ .decl = decl }, + .file_scope = decl.getFileScope(), + .parent_decl_node = decl.src_node, .lazy = .{ .node_offset = 0 }, }; } @@ -367,7 +368,8 @@ pub const ErrorSet = struct { pub fn srcLoc(self: ErrorSet) SrcLoc { return .{ - .container = .{ .decl = self.owner_decl }, + .file_scope = self.owner_decl.getFileScope(), + .parent_decl_node = self.owner_decl.src_node, .lazy = .{ .node_offset = self.node_offset }, }; } @@ -397,7 +399,8 @@ pub const Struct = struct { pub fn srcLoc(s: Struct) SrcLoc { return .{ - .container = .{ .decl = s.owner_decl }, + .file_scope = s.owner_decl.getFileScope(), + .parent_decl_node = s.owner_decl.src_node, .lazy = .{ .node_offset = s.node_offset }, }; } @@ -416,7 +419,8 @@ pub const EnumSimple = struct { pub fn srcLoc(self: EnumSimple) SrcLoc { return .{ - .container = .{ .decl = self.owner_decl }, + .file_scope = self.owner_decl.getFileScope(), + .parent_decl_node = self.owner_decl.src_node, .lazy = .{ .node_offset = self.node_offset }, }; } @@ -444,7 +448,8 @@ pub const EnumFull = struct { pub fn srcLoc(self: EnumFull) SrcLoc { return .{ - .container = .{ .decl = self.owner_decl }, + .file_scope = self.owner_decl.getFileScope(), + .parent_decl_node = self.owner_decl.src_node, .lazy = .{ .node_offset = self.node_offset }, }; } @@ -1710,51 +1715,19 @@ pub const ErrorMsg = struct { /// Canonical reference to a position within a source file. pub const SrcLoc = struct { - /// The active field is determined by tag of `lazy`. - container: union { - /// The containing `Decl` according to the source code. - decl: *Decl, - file_scope: *Scope.File, - }, - /// Relative to `decl`. + file_scope: *Scope.File, + /// Might be 0 depending on tag of `lazy`. + parent_decl_node: ast.Node.Index, + /// Relative to `parent_decl_node`. lazy: LazySrcLoc, - pub fn fileScope(src_loc: SrcLoc) *Scope.File { - return switch (src_loc.lazy) { - .unneeded => unreachable, - - .byte_abs, - .token_abs, - .node_abs, - .entire_file, - => src_loc.container.file_scope, + pub fn declSrcToken(src_loc: SrcLoc) ast.TokenIndex { + const tree = src_loc.file_scope.tree; + return tree.firstToken(src_loc.parent_decl_node); + } - .byte_offset, - .token_offset, - .node_offset, - .node_offset_back2tok, - .node_offset_var_decl_ty, - .node_offset_for_cond, - .node_offset_builtin_call_arg0, - .node_offset_builtin_call_arg1, - .node_offset_array_access_index, - .node_offset_slice_sentinel, - .node_offset_call_func, - .node_offset_field_name, - .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_fn_type_cc, - .node_offset_fn_type_ret_ty, - => src_loc.container.decl.namespace.file_scope, - }; + pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) ast.TokenIndex { + return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node)); } pub fn byteOffset(src_loc: SrcLoc) !u32 { @@ -1765,48 +1738,45 @@ pub const SrcLoc = struct { .byte_abs => |byte_index| return byte_index, .token_abs => |tok_index| { - const tree = src_loc.container.file_scope.tree; + const tree = src_loc.file_scope.tree; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_abs => |node| { - const tree = src_loc.container.file_scope.tree; + const tree = src_loc.file_scope.tree; const token_starts = tree.tokens.items(.start); const tok_index = tree.firstToken(node); return token_starts[tok_index]; }, .byte_offset => |byte_off| { - const decl = src_loc.container.decl; - return decl.srcByteOffset() + byte_off; + const tree = src_loc.file_scope.tree; + const token_starts = tree.tokens.items(.start); + return token_starts[src_loc.declSrcToken()] + byte_off; }, .token_offset => |tok_off| { - const decl = src_loc.container.decl; - const tok_index = decl.srcToken() + tok_off; - const tree = decl.namespace.file_scope.tree; + const tok_index = src_loc.declSrcToken() + tok_off; + const tree = src_loc.file_scope.tree; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset, .node_offset_bin_op => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const main_tokens = tree.nodes.items(.main_token); const tok_index = main_tokens[node]; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_back2tok => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const tok_index = tree.firstToken(node) - 2; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_var_decl_ty => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_tags = tree.nodes.items(.tag); const full = switch (node_tags[node]) { .global_var_decl => tree.globalVarDecl(node), @@ -1825,11 +1795,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_builtin_call_arg0 => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const param = switch (node_tags[node]) { .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs, .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs], @@ -1841,11 +1810,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_builtin_call_arg1 => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const param = switch (node_tags[node]) { .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs, .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1], @@ -1857,22 +1825,20 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_array_access_index => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const main_tokens = tree.nodes.items(.main_token); const tok_index = main_tokens[node_datas[node].rhs]; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_slice_sentinel => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const full = switch (node_tags[node]) { .slice_open => tree.sliceOpen(node), .slice => tree.slice(node), @@ -1885,11 +1851,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_call_func => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); var params: [1]ast.Node.Index = undefined; const full = switch (node_tags[node]) { .call_one, @@ -1912,11 +1877,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_field_name => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const tok_index = switch (node_tags[node]) { .field_access => node_datas[node].rhs, else => tree.firstToken(node) - 2, @@ -1925,21 +1889,19 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_deref_ptr => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const tok_index = node_datas[node].lhs; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_asm_source => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const full = switch (node_tags[node]) { .asm_simple => tree.asmSimple(node), .@"asm" => tree.asmFull(node), @@ -1951,11 +1913,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_asm_ret_ty => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const full = switch (node_tags[node]) { .asm_simple => tree.asmSimple(node), .@"asm" => tree.asmFull(node), @@ -1968,9 +1929,8 @@ pub const SrcLoc = struct { }, .node_offset_for_cond, .node_offset_if_cond => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_tags = tree.nodes.items(.tag); const src_node = switch (node_tags[node]) { .if_simple => tree.ifSimple(node).ast.cond_expr, @@ -1988,9 +1948,8 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_bin_lhs => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const src_node = node_datas[node].lhs; const main_tokens = tree.nodes.items(.main_token); @@ -1999,9 +1958,8 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_bin_rhs => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const src_node = node_datas[node].rhs; const main_tokens = tree.nodes.items(.main_token); @@ -2011,9 +1969,8 @@ pub const SrcLoc = struct { }, .node_offset_switch_operand => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const src_node = node_datas[node].lhs; const main_tokens = tree.nodes.items(.main_token); @@ -2023,9 +1980,8 @@ pub const SrcLoc = struct { }, .node_offset_switch_special_prong => |node_off| { - const decl = src_loc.container.decl; - const switch_node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const switch_node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -2050,9 +2006,8 @@ pub const SrcLoc = struct { }, .node_offset_switch_range => |node_off| { - const decl = src_loc.container.decl; - const switch_node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const switch_node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -2081,11 +2036,10 @@ pub const SrcLoc = struct { }, .node_offset_fn_type_cc => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); var params: [1]ast.Node.Index = undefined; const full = switch (node_tags[node]) { .fn_proto_simple => tree.fnProtoSimple(¶ms, node), @@ -2101,11 +2055,10 @@ pub const SrcLoc = struct { }, .node_offset_fn_type_ret_ty => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); var params: [1]ast.Node.Index = undefined; const full = switch (node_tags[node]) { .fn_proto_simple => tree.fnProtoSimple(¶ms, node), @@ -2288,7 +2241,8 @@ pub const LazySrcLoc = union(enum) { .token_abs, .node_abs, => .{ - .container = .{ .file_scope = scope.getFileScope() }, + .file_scope = scope.getFileScope(), + .parent_decl_node = 0, .lazy = lazy, }, @@ -2317,7 +2271,8 @@ pub const LazySrcLoc = union(enum) { .node_offset_fn_type_cc, .node_offset_fn_type_ret_ty, => .{ - .container = .{ .decl = scope.srcDecl().? }, + .file_scope = scope.getFileScope(), + .parent_decl_node = scope.srcDecl().?.src_node, .lazy = lazy, }, }; @@ -2332,7 +2287,8 @@ pub const LazySrcLoc = union(enum) { .token_abs, .node_abs, => .{ - .container = .{ .file_scope = decl.getFileScope() }, + .file_scope = decl.getFileScope(), + .parent_decl_node = 0, .lazy = lazy, }, @@ -2361,7 +2317,8 @@ pub const LazySrcLoc = union(enum) { .node_offset_fn_type_cc, .node_offset_fn_type_ret_ty, => .{ - .container = .{ .decl = decl }, + .file_scope = decl.getFileScope(), + .parent_decl_node = decl.src_node, .lazy = lazy, }, }; @@ -2409,7 +2366,7 @@ pub fn deinit(mod: *Module) void { mod.emit_h_failed_decls.deinit(gpa); for (mod.failed_files.items()) |entry| { - entry.value.destroy(gpa); + if (entry.value) |msg| msg.destroy(gpa); } mod.failed_files.deinit(gpa); @@ -2495,7 +2452,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node const lock = comp.mutex.acquire(); defer lock.release(); if (mod.failed_files.swapRemove(file)) |entry| { - entry.value.destroy(gpa); // Delete previous error message. + if (entry.value) |msg| msg.destroy(gpa); // Delete previous error message. } }, } @@ -2531,7 +2488,8 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node const err_msg = try gpa.create(ErrorMsg); err_msg.* = .{ .src_loc = .{ - .container = .{ .file_scope = file }, + .file_scope = file, + .parent_decl_node = 0, .lazy = .{ .byte_abs = token_starts[parse_err.token] }, }, .msg = msg.toOwnedSlice(), @@ -2550,11 +2508,11 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node file.zir = try AstGen.generate(gpa, file); file.zir_loaded = true; - if (file.zir.extra[1] != 0) { + if (file.zir.hasCompileErrors()) { { const lock = comp.mutex.acquire(); defer lock.release(); - try mod.failed_files.putNoClobber(gpa, file, undefined); + try mod.failed_files.putNoClobber(gpa, file, null); } file.status = .astgen_failure; return error.AnalysisFail; @@ -2972,12 +2930,14 @@ fn semaContainerFn( if (deleted_decls.swapRemove(decl) == null) { decl.analysis = .sema_failure; const msg = try ErrorMsg.create(mod.gpa, .{ - .container = .{ .file_scope = namespace.file_scope }, + .file_scope = namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .token_abs = name_token }, }, "redeclaration of '{s}'", .{decl.name}); errdefer msg.destroy(mod.gpa); const other_src_loc: SrcLoc = .{ - .container = .{ .file_scope = decl.namespace.file_scope }, + .file_scope = namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .node_abs = prev_src_node }, }; try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{}); @@ -3040,12 +3000,14 @@ fn semaContainerVar( if (deleted_decls.swapRemove(decl) == null) { decl.analysis = .sema_failure; const msg = try ErrorMsg.create(mod.gpa, .{ - .container = .{ .file_scope = namespace.file_scope }, + .file_scope = namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .token_abs = name_token }, }, "redeclaration of '{s}'", .{decl.name}); errdefer msg.destroy(mod.gpa); const other_src_loc: SrcLoc = .{ - .container = .{ .file_scope = decl.namespace.file_scope }, + .file_scope = decl.namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .node_abs = prev_src_node }, }; try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{}); -- cgit v1.2.3