| author | |
| committer | |
| log | 6294c1136cb44285156c04f9f89f62b0f9e8e471 |
| tree | 241f9488c7b45faa096fb87f4f06d3c1fc0495f1 |
| parent | 0268f54fcfbb8a1c9f258b0d6f9c2a87ab597531 |
| signature |
2 files changed, 47 insertions(+), 2 deletions(-)
src/astgen.zig+28-1| ... | ... | @@ -489,7 +489,6 @@ fn varDecl( |
| 489 | 489 | node: *ast.Node.VarDecl, |
| 490 | 490 | block_arena: *Allocator, |
| 491 | 491 | ) InnerError!*Scope { |
| 492 | // TODO implement detection of shadowing | |
| 493 | 492 | if (node.getComptimeToken()) |comptime_token| { |
| 494 | 493 | return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{}); |
| 495 | 494 | } |
| ... | ... | @@ -499,6 +498,34 @@ fn varDecl( |
| 499 | 498 | const tree = scope.tree(); |
| 500 | 499 | const name_src = tree.token_locs[node.name_token].start; |
| 501 | 500 | const ident_name = try identifierTokenString(mod, scope, node.name_token); |
| 501 | ||
| 502 | // Local variables shadowing detection, including function parameters. | |
| 503 | { | |
| 504 | var s = scope; | |
| 505 | while (true) switch (s.tag) { | |
| 506 | .local_val => { | |
| 507 | const local_val = s.cast(Scope.LocalVal).?; | |
| 508 | if (mem.eql(u8, local_val.name, ident_name)) { | |
| 509 | return mod.fail(scope, name_src, "redefinition of '{}'", .{ident_name}); | |
| 510 | } | |
| 511 | s = local_val.parent; | |
| 512 | }, | |
| 513 | .local_ptr => { | |
| 514 | const local_ptr = s.cast(Scope.LocalPtr).?; | |
| 515 | if (mem.eql(u8, local_ptr.name, ident_name)) { | |
| 516 | return mod.fail(scope, name_src, "redefinition of '{}'", .{ident_name}); | |
| 517 | } | |
| 518 | s = local_ptr.parent; | |
| 519 | }, | |
| 520 | .gen_zir => s = s.cast(Scope.GenZIR).?.parent, | |
| 521 | else => break, | |
| 522 | }; | |
| 523 | } | |
| 524 | ||
| 525 | // Namespace vars shadowing detection | |
| 526 | if (mod.lookupDeclName(scope, ident_name)) |_| { | |
| 527 | return mod.fail(scope, name_src, "redefinition of '{}'", .{ident_name}); | |
| 528 | } | |
| 502 | 529 | const init_node = node.getInitNode() orelse |
| 503 | 530 | return mod.fail(scope, name_src, "variables must be initialized", .{}); |
| 504 | 531 |
test/stage2/test.zig+19-1| ... | ... | @@ -830,7 +830,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 830 | 830 | // Character literals and multiline strings. |
| 831 | 831 | case.addCompareOutput( |
| 832 | 832 | \\export fn _start() noreturn { |
| 833 | \\ const ignore = | |
| 833 | \\ const ignore = | |
| 834 | 834 | \\ \\ cool thx |
| 835 | 835 | \\ \\ |
| 836 | 836 | \\ ; |
| ... | ... | @@ -1113,6 +1113,24 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1113 | 1113 | \\fn entry() void {} |
| 1114 | 1114 | , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); |
| 1115 | 1115 | |
| 1116 | { | |
| 1117 | var case = ctx.obj("variable shadowing", linux_x64); | |
| 1118 | case.addError( | |
| 1119 | \\export fn _start() noreturn { | |
| 1120 | \\ var i: u32 = 10; | |
| 1121 | \\ var i: u32 = 10; | |
| 1122 | \\ unreachable; | |
| 1123 | \\} | |
| 1124 | , &[_][]const u8{":3:9: error: redefinition of 'i'"}); | |
| 1125 | case.addError( | |
| 1126 | \\var testing: i64 = 10; | |
| 1127 | \\export fn _start() noreturn { | |
| 1128 | \\ var testing: i64 = 20; | |
| 1129 | \\ unreachable; | |
| 1130 | \\} | |
| 1131 | , &[_][]const u8{":3:9: error: redefinition of 'testing'"}); | |
| 1132 | } | |
| 1133 | ||
| 1116 | 1134 | { |
| 1117 | 1135 | var case = ctx.obj("extern variable has no type", linux_x64); |
| 1118 | 1136 | case.addError( |