Commit 29ae6515f3
Changed files (16)
src
test
cases
compile_errors
doc/langref.html.in
@@ -4064,7 +4064,7 @@ test "labeled break from labeled block expression" {
{#header_open|Shadowing#}
<p>{#link|Identifiers#} are never allowed to "hide" other identifiers by using the same name:</p>
- {#code_begin|test_err|local shadows declaration#}
+ {#code_begin|test_err|local variable shadows declaration#}
const pi = 3.14;
test "inside test block" {
src/AstGen.zig
@@ -2004,7 +2004,8 @@ fn blockExpr(
return labeledBlockExpr(gz, scope, rl, block_node, statements);
}
- try blockExprStmts(gz, scope, statements);
+ var sub_gz = gz.makeSubBlock(scope);
+ try blockExprStmts(&sub_gz, &sub_gz.base, statements);
return rvalue(gz, rl, .void_value, block_node);
}
@@ -2772,7 +2773,13 @@ fn varDecl(
}
const ident_name = try astgen.identAsString(name_token);
- try astgen.detectLocalShadowing(scope, ident_name, name_token, ident_name_raw);
+ try astgen.detectLocalShadowing(
+ scope,
+ ident_name,
+ name_token,
+ ident_name_raw,
+ if (token_tags[var_decl.ast.mut_token] == .keyword_const) .@"local constant" else .@"local variable",
+ );
if (var_decl.ast.init_node == 0) {
return astgen.failNode(node, "variables must be initialized", .{});
@@ -3502,7 +3509,7 @@ fn fnDecl(
const param_name = try astgen.identAsString(name_token);
if (!is_extern) {
- try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes);
+ try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes, .@"function parameter");
}
break :blk param_name;
} else if (!is_extern) {
@@ -5181,7 +5188,7 @@ fn orelseCatchExpr(
}
const err_name = try astgen.identAsString(payload);
- try astgen.detectLocalShadowing(scope, err_name, payload, err_str);
+ try astgen.detectLocalShadowing(scope, err_name, payload, err_str, .@"capture");
err_val_scope = .{
.parent = &else_scope.base,
@@ -5480,7 +5487,7 @@ fn ifExpr(
const token_name_str = tree.tokenSlice(token_name_index);
if (mem.eql(u8, "_", token_name_str))
break :s &then_scope.base;
- try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index, token_name_str);
+ try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index, token_name_str, .@"capture");
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -5505,7 +5512,7 @@ fn ifExpr(
break :s &then_scope.base;
const payload_inst = try then_scope.addUnNode(tag, cond.inst, if_full.ast.then_expr);
const ident_name = try astgen.identAsString(ident_token);
- try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes);
+ try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes, .@"capture");
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -5551,7 +5558,7 @@ fn ifExpr(
const error_token_str = tree.tokenSlice(error_token);
if (mem.eql(u8, "_", error_token_str))
break :s &else_scope.base;
- try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, error_token_str);
+ try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, error_token_str, .@"capture");
payload_val_scope = .{
.parent = &else_scope.base,
.gen_zir = &else_scope,
@@ -5816,7 +5823,7 @@ fn whileExpr(
break :s &then_scope.base;
const payload_name_loc = payload_token + @boolToInt(payload_is_ref);
const ident_name = try astgen.identAsString(payload_name_loc);
- try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc, ident_bytes);
+ try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc, ident_bytes, .@"capture");
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -5843,7 +5850,7 @@ fn whileExpr(
const ident_bytes = tree.tokenSlice(ident_token);
if (mem.eql(u8, "_", ident_bytes))
break :s &then_scope.base;
- try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes);
+ try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes, .@"capture");
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -5919,7 +5926,7 @@ fn whileExpr(
const ident_bytes = tree.tokenSlice(error_token);
if (mem.eql(u8, ident_bytes, "_"))
break :s &else_scope.base;
- try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, ident_bytes);
+ try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, ident_bytes, .@"capture");
payload_val_scope = .{
.parent = &else_scope.base,
.gen_zir = &else_scope,
@@ -6092,7 +6099,7 @@ fn forExpr(
.lhs = array_ptr,
.rhs = index,
});
- try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name);
+ try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .@"capture");
payload_val_scope = .{
.parent = &then_scope.base,
.gen_zir = &then_scope,
@@ -6118,7 +6125,7 @@ fn forExpr(
return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});
}
const index_name = try astgen.identAsString(index_token);
- try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes);
+ try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture");
index_scope = .{
.parent = payload_sub_scope,
.gen_zir = &then_scope,
@@ -6433,7 +6440,7 @@ fn switchExpr(
});
}
const capture_name = try astgen.identAsString(ident);
- try astgen.detectLocalShadowing(&case_scope.base, capture_name, ident, ident_slice);
+ try astgen.detectLocalShadowing(&case_scope.base, capture_name, ident, ident_slice, .@"capture");
capture_val_scope = .{
.parent = &case_scope.base,
.gen_zir = &case_scope,
@@ -6458,7 +6465,7 @@ fn switchExpr(
return astgen.failTok(tag_token, "tag capture on non-inline prong", .{});
}
const tag_name = try astgen.identAsString(tag_token);
- try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice);
+ try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");
tag_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
try astgen.instructions.append(gpa, .{
.tag = .switch_capture_tag,
@@ -11669,6 +11676,7 @@ fn detectLocalShadowing(
ident_name: u32,
name_token: Ast.TokenIndex,
token_bytes: []const u8,
+ id_cat: Scope.IdCat,
) !void {
const gpa = astgen.gpa;
if (token_bytes[0] != '@' and isPrimitive(token_bytes)) {
@@ -11682,6 +11690,7 @@ fn detectLocalShadowing(
}
var s = scope;
+ var outer_scope = false;
while (true) switch (s.tag) {
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
@@ -11689,6 +11698,17 @@ fn detectLocalShadowing(
const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
const name = try gpa.dupe(u8, name_slice);
defer gpa.free(name);
+ if (outer_scope) {
+ return astgen.failTokNotes(name_token, "{s} '{s}' shadows {s} from outer scope", .{
+ @tagName(id_cat), name, @tagName(local_val.id_cat),
+ }, &[_]u32{
+ try astgen.errNoteTok(
+ local_val.token_src,
+ "previous declaration here",
+ .{},
+ ),
+ });
+ }
return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
@tagName(local_val.id_cat), name,
}, &[_]u32{
@@ -11707,6 +11727,17 @@ fn detectLocalShadowing(
const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
const name = try gpa.dupe(u8, name_slice);
defer gpa.free(name);
+ if (outer_scope) {
+ return astgen.failTokNotes(name_token, "{s} '{s}' shadows {s} from outer scope", .{
+ @tagName(id_cat), name, @tagName(local_ptr.id_cat),
+ }, &[_]u32{
+ try astgen.errNoteTok(
+ local_ptr.token_src,
+ "previous declaration here",
+ .{},
+ ),
+ });
+ }
return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
@tagName(local_ptr.id_cat), name,
}, &[_]u32{
@@ -11720,6 +11751,7 @@ fn detectLocalShadowing(
s = local_ptr.parent;
},
.namespace => {
+ outer_scope = true;
const ns = s.cast(Scope.Namespace).?;
const decl_node = ns.decls.get(ident_name) orelse {
s = ns.parent;
@@ -11728,13 +11760,16 @@ fn detectLocalShadowing(
const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
const name = try gpa.dupe(u8, name_slice);
defer gpa.free(name);
- return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{
- name,
+ return astgen.failTokNotes(name_token, "{s} shadows declaration of '{s}'", .{
+ @tagName(id_cat), name,
}, &[_]u32{
try astgen.errNoteNode(decl_node, "declared here", .{}),
});
},
- .gen_zir => s = s.cast(GenZir).?.parent,
+ .gen_zir => {
+ s = s.cast(GenZir).?.parent;
+ outer_scope = true;
+ },
.defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
.top => break,
};
@@ -11844,8 +11879,8 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
if (local_val.name == name_str_index) {
- return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
- @tagName(local_val.id_cat), token_bytes,
+ return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{
+ token_bytes, @tagName(local_val.id_cat),
}, &[_]u32{
try astgen.errNoteTok(
local_val.token_src,
@@ -11859,8 +11894,8 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
if (local_ptr.name == name_str_index) {
- return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
- @tagName(local_ptr.id_cat), token_bytes,
+ return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{
+ token_bytes, @tagName(local_ptr.id_cat),
}, &[_]u32{
try astgen.errNoteTok(
local_ptr.token_src,
test/cases/compile_errors/decl_shadows_local.zig
@@ -16,7 +16,7 @@ fn bar(a: usize) void {
// backend=stage2
// target=native
//
-// :3:15: error: redeclaration of function parameter 'a'
+// :3:15: error: declaration 'a' shadows function parameter from outer scope
// :1:8: note: previous declaration here
-// :9:19: error: redeclaration of function parameter 'a'
+// :9:19: error: declaration 'a' shadows function parameter from outer scope
// :6:8: note: previous declaration here
test/cases/compile_errors/local_shadows_global_that_occurs_later.zig
@@ -8,5 +8,5 @@ fn foo() void {}
// backend=stage2
// target=native
//
-// :2:9: error: local shadows declaration of 'foo'
+// :2:9: error: local variable shadows declaration of 'foo'
// :5:1: note: declared here
test/cases/compile_errors/local_variable_redeclares_parameter.zig
@@ -7,5 +7,5 @@ export fn entry() void { f(1); }
// backend=stage2
// target=native
//
-// :2:11: error: redeclaration of function parameter 'a'
+// :2:11: error: local constant 'a' shadows function parameter from outer scope
// :1:6: note: previous declaration here
test/cases/compile_errors/local_variable_shadowing_global.zig
@@ -10,5 +10,5 @@ export fn entry() void {
// backend=stage2
// target=native
//
-// :5:9: error: local shadows declaration of 'Bar'
+// :5:9: error: local variable shadows declaration of 'Bar'
// :2:1: note: declared here
test/cases/compile_errors/parameter_shadowing_global.zig
@@ -8,5 +8,5 @@ export fn entry() void {
// backend=stage2
// target=native
//
-// :2:6: error: local shadows declaration of 'Foo'
+// :2:6: error: function parameter shadows declaration of 'Foo'
// :1:1: note: declared here
test/cases/function_redeclaration.zig
@@ -10,5 +10,5 @@ fn foo() void {
//
// :3:1: error: redeclaration of 'entry'
// :2:1: note: other declaration here
-// :6:9: error: local shadows declaration of 'foo'
+// :6:9: error: local variable shadows declaration of 'foo'
// :5:1: note: declared here
test/cases/variable_shadowing.1.zig
@@ -5,5 +5,5 @@ pub fn main() void {
// error
//
-// :3:9: error: local shadows declaration of 'testing'
+// :3:9: error: local variable shadows declaration of 'testing'
// :1:1: note: declared here
test/cases/variable_shadowing.3.zig
@@ -6,5 +6,5 @@ pub fn main() void {
// error
//
-// :3:19: error: redeclaration of local variable 'i'
+// :3:19: error: loop index capture 'i' shadows local variable from outer scope
// :2:9: note: previous declaration here
test/cases/variable_shadowing.4.zig
@@ -6,5 +6,5 @@ pub fn main() void {
// error
//
-// :3:16: error: redeclaration of local variable 'i'
+// :3:16: error: capture 'i' shadows local variable from outer scope
// :2:9: note: previous declaration here
test/cases/variable_shadowing.5.zig
@@ -6,5 +6,5 @@ pub fn main() void {
// error
//
-// :3:18: error: redeclaration of local variable 'i'
+// :3:18: error: capture 'i' shadows local variable from outer scope
// :2:9: note: previous declaration here
test/cases/variable_shadowing.6.zig
@@ -9,5 +9,5 @@ pub fn main() void {
// error
//
-// :5:13: error: redeclaration of local variable 'i'
+// :5:13: error: capture 'i' shadows local variable from outer scope
// :2:9: note: previous declaration here
test/cases/variable_shadowing.7.zig
@@ -5,5 +5,5 @@ pub fn main() void {
// error
//
-// :3:16: error: redeclaration of local variable 'i'
+// :3:16: error: capture 'i' shadows local variable from outer scope
// :2:9: note: previous declaration here
test/cases/variable_shadowing.8.zig
@@ -5,5 +5,5 @@ pub fn main() void {
// error
//
-// :3:16: error: redeclaration of local variable 'i'
+// :3:16: error: capture 'i' shadows local variable from outer scope
// :2:9: note: previous declaration here
test/cases/variable_shadowing.9.zig
@@ -5,5 +5,5 @@ pub fn main() void {
// error
//
-// :3:28: error: redeclaration of local variable 'i'
+// :3:28: error: capture 'i' shadows local variable from outer scope
// :2:9: note: previous declaration here