authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-28 15:15:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-28 16:04:38-07:00
log4bb5d17edc85eac74626224810d6a44a3c73cca3
tree1464b91474019c5c047ba66bae7197fa7e6d73bf
parent05cf44933d753f7a5a53ab289ea60fd43761de57

AstGen: pre-scan all decls in a namespace

Also: * improve the "ambiguous reference" error by swapping the order of "declared here" and "also declared here" notes. * improve the "not accessible from inner function" error: - point out that it has to do with the thing being mutable - eliminate the incorrect association with it being a function - note where it crosses a namespace boundary * struct field types are evaluated in a context that has the struct namespace visible. Likewise with align expressions, linksection expressions, enum tag values, and union/enum tag argument expressions. Closes #9194 Closes #9622

6 files changed, 183 insertions(+), 141 deletions(-)

src/AstGen.zig+146-133
......@@ -2883,8 +2883,6 @@ fn fnDecl(
28832883 };
28842884 const fn_name_str_index = try astgen.identAsString(fn_name_token);
28852885
2886 try astgen.declareNewName(scope, fn_name_str_index, decl_node, fn_name_token);
2887
28882886 // We insert this at the beginning so that its instruction index marks the
28892887 // start of the top level declaration.
28902888 const block_inst = try gz.addBlock(.block_inline, fn_proto.ast.proto_node);
......@@ -3153,8 +3151,6 @@ fn globalVarDecl(
31533151 const name_token = var_decl.ast.mut_token + 1;
31543152 const name_str_index = try astgen.identAsString(name_token);
31553153
3156 try astgen.declareNewName(scope, name_str_index, node, name_token);
3157
31583154 var block_scope: GenZir = .{
31593155 .parent = scope,
31603156 .decl_node_index = node,
......@@ -3509,9 +3505,11 @@ fn structDeclInner(
35093505 };
35103506 defer block_scope.instructions.deinit(gpa);
35113507
3512 var namespace: Scope.Namespace = .{ .parent = scope };
3508 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
35133509 defer namespace.decls.deinit(gpa);
35143510
3511 try astgen.scanDecls(&namespace, container_decl.ast.members);
3512
35153513 var wip_decls: WipDecls = .{};
35163514 defer wip_decls.deinit(gpa);
35173515
......@@ -3671,7 +3669,7 @@ fn structDeclInner(
36713669 const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype")
36723670 .none
36733671 else
3674 try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr);
3672 try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
36753673 fields_data.appendAssumeCapacity(@enumToInt(field_type));
36763674
36773675 known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr);
......@@ -3687,13 +3685,13 @@ fn structDeclInner(
36873685 (@as(u32, @boolToInt(unused)) << 31);
36883686
36893687 if (have_align) {
3690 const align_inst = try expr(&block_scope, &block_scope.base, align_rl, member.ast.align_expr);
3688 const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr);
36913689 fields_data.appendAssumeCapacity(@enumToInt(align_inst));
36923690 }
36933691 if (have_value) {
36943692 const rl: ResultLoc = if (field_type == .none) .none else .{ .ty = field_type };
36953693
3696 const default_inst = try expr(&block_scope, &block_scope.base, rl, member.ast.value_expr);
3694 const default_inst = try expr(&block_scope, &namespace.base, rl, member.ast.value_expr);
36973695 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
36983696 } else if (member.comptime_token) |comptime_token| {
36993697 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
......@@ -3756,7 +3754,7 @@ fn unionDeclInner(
37563754 node: ast.Node.Index,
37573755 members: []const ast.Node.Index,
37583756 layout: std.builtin.TypeInfo.ContainerLayout,
3759 arg_inst: Zir.Inst.Ref,
3757 arg_node: ast.Node.Index,
37603758 have_auto_enum: bool,
37613759) InnerError!Zir.Inst.Ref {
37623760 const astgen = gz.astgen;
......@@ -3778,9 +3776,16 @@ fn unionDeclInner(
37783776 };
37793777 defer block_scope.instructions.deinit(gpa);
37803778
3781 var namespace: Scope.Namespace = .{ .parent = scope };
3779 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
37823780 defer namespace.decls.deinit(gpa);
37833781
3782 try astgen.scanDecls(&namespace, members);
3783
3784 const arg_inst: Zir.Inst.Ref = if (arg_node != 0)
3785 try typeExpr(gz, &namespace.base, arg_node)
3786 else
3787 .none;
3788
37843789 var wip_decls: WipDecls = .{};
37853790 defer wip_decls.deinit(gpa);
37863791
......@@ -3946,7 +3951,7 @@ fn unionDeclInner(
39463951 (@as(u32, @boolToInt(unused)) << 31);
39473952
39483953 if (have_type and node_tags[member.ast.type_expr] != .@"anytype") {
3949 const field_type = try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr);
3954 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
39503955 fields_data.appendAssumeCapacity(@enumToInt(field_type));
39513956 }
39523957 if (have_align) {
......@@ -4046,11 +4051,6 @@ fn containerDecl(
40464051 // We must not create any types until Sema. Here the goal is only to generate
40474052 // ZIR for all the field types, alignments, and default value expressions.
40484053
4049 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
4050 try comptimeExpr(gz, scope, .{ .ty = .type_type }, container_decl.ast.arg)
4051 else
4052 .none;
4053
40544054 switch (token_tags[container_decl.ast.main_token]) {
40554055 .keyword_struct => {
40564056 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) {
......@@ -4059,7 +4059,7 @@ fn containerDecl(
40594059 else => unreachable,
40604060 } else std.builtin.TypeInfo.ContainerLayout.Auto;
40614061
4062 assert(arg_inst == .none);
4062 assert(container_decl.ast.arg == 0);
40634063
40644064 const result = try structDeclInner(gz, scope, node, container_decl, layout);
40654065 return rvalue(gz, rl, result, node);
......@@ -4073,7 +4073,7 @@ fn containerDecl(
40734073
40744074 const have_auto_enum = container_decl.ast.enum_token != null;
40754075
4076 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, arg_inst, have_auto_enum);
4076 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, have_auto_enum);
40774077 return rvalue(gz, rl, result, node);
40784078 },
40794079 .keyword_enum => {
......@@ -4140,7 +4140,7 @@ fn containerDecl(
41404140 }
41414141 total_fields += 1;
41424142 if (member.ast.value_expr != 0) {
4143 if (arg_inst == .none) {
4143 if (container_decl.ast.arg == 0) {
41444144 return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{});
41454145 }
41464146 values += 1;
......@@ -4159,7 +4159,7 @@ fn containerDecl(
41594159 // must be at least one tag.
41604160 return astgen.failNode(node, "enum declarations must have at least one tag", .{});
41614161 }
4162 if (counts.nonexhaustive_node != 0 and arg_inst == .none) {
4162 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
41634163 return astgen.failNodeNotes(
41644164 node,
41654165 "non-exhaustive enum missing integer tag type",
......@@ -4189,9 +4189,16 @@ fn containerDecl(
41894189 };
41904190 defer block_scope.instructions.deinit(gpa);
41914191
4192 var namespace: Scope.Namespace = .{ .parent = scope };
4192 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
41934193 defer namespace.decls.deinit(gpa);
41944194
4195 try astgen.scanDecls(&namespace, container_decl.ast.members);
4196
4197 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
4198 try comptimeExpr(gz, &namespace.base, .{ .ty = .type_type }, container_decl.ast.arg)
4199 else
4200 .none;
4201
41954202 var wip_decls: WipDecls = .{};
41964203 defer wip_decls.deinit(gpa);
41974204
......@@ -4364,7 +4371,7 @@ fn containerDecl(
43644371 },
43654372 );
43664373 }
4367 const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr);
4374 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .ty = arg_inst }, member.ast.value_expr);
43684375 fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst));
43694376 }
43704377
......@@ -4416,9 +4423,13 @@ fn containerDecl(
44164423 return rvalue(gz, rl, indexToRef(decl_inst), node);
44174424 },
44184425 .keyword_opaque => {
4419 var namespace: Scope.Namespace = .{ .parent = scope };
4426 assert(container_decl.ast.arg == 0);
4427
4428 var namespace: Scope.Namespace = .{ .parent = scope, .node = node };
44204429 defer namespace.decls.deinit(gpa);
44214430
4431 try astgen.scanDecls(&namespace, container_decl.ast.members);
4432
44224433 var wip_decls: WipDecls = .{};
44234434 defer wip_decls.deinit(gpa);
44244435
......@@ -6352,73 +6363,68 @@ fn identifier(
63526363
63536364 // Local variables, including function parameters.
63546365 const name_str_index = try astgen.identAsString(ident_token);
6355 {
6356 var s = scope;
6357 var found_already: ?ast.Node.Index = null; // we have found a decl with the same name already
6358 var hit_namespace = false;
6359 while (true) switch (s.tag) {
6360 .local_val => {
6361 const local_val = s.cast(Scope.LocalVal).?;
6362
6363 if (local_val.name == name_str_index) {
6364 local_val.used = true;
6365 // Captures of non-locals need to be emitted as decl_val or decl_ref.
6366 // This *might* be capturable depending on if it is comptime known.
6367 if (!hit_namespace) {
6368 return rvalue(gz, rl, local_val.inst, ident);
6369 }
6370 }
6371 s = local_val.parent;
6372 },
6373 .local_ptr => {
6374 const local_ptr = s.cast(Scope.LocalPtr).?;
6375 if (local_ptr.name == name_str_index) {
6376 local_ptr.used = true;
6377 if (hit_namespace) {
6378 if (local_ptr.maybe_comptime)
6379 break
6380 else
6381 return astgen.failNodeNotes(ident, "'{s}' not accessible from inner function", .{ident_name}, &.{
6382 try astgen.errNoteTok(local_ptr.token_src, "declared here", .{}),
6383 // TODO add crossed function definition here note.
6384 // Maybe add a note to the error about it being because of the var,
6385 // maybe recommend copying it into a const variable. -SpexGuy
6386 });
6387 }
6388 switch (rl) {
6389 .ref, .none_or_ref => return local_ptr.ptr,
6390 else => {
6391 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
6392 return rvalue(gz, rl, loaded, ident);
6393 },
6394 }
6366 var s = scope;
6367 var found_already: ?ast.Node.Index = null; // we have found a decl with the same name already
6368 var hit_namespace: ast.Node.Index = 0;
6369 while (true) switch (s.tag) {
6370 .local_val => {
6371 const local_val = s.cast(Scope.LocalVal).?;
6372
6373 if (local_val.name == name_str_index) {
6374 local_val.used = true;
6375 // Captures of non-locals need to be emitted as decl_val or decl_ref.
6376 // This *might* be capturable depending on if it is comptime known.
6377 if (hit_namespace == 0) {
6378 return rvalue(gz, rl, local_val.inst, ident);
63956379 }
6396 s = local_ptr.parent;
6397 },
6398 .gen_zir => s = s.cast(GenZir).?.parent,
6399 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
6400 // look for ambiguous references to decls
6401 .namespace => {
6402 const ns = s.cast(Scope.Namespace).?;
6403 if (ns.decls.get(name_str_index)) |i| {
6404 if (found_already) |f|
6405 return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{
6406 try astgen.errNoteNode(i, "declared here", .{}),
6407 try astgen.errNoteNode(f, "also declared here", .{}),
6408 })
6380 }
6381 s = local_val.parent;
6382 },
6383 .local_ptr => {
6384 const local_ptr = s.cast(Scope.LocalPtr).?;
6385 if (local_ptr.name == name_str_index) {
6386 local_ptr.used = true;
6387 if (hit_namespace != 0) {
6388 if (local_ptr.maybe_comptime)
6389 break
64096390 else
6410 found_already = i;
6391 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{
6392 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}),
6393 try astgen.errNoteNode(hit_namespace, "crosses namespace boundary here", .{}),
6394 });
64116395 }
6412 hit_namespace = true;
6413 s = ns.parent;
6414 },
6415 .top => break,
6416 };
6417 }
6396 switch (rl) {
6397 .ref, .none_or_ref => return local_ptr.ptr,
6398 else => {
6399 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
6400 return rvalue(gz, rl, loaded, ident);
6401 },
6402 }
6403 }
6404 s = local_ptr.parent;
6405 },
6406 .gen_zir => s = s.cast(GenZir).?.parent,
6407 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
6408 .namespace => {
6409 const ns = s.cast(Scope.Namespace).?;
6410 if (ns.decls.get(name_str_index)) |i| {
6411 if (found_already) |f| {
6412 return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{
6413 try astgen.errNoteNode(f, "declared here", .{}),
6414 try astgen.errNoteNode(i, "also declared here", .{}),
6415 });
6416 }
6417 // We found a match but must continue looking for ambiguous references to decls.
6418 found_already = i;
6419 }
6420 hit_namespace = ns.node;
6421 s = ns.parent;
6422 },
6423 .top => break,
6424 };
64186425
6419 // We can't look up Decls until Sema because the same ZIR code is supposed to be
6420 // used for multiple generic instantiations, and this may refer to a different Decl
6421 // depending on the scope, determined by the generic instantiation.
6426 // Decl references happen by name rather than ZIR index so that when unrelated
6427 // decls are modified, ZIR code containing references to them can be unmodified.
64226428 switch (rl) {
64236429 .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
64246430 else => {
......@@ -8941,6 +8947,7 @@ const Scope = struct {
89418947 /// Maps string table index to the source location of declaration,
89428948 /// for the purposes of reporting name shadowing compile errors.
89438949 decls: std.AutoHashMapUnmanaged(u32, ast.Node.Index) = .{},
8950 node: ast.Node.Index,
89448951 };
89458952
89468953 const Top = struct {
......@@ -10014,53 +10021,6 @@ fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 {
1001410021 return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index;
1001510022}
1001610023
10017fn declareNewName(
10018 astgen: *AstGen,
10019 start_scope: *Scope,
10020 name_index: u32,
10021 node: ast.Node.Index,
10022 name_token: ast.TokenIndex,
10023) !void {
10024 const gpa = astgen.gpa;
10025
10026 const token_bytes = astgen.tree.tokenSlice(name_token);
10027 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) {
10028 return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{
10029 token_bytes,
10030 }, &[_]u32{
10031 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{
10032 token_bytes,
10033 }),
10034 });
10035 }
10036
10037 var scope = start_scope;
10038 while (true) {
10039 switch (scope.tag) {
10040 .gen_zir => scope = scope.cast(GenZir).?.parent,
10041 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
10042 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
10043 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
10044 .namespace => {
10045 const ns = scope.cast(Scope.Namespace).?;
10046 const gop = try ns.decls.getOrPut(gpa, name_index);
10047 if (gop.found_existing) {
10048 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_index)));
10049 defer gpa.free(name);
10050 return astgen.failNodeNotes(node, "redeclaration of '{s}'", .{
10051 name,
10052 }, &[_]u32{
10053 try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}),
10054 });
10055 }
10056 gop.value_ptr.* = node;
10057 break;
10058 },
10059 .top => break,
10060 }
10061 }
10062}
10063
1006410024fn isPrimitive(name: []const u8) bool {
1006510025 if (simple_types.get(name) != null) return true;
1006610026 if (name.len < 2) return false;
......@@ -10183,3 +10143,56 @@ fn refToIndex(inst: Zir.Inst.Ref) ?Zir.Inst.Index {
1018310143 return null;
1018410144 }
1018510145}
10146
10147fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const ast.Node.Index) !void {
10148 const gpa = astgen.gpa;
10149 const tree = astgen.tree;
10150 const node_tags = tree.nodes.items(.tag);
10151 const main_tokens = tree.nodes.items(.main_token);
10152 for (members) |member_node| {
10153 const name_token = switch (node_tags[member_node]) {
10154 .fn_decl,
10155 .fn_proto_simple,
10156 .fn_proto_multi,
10157 .fn_proto_one,
10158 .fn_proto,
10159 .global_var_decl,
10160 .local_var_decl,
10161 .simple_var_decl,
10162 .aligned_var_decl,
10163 => main_tokens[member_node] + 1,
10164
10165 else => continue,
10166 };
10167
10168 const token_bytes = astgen.tree.tokenSlice(name_token);
10169 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) {
10170 switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{
10171 token_bytes,
10172 }, &[_]u32{
10173 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{
10174 token_bytes,
10175 }),
10176 })) {
10177 error.AnalysisFail => continue,
10178 error.OutOfMemory => return error.OutOfMemory,
10179 }
10180 }
10181
10182 const name_str_index = try astgen.identAsString(name_token);
10183 const gop = try namespace.decls.getOrPut(gpa, name_str_index);
10184 if (gop.found_existing) {
10185 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index)));
10186 defer gpa.free(name);
10187 switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{
10188 name,
10189 }, &[_]u32{
10190 try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}),
10191 })) {
10192 error.AnalysisFail => continue,
10193 error.OutOfMemory => return error.OutOfMemory,
10194 }
10195 }
10196 gop.value_ptr.* = member_node;
10197 }
10198}
src/Module.zig+4-1
......@@ -2648,7 +2648,10 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
26482648 undefined;
26492649 defer if (data_has_safety_tag) gpa.free(safety_buffer);
26502650 const data_ptr = if (data_has_safety_tag)
2651 @ptrCast([*]const u8, safety_buffer.ptr)
2651 if (file.zir.instructions.len == 0)
2652 @as([*]const u8, undefined)
2653 else
2654 @ptrCast([*]const u8, safety_buffer.ptr)
26522655 else
26532656 @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr);
26542657 if (data_has_safety_tag) {
test/behavior/generics.zig+2-1
......@@ -91,7 +91,8 @@ test "type constructed by comptime function call" {
9191}
9292
9393fn SimpleList(comptime L: usize) type {
94 var T = u8;
94 var mutable_T = u8;
95 const T = mutable_T;
9596 return struct {
9697 array: [L]T,
9798 };
test/behavior/misc.zig+2-2
......@@ -506,7 +506,7 @@ test "lazy typeInfo value as generic parameter" {
506506 S.foo(@typeInfo(@TypeOf(.{})));
507507}
508508
509fn A() type {
509fn ZA() type {
510510 return struct {
511511 b: B(),
512512
......@@ -520,7 +520,7 @@ fn A() type {
520520 };
521521}
522522test "non-ambiguous reference of shadowed decls" {
523 try expect(A().B().Self != A().Self);
523 try expect(ZA().B().Self != ZA().Self);
524524}
525525
526526test "use of declaration with same name as primitive" {
test/cases.zig+5-4
......@@ -984,8 +984,8 @@ pub fn addCases(ctx: *TestContext) !void {
984984 \\};
985985 , &.{
986986 ":4:17: error: ambiguous reference",
987 ":1:1: note: declared here",
988 ":2:5: note: also declared here",
987 ":2:5: note: declared here",
988 ":1:1: note: also declared here",
989989 });
990990
991991 ctx.compileError("inner func accessing outer var", linux_x64,
......@@ -999,8 +999,9 @@ pub fn addCases(ctx: *TestContext) !void {
999999 \\ _ = S;
10001000 \\}
10011001 , &.{
1002 ":5:20: error: 'bar' not accessible from inner function",
1003 ":2:9: note: declared here",
1002 ":5:20: error: mutable 'bar' not accessible from here",
1003 ":2:9: note: declared mutable here",
1004 ":3:15: note: crosses namespace boundary here",
10041005 });
10051006
10061007 ctx.compileError("global variable redeclaration", linux_x64,
test/compile_errors.zig+24
......@@ -5342,6 +5342,17 @@ pub fn addCases(ctx: *TestContext) !void {
53425342 "tmp.zig:2:1: note: declared here",
53435343 });
53445344
5345 ctx.objErrStage1("local shadows global that occurs later",
5346 \\pub fn main() void {
5347 \\ var foo = true;
5348 \\ _ = foo;
5349 \\}
5350 \\fn foo() void {}
5351 , &[_][]const u8{
5352 "tmp.zig:2:9: error: local shadows declaration of 'foo'",
5353 "tmp.zig:5:1: note: declared here",
5354 });
5355
53455356 ctx.objErrStage1("switch expression - missing enumeration prong",
53465357 \\const Number = enum {
53475358 \\ One,
......@@ -8814,4 +8825,17 @@ pub fn addCases(ctx: *TestContext) !void {
88148825 , &[_][]const u8{
88158826 "error: Unsupported OS",
88168827 });
8828
8829 ctx.objErrStage1("attempt to close over comptime variable from outer scope",
8830 \\fn SimpleList(comptime L: usize) type {
8831 \\ var T = u8;
8832 \\ return struct {
8833 \\ array: [L]T,
8834 \\ };
8835 \\}
8836 , &[_][]const u8{
8837 "tmp.zig:4:19: error: mutable 'T' not accessible from here",
8838 "tmp.zig:2:9: note: declared mutable here",
8839 "tmp.zig:3:12: note: crosses namespace boundary here",
8840 });
88178841}