authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-25 23:00:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-25 23:45:17-07:00
logb2deaf80279aab1322036e55a9646ecbaaa47f44
treef950b7d882299bab45a6d5ea8cd213d1850c2bb0
parent4bfcd105eff797aceb621d2c8b971c15fef6e450

stage2: improve source locations of Decl access

* zir.Code: introduce a decls array. This is so that `decl_val` and `decl_ref` instructions can refer to a Decl with a u32 and therefore they can also store a source location. This is needed for proper compile error reporting. * astgen uses a hash map to avoid redundantly adding a Decl to the decls array. * fixed reporting "instruction illegal outside function body" instead of the desired message "unable to resolve comptime value". * astgen skips emitting dbg_stmt instructions in comptime scopes. * astgen has some logic to avoid adding unnecessary type coercion instructions for common values.

6 files changed, 148 insertions(+), 66 deletions(-)

BRANCH_TODO+3
......@@ -38,3 +38,6 @@ Performance optimizations to look into:
3838 * astgen for loops using pointer arithmetic because it's faster and if the programmer
3939 wants an index capture, that will just be a convenience variable that zig sets up
4040 independently.
41 * in astgen, if a decl_val would be to a const variable or to a function, there could be
42 a special zir.Inst.Ref form that means to refer to a decl as the operand. This
43 would elide all the decl_val instructions in the ZIR.
src/Module.zig+21-12
......@@ -103,7 +103,7 @@ stage1_flags: packed struct {
103103
104104emit_h: ?Compilation.EmitLoc,
105105
106compile_log_text: std.ArrayListUnmanaged(u8) = .{},
106compile_log_text: ArrayListUnmanaged(u8) = .{},
107107
108108pub const Export = struct {
109109 options: std.builtin.ExportOptions,
......@@ -335,7 +335,7 @@ pub const Decl = struct {
335335
336336/// This state is attached to every Decl when Module emit_h is non-null.
337337pub const EmitH = struct {
338 fwd_decl: std.ArrayListUnmanaged(u8) = .{},
338 fwd_decl: ArrayListUnmanaged(u8) = .{},
339339};
340340
341341/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
......@@ -916,7 +916,7 @@ pub const Scope = struct {
916916 zir_code: *WipZirCode,
917917 /// Keeps track of the list of instructions in this scope only. Indexes
918918 /// to instructions in `zir_code`.
919 instructions: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
919 instructions: ArrayListUnmanaged(zir.Inst.Index) = .{},
920920 label: ?Label = null,
921921 break_block: zir.Inst.Index = 0,
922922 continue_block: zir.Inst.Index = 0,
......@@ -935,11 +935,11 @@ pub const Scope = struct {
935935 break_count: usize = 0,
936936 /// Tracks `break :foo bar` instructions so they can possibly be elided later if
937937 /// the labeled block ends up not needing a result location pointer.
938 labeled_breaks: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
938 labeled_breaks: ArrayListUnmanaged(zir.Inst.Index) = .{},
939939 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions
940940 /// so they can possibly be elided later if the labeled block ends up not needing
941941 /// a result location pointer.
942 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
942 labeled_store_to_block_ptr_list: ArrayListUnmanaged(zir.Inst.Index) = .{},
943943
944944 pub const Label = struct {
945945 token: ast.TokenIndex,
......@@ -957,6 +957,7 @@ pub const Scope = struct {
957957 .instructions = gz.zir_code.instructions.toOwnedSlice(),
958958 .string_bytes = gz.zir_code.string_bytes.toOwnedSlice(gpa),
959959 .extra = gz.zir_code.extra.toOwnedSlice(gpa),
960 .decls = gz.zir_code.decls.toOwnedSlice(gpa),
960961 };
961962 }
962963
......@@ -1253,11 +1254,15 @@ pub const Scope = struct {
12531254 pub fn addDecl(
12541255 gz: *GenZir,
12551256 tag: zir.Inst.Tag,
1256 decl: *Decl,
1257 decl_index: u32,
1258 src_node: ast.Node.Index,
12571259 ) !zir.Inst.Ref {
12581260 return gz.add(.{
12591261 .tag = tag,
1260 .data = .{ .decl = decl },
1262 .data = .{ .pl_node = .{
1263 .src_node = gz.zir_code.decl.nodeIndexToRelative(src_node),
1264 .payload_index = decl_index,
1265 } },
12611266 });
12621267 }
12631268
......@@ -1379,8 +1384,10 @@ pub const Scope = struct {
13791384/// The `GenZir.finish` function converts this to a `zir.Code`.
13801385pub const WipZirCode = struct {
13811386 instructions: std.MultiArrayList(zir.Inst) = .{},
1382 string_bytes: std.ArrayListUnmanaged(u8) = .{},
1383 extra: std.ArrayListUnmanaged(u32) = .{},
1387 string_bytes: ArrayListUnmanaged(u8) = .{},
1388 extra: ArrayListUnmanaged(u32) = .{},
1389 decl_map: std.StringArrayHashMapUnmanaged(void) = .{},
1390 decls: ArrayListUnmanaged(*Decl) = .{},
13841391 /// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
13851392 /// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
13861393 ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,
......@@ -1442,6 +1449,8 @@ pub const WipZirCode = struct {
14421449 wzc.instructions.deinit(wzc.gpa);
14431450 wzc.extra.deinit(wzc.gpa);
14441451 wzc.string_bytes.deinit(wzc.gpa);
1452 wzc.decl_map.deinit(wzc.gpa);
1453 wzc.decls.deinit(wzc.gpa);
14451454 }
14461455};
14471456
......@@ -4062,7 +4071,7 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
40624071 if (!mem.startsWith(u8, ident_name, "@")) {
40634072 return ident_name;
40644073 }
4065 var buf: std.ArrayListUnmanaged(u8) = .{};
4074 var buf: ArrayListUnmanaged(u8) = .{};
40664075 defer buf.deinit(mod.gpa);
40674076 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
40684077 return buf.toOwnedSlice(mod.gpa);
......@@ -4075,7 +4084,7 @@ pub fn appendIdentStr(
40754084 mod: *Module,
40764085 scope: *Scope,
40774086 token: ast.TokenIndex,
4078 buf: *std.ArrayListUnmanaged(u8),
4087 buf: *ArrayListUnmanaged(u8),
40794088) InnerError!void {
40804089 const tree = scope.tree();
40814090 const token_tags = tree.tokens.items(.tag);
......@@ -4093,7 +4102,7 @@ pub fn parseStrLit(
40934102 mod: *Module,
40944103 scope: *Scope,
40954104 token: ast.TokenIndex,
4096 buf: *std.ArrayListUnmanaged(u8),
4105 buf: *ArrayListUnmanaged(u8),
40974106 bytes: []const u8,
40984107 offset: u32,
40994108) InnerError!void {
src/Sema.zig+14-5
......@@ -1102,10 +1102,15 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
11021102 const tracy = trace(@src());
11031103 defer tracy.end();
11041104
1105 // We do not set sema.src here because dbg_stmt instructions are only emitted for
1106 // ZIR code that possibly will need to generate runtime code. So error messages
1107 // and other source locations must not rely on sema.src being set from dbg_stmt
1108 // instructions.
11051109 if (block.is_comptime) return;
11061110
11071111 const src_node = sema.code.instructions.items(.data)[inst].node;
11081112 const src: LazySrcLoc = .{ .node_offset = src_node };
1113
11091114 const src_loc = src.toSrcLoc(&block.base);
11101115 const abs_byte_off = try src_loc.byteOffset();
11111116 _ = try block.addDbgStmt(src, abs_byte_off);
......@@ -1115,16 +1120,20 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
11151120 const tracy = trace(@src());
11161121 defer tracy.end();
11171122
1118 const decl = sema.code.instructions.items(.data)[inst].decl;
1119 return sema.analyzeDeclRef(block, .unneeded, decl);
1123 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1124 const src = inst_data.src();
1125 const decl = sema.code.decls[inst_data.payload_index];
1126 return sema.analyzeDeclRef(block, src, decl);
11201127}
11211128
11221129fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
11231130 const tracy = trace(@src());
11241131 defer tracy.end();
11251132
1126 const decl = sema.code.instructions.items(.data)[inst].decl;
1127 return sema.analyzeDeclVal(block, .unneeded, decl);
1133 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1134 const src = inst_data.src();
1135 const decl = sema.code.decls[inst_data.payload_index];
1136 return sema.analyzeDeclVal(block, src, decl);
11281137}
11291138
11301139fn zirCallNone(
......@@ -3211,10 +3220,10 @@ fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void
32113220}
32123221
32133222fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
3214 try sema.requireFunctionBlock(block, src);
32153223 if (block.is_comptime) {
32163224 return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
32173225 }
3226 try sema.requireFunctionBlock(block, src);
32183227}
32193228
32203229fn validateVarType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) !void {
src/astgen.zig+77-12
......@@ -952,7 +952,9 @@ fn blockExprStmts(
952952
953953 var scope = parent_scope;
954954 for (statements) |statement| {
955 _ = try gz.addNode(.dbg_stmt_node, statement);
955 if (!gz.force_comptime) {
956 _ = try gz.addNode(.dbg_stmt_node, statement);
957 }
956958 switch (node_tags[statement]) {
957959 .global_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)),
958960 .local_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)),
......@@ -2846,14 +2848,17 @@ fn identifier(
28462848 };
28472849 }
28482850
2849 if (mod.lookupDeclName(scope, ident_name)) |decl| {
2850 return if (rl == .ref)
2851 gz.addDecl(.decl_ref, decl)
2852 else
2853 rvalue(mod, scope, rl, try gz.addDecl(.decl_val, decl), ident);
2851 const gop = try gz.zir_code.decl_map.getOrPut(mod.gpa, ident_name);
2852 if (!gop.found_existing) {
2853 const decl = mod.lookupDeclName(scope, ident_name) orelse
2854 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
2855 try gz.zir_code.decls.append(mod.gpa, decl);
2856 }
2857 const decl_index = @intCast(u32, gop.index);
2858 switch (rl) {
2859 .ref => return gz.addDecl(.decl_ref, decl_index, ident),
2860 else => return rvalue(mod, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),
28542861 }
2855
2856 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
28572862}
28582863
28592864fn stringLiteral(
......@@ -3743,10 +3748,70 @@ fn rvalue(
37433748 const src_token = tree.firstToken(src_node);
37443749 return gz.addUnTok(.ref, result, src_token);
37453750 },
3746 .ty => |ty_inst| return gz.addPlNode(.as_node, src_node, zir.Inst.As{
3747 .dest_type = ty_inst,
3748 .operand = result,
3749 }),
3751 .ty => |ty_inst| {
3752 // Quickly eliminate some common, unnecessary type coercion.
3753 const as_ty = @as(u64, @enumToInt(zir.Inst.Ref.type_type)) << 32;
3754 const as_comptime_int = @as(u64, @enumToInt(zir.Inst.Ref.comptime_int_type)) << 32;
3755 const as_bool = @as(u64, @enumToInt(zir.Inst.Ref.bool_type)) << 32;
3756 const as_usize = @as(u64, @enumToInt(zir.Inst.Ref.usize_type)) << 32;
3757 const as_void = @as(u64, @enumToInt(zir.Inst.Ref.void_type)) << 32;
3758 switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) {
3759 as_ty | @enumToInt(zir.Inst.Ref.u8_type),
3760 as_ty | @enumToInt(zir.Inst.Ref.i8_type),
3761 as_ty | @enumToInt(zir.Inst.Ref.u16_type),
3762 as_ty | @enumToInt(zir.Inst.Ref.i16_type),
3763 as_ty | @enumToInt(zir.Inst.Ref.u32_type),
3764 as_ty | @enumToInt(zir.Inst.Ref.i32_type),
3765 as_ty | @enumToInt(zir.Inst.Ref.u64_type),
3766 as_ty | @enumToInt(zir.Inst.Ref.i64_type),
3767 as_ty | @enumToInt(zir.Inst.Ref.usize_type),
3768 as_ty | @enumToInt(zir.Inst.Ref.isize_type),
3769 as_ty | @enumToInt(zir.Inst.Ref.c_short_type),
3770 as_ty | @enumToInt(zir.Inst.Ref.c_ushort_type),
3771 as_ty | @enumToInt(zir.Inst.Ref.c_int_type),
3772 as_ty | @enumToInt(zir.Inst.Ref.c_uint_type),
3773 as_ty | @enumToInt(zir.Inst.Ref.c_long_type),
3774 as_ty | @enumToInt(zir.Inst.Ref.c_ulong_type),
3775 as_ty | @enumToInt(zir.Inst.Ref.c_longlong_type),
3776 as_ty | @enumToInt(zir.Inst.Ref.c_ulonglong_type),
3777 as_ty | @enumToInt(zir.Inst.Ref.c_longdouble_type),
3778 as_ty | @enumToInt(zir.Inst.Ref.f16_type),
3779 as_ty | @enumToInt(zir.Inst.Ref.f32_type),
3780 as_ty | @enumToInt(zir.Inst.Ref.f64_type),
3781 as_ty | @enumToInt(zir.Inst.Ref.f128_type),
3782 as_ty | @enumToInt(zir.Inst.Ref.c_void_type),
3783 as_ty | @enumToInt(zir.Inst.Ref.bool_type),
3784 as_ty | @enumToInt(zir.Inst.Ref.void_type),
3785 as_ty | @enumToInt(zir.Inst.Ref.type_type),
3786 as_ty | @enumToInt(zir.Inst.Ref.anyerror_type),
3787 as_ty | @enumToInt(zir.Inst.Ref.comptime_int_type),
3788 as_ty | @enumToInt(zir.Inst.Ref.comptime_float_type),
3789 as_ty | @enumToInt(zir.Inst.Ref.noreturn_type),
3790 as_ty | @enumToInt(zir.Inst.Ref.null_type),
3791 as_ty | @enumToInt(zir.Inst.Ref.undefined_type),
3792 as_ty | @enumToInt(zir.Inst.Ref.fn_noreturn_no_args_type),
3793 as_ty | @enumToInt(zir.Inst.Ref.fn_void_no_args_type),
3794 as_ty | @enumToInt(zir.Inst.Ref.fn_naked_noreturn_no_args_type),
3795 as_ty | @enumToInt(zir.Inst.Ref.fn_ccc_void_no_args_type),
3796 as_ty | @enumToInt(zir.Inst.Ref.single_const_pointer_to_comptime_int_type),
3797 as_ty | @enumToInt(zir.Inst.Ref.const_slice_u8_type),
3798 as_ty | @enumToInt(zir.Inst.Ref.enum_literal_type),
3799 as_comptime_int | @enumToInt(zir.Inst.Ref.zero),
3800 as_comptime_int | @enumToInt(zir.Inst.Ref.one),
3801 as_bool | @enumToInt(zir.Inst.Ref.bool_true),
3802 as_bool | @enumToInt(zir.Inst.Ref.bool_false),
3803 as_usize | @enumToInt(zir.Inst.Ref.zero_usize),
3804 as_usize | @enumToInt(zir.Inst.Ref.one_usize),
3805 as_void | @enumToInt(zir.Inst.Ref.void_value),
3806 => return result, // type of result is already correct
3807
3808 // Need an explicit type coercion instruction.
3809 else => return gz.addPlNode(.as_node, src_node, zir.Inst.As{
3810 .dest_type = ty_inst,
3811 .operand = result,
3812 }),
3813 }
3814 },
37503815 .ptr => |ptr_inst| {
37513816 _ = try gz.addPlNode(.store_node, src_node, zir.Inst.Bin{
37523817 .lhs = ptr_inst,
src/zir.zig+18-22
......@@ -37,6 +37,8 @@ pub const Code = struct {
3737 string_bytes: []u8,
3838 /// The meaning of this data is determined by `Inst.Tag` value.
3939 extra: []u32,
40 /// Used for decl_val and decl_ref instructions.
41 decls: []*Module.Decl,
4042
4143 /// Returns the requested data, as well as the new index which is at the start of the
4244 /// trailers for the object.
......@@ -76,6 +78,7 @@ pub const Code = struct {
7678 code.instructions.deinit(gpa);
7779 gpa.free(code.string_bytes);
7880 gpa.free(code.extra);
81 gpa.free(code.decls);
7982 code.* = undefined;
8083 }
8184
......@@ -103,7 +106,7 @@ pub const Code = struct {
103106 const stderr = std.io.getStdErr().writer();
104107 try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name });
105108 try writer.writeInstToStream(stderr, 0);
106 try stderr.print("}} // ZIR {s} {s}\n\n", .{ kind, decl_name });
109 try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name });
107110 }
108111};
109112
......@@ -115,7 +118,7 @@ pub const Inst = struct {
115118 data: Data,
116119
117120 /// These names are used directly as the instruction names in the text format.
118 pub const Tag = enum {
121 pub const Tag = enum(u8) {
119122 /// Arithmetic addition, asserts no integer overflow.
120123 /// Uses the `pl_node` union field. Payload is `Bin`.
121124 add,
......@@ -274,10 +277,10 @@ pub const Inst = struct {
274277 /// Uses the `node` union field.
275278 dbg_stmt_node,
276279 /// Represents a pointer to a global decl.
277 /// Uses the `decl` union field.
280 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
278281 decl_ref,
279282 /// Equivalent to a decl_ref followed by load.
280 /// Uses the `decl` union field.
283 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
281284 decl_val,
282285 /// Load the value from a pointer. Assumes `x.*` syntax.
283286 /// Uses `un_node` field. AST node is the `x.*` syntax.
......@@ -612,10 +615,6 @@ pub const Inst = struct {
612615 // /// validated by the switch_br instruction.
613616 // switch_range,
614617
615 comptime {
616 assert(@sizeOf(Tag) == 1);
617 }
618
619618 /// Returns whether the instruction is one of the control flow "noreturn" types.
620619 /// Function calls do not count.
621620 pub fn isNoReturn(tag: Tag) bool {
......@@ -1099,7 +1098,6 @@ pub const Inst = struct {
10991098 }
11001099 },
11011100 bin: Bin,
1102 decl: *Module.Decl,
11031101 @"const": *TypedValue,
11041102 /// For strings which may contain null bytes.
11051103 str: struct {
......@@ -1503,6 +1501,10 @@ const Writer = struct {
15031501 .typeof_peer,
15041502 => try self.writePlNodeMultiOp(stream, inst),
15051503
1504 .decl_ref,
1505 .decl_val,
1506 => try self.writePlNodeDecl(stream, inst),
1507
15061508 .as_node => try self.writeAs(stream, inst),
15071509
15081510 .breakpoint,
......@@ -1513,10 +1515,6 @@ const Writer = struct {
15131515 .repeat_inline,
15141516 => try self.writeNode(stream, inst),
15151517
1516 .decl_ref,
1517 .decl_val,
1518 => try self.writeDecl(stream, inst),
1519
15201518 .error_value,
15211519 .enum_literal,
15221520 => try self.writeStrTok(stream, inst),
......@@ -1715,6 +1713,13 @@ const Writer = struct {
17151713 try self.writeSrc(stream, inst_data.src());
17161714 }
17171715
1716 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1717 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1718 const decl = self.code.decls[inst_data.payload_index];
1719 try stream.print("{s}) ", .{decl.name});
1720 try self.writeSrc(stream, inst_data.src());
1721 }
1722
17181723 fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void {
17191724 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
17201725 const extra = self.code.extraData(Inst.As, inst_data.payload_index).data;
......@@ -1736,15 +1741,6 @@ const Writer = struct {
17361741 try self.writeSrc(stream, src);
17371742 }
17381743
1739 fn writeDecl(
1740 self: *Writer,
1741 stream: anytype,
1742 inst: Inst.Index,
1743 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1744 const decl = self.code.instructions.items(.data)[inst].decl;
1745 try stream.print("{s})", .{decl.name});
1746 }
1747
17481744 fn writeStrTok(
17491745 self: *Writer,
17501746 stream: anytype,
test/stage2/test.zig+15-15
......@@ -1112,21 +1112,21 @@ pub fn addCases(ctx: *TestContext) !void {
11121112 });
11131113 }
11141114
1115 //{
1116 // var case = ctx.obj("extern variable has no type", linux_x64);
1117 // case.addError(
1118 // \\comptime {
1119 // \\ _ = foo;
1120 // \\}
1121 // \\extern var foo: i32;
1122 // , &[_][]const u8{":2:9: error: unable to resolve comptime value"});
1123 // case.addError(
1124 // \\export fn entry() void {
1125 // \\ _ = foo;
1126 // \\}
1127 // \\extern var foo;
1128 // , &[_][]const u8{":4:8: error: unable to infer variable type"});
1129 //}
1115 {
1116 var case = ctx.obj("extern variable has no type", linux_x64);
1117 case.addError(
1118 \\comptime {
1119 \\ _ = foo;
1120 \\}
1121 \\extern var foo: i32;
1122 , &[_][]const u8{":2:9: error: unable to resolve comptime value"});
1123 case.addError(
1124 \\export fn entry() void {
1125 \\ _ = foo;
1126 \\}
1127 \\extern var foo;
1128 , &[_][]const u8{":4:8: error: unable to infer variable type"});
1129 }
11301130
11311131 //{
11321132 // var case = ctx.exe("break/continue", linux_x64);