| author | |
| committer | |
| log | 9c95f38a7c1defc7f63a4815bfc2d76a5f9f83f6 |
| tree | 3182a24f22da9da86b56d8894b4bd603e89e10e3 |
| parent | f1f28af1880a79bb2d7210d3a704c78698f0b45b |
Locals are not allowed to shadow declarations, but declarations are
allowed to shadow each other, as long as there are no ambiguous
references.
closes #6786 files changed, 67 insertions(+), 83 deletions(-)
src/stage1/analyze.cpp+4-39| ... | @@ -4171,46 +4171,11 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -4171,46 +4171,11 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 4171 | } else { | 4171 | } else { |
| 4172 | variable_entry->align_bytes = get_abi_alignment(g, var_type); | 4172 | variable_entry->align_bytes = get_abi_alignment(g, var_type); |
| 4173 | 4173 | ||
| 4174 | ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); | 4174 | ZigType *type; |
| 4175 | if (existing_var && !existing_var->shadowable) { | 4175 | if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { |
| 4176 | if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) { | 4176 | add_node_error(g, source_node, |
| 4177 | ErrorMsg *msg = add_node_error(g, source_node, | 4177 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); |
| 4178 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); | ||
| 4179 | add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration here")); | ||
| 4180 | } | ||
| 4181 | variable_entry->var_type = g->builtin_types.entry_invalid; | 4178 | variable_entry->var_type = g->builtin_types.entry_invalid; |
| 4182 | } else { | ||
| 4183 | ZigType *type; | ||
| 4184 | if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { | ||
| 4185 | add_node_error(g, source_node, | ||
| 4186 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); | ||
| 4187 | variable_entry->var_type = g->builtin_types.entry_invalid; | ||
| 4188 | } else { | ||
| 4189 | Scope *search_scope = nullptr; | ||
| 4190 | if (src_tld == nullptr) { | ||
| 4191 | search_scope = parent_scope; | ||
| 4192 | } else if (src_tld->parent_scope != nullptr && src_tld->parent_scope->parent != nullptr) { | ||
| 4193 | search_scope = src_tld->parent_scope->parent; | ||
| 4194 | } | ||
| 4195 | if (search_scope != nullptr) { | ||
| 4196 | Tld *tld = find_decl(g, search_scope, name); | ||
| 4197 | if (tld != nullptr && tld != src_tld) { | ||
| 4198 | bool want_err_msg = true; | ||
| 4199 | if (tld->id == TldIdVar) { | ||
| 4200 | ZigVar *var = reinterpret_cast<TldVar *>(tld)->var; | ||
| 4201 | if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { | ||
| 4202 | want_err_msg = false; | ||
| 4203 | } | ||
| 4204 | } | ||
| 4205 | if (want_err_msg) { | ||
| 4206 | ErrorMsg *msg = add_node_error(g, source_node, | ||
| 4207 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | ||
| 4208 | add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition here")); | ||
| 4209 | } | ||
| 4210 | variable_entry->var_type = g->builtin_types.entry_invalid; | ||
| 4211 | } | ||
| 4212 | } | ||
| 4213 | } | ||
| 4214 | } | 4179 | } |
| 4215 | } | 4180 | } |
| 4216 | 4181 |
src/stage1/astgen.cpp+25-18| ... | @@ -3200,23 +3200,6 @@ ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, | ... | @@ -3200,23 +3200,6 @@ ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, |
| 3200 | add_node_error(codegen, node, | 3200 | add_node_error(codegen, node, |
| 3201 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); | 3201 | buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); |
| 3202 | variable_entry->var_type = codegen->builtin_types.entry_invalid; | 3202 | variable_entry->var_type = codegen->builtin_types.entry_invalid; |
| 3203 | } else { | ||
| 3204 | Tld *tld = find_decl(codegen, parent_scope, name); | ||
| 3205 | if (tld != nullptr) { | ||
| 3206 | bool want_err_msg = true; | ||
| 3207 | if (tld->id == TldIdVar) { | ||
| 3208 | ZigVar *var = reinterpret_cast<TldVar *>(tld)->var; | ||
| 3209 | if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { | ||
| 3210 | want_err_msg = false; | ||
| 3211 | } | ||
| 3212 | } | ||
| 3213 | if (want_err_msg) { | ||
| 3214 | ErrorMsg *msg = add_node_error(codegen, node, | ||
| 3215 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | ||
| 3216 | add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition here")); | ||
| 3217 | } | ||
| 3218 | variable_entry->var_type = codegen->builtin_types.entry_invalid; | ||
| 3219 | } | ||
| 3220 | } | 3203 | } |
| 3221 | } | 3204 | } |
| 3222 | } | 3205 | } |
| ... | @@ -3875,7 +3858,31 @@ static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode | ... | @@ -3875,7 +3858,31 @@ static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode |
| 3875 | } | 3858 | } |
| 3876 | } | 3859 | } |
| 3877 | 3860 | ||
| 3878 | Tld *tld = find_decl(ag->codegen, scope, variable_name); | 3861 | Tld *tld = nullptr; |
| 3862 | { | ||
| 3863 | Scope *s = scope; | ||
| 3864 | while (s) { | ||
| 3865 | if (s->id == ScopeIdDecls) { | ||
| 3866 | ScopeDecls *decls_scope = (ScopeDecls *)s; | ||
| 3867 | |||
| 3868 | Tld *result = find_container_decl(ag->codegen, decls_scope, variable_name); | ||
| 3869 | if (result != nullptr) { | ||
| 3870 | if (tld != nullptr && tld != result) { | ||
| 3871 | ErrorMsg *msg = add_node_error(ag->codegen, node, | ||
| 3872 | buf_sprintf("ambiguous reference")); | ||
| 3873 | add_error_note(ag->codegen, msg, tld->source_node, | ||
| 3874 | buf_sprintf("declared here")); | ||
| 3875 | add_error_note(ag->codegen, msg, result->source_node, | ||
| 3876 | buf_sprintf("also declared here")); | ||
| 3877 | return ag->codegen->invalid_inst_src; | ||
| 3878 | } | ||
| 3879 | tld = result; | ||
| 3880 | } | ||
| 3881 | } | ||
| 3882 | s = s->parent; | ||
| 3883 | } | ||
| 3884 | } | ||
| 3885 | |||
| 3879 | if (tld) { | 3886 | if (tld) { |
| 3880 | Stage1ZirInst *decl_ref = ir_build_decl_ref(ag, scope, node, tld, lval); | 3887 | Stage1ZirInst *decl_ref = ir_build_decl_ref(ag, scope, node, tld, lval); |
| 3881 | if (lval == LValPtr || lval == LValAssign) { | 3888 | if (lval == LValPtr || lval == LValAssign) { |
test/behavior/error.zig+6-6| ... | @@ -412,19 +412,19 @@ test "function pointer with return type that is error union with payload which i | ... | @@ -412,19 +412,19 @@ test "function pointer with return type that is error union with payload which i |
| 412 | test "return result loc as peer result loc in inferred error set function" { | 412 | test "return result loc as peer result loc in inferred error set function" { |
| 413 | const S = struct { | 413 | const S = struct { |
| 414 | fn doTheTest() !void { | 414 | fn doTheTest() !void { |
| 415 | if (foo(2)) |x| { | 415 | if (quux(2)) |x| { |
| 416 | try expect(x.Two); | 416 | try expect(x.Two); |
| 417 | } else |e| switch (e) { | 417 | } else |e| switch (e) { |
| 418 | error.Whatever => @panic("fail"), | 418 | error.Whatever => @panic("fail"), |
| 419 | } | 419 | } |
| 420 | try expectError(error.Whatever, foo(99)); | 420 | try expectError(error.Whatever, quux(99)); |
| 421 | } | 421 | } |
| 422 | const FormValue = union(enum) { | 422 | const FormValue = union(enum) { |
| 423 | One: void, | 423 | One: void, |
| 424 | Two: bool, | 424 | Two: bool, |
| 425 | }; | 425 | }; |
| 426 | 426 | ||
| 427 | fn foo(id: u64) !FormValue { | 427 | fn quux(id: u64) !FormValue { |
| 428 | return switch (id) { | 428 | return switch (id) { |
| 429 | 2 => FormValue{ .Two = true }, | 429 | 2 => FormValue{ .Two = true }, |
| 430 | 1 => FormValue{ .One = {} }, | 430 | 1 => FormValue{ .One = {} }, |
| ... | @@ -452,11 +452,11 @@ test "error payload type is correctly resolved" { | ... | @@ -452,11 +452,11 @@ test "error payload type is correctly resolved" { |
| 452 | 452 | ||
| 453 | test "error union comptime caching" { | 453 | test "error union comptime caching" { |
| 454 | const S = struct { | 454 | const S = struct { |
| 455 | fn foo(comptime arg: anytype) void { | 455 | fn quux(comptime arg: anytype) void { |
| 456 | arg catch {}; | 456 | arg catch {}; |
| 457 | } | 457 | } |
| 458 | }; | 458 | }; |
| 459 | 459 | ||
| 460 | S.foo(@as(anyerror!void, {})); | 460 | S.quux(@as(anyerror!void, {})); |
| 461 | S.foo(@as(anyerror!void, {})); | 461 | S.quux(@as(anyerror!void, {})); |
| 462 | } | 462 | } |
test/behavior/misc.zig+17| ... | @@ -505,3 +505,20 @@ test "lazy typeInfo value as generic parameter" { | ... | @@ -505,3 +505,20 @@ test "lazy typeInfo value as generic parameter" { |
| 505 | }; | 505 | }; |
| 506 | S.foo(@typeInfo(@TypeOf(.{}))); | 506 | S.foo(@typeInfo(@TypeOf(.{}))); |
| 507 | } | 507 | } |
| 508 | |||
| 509 | fn A() type { | ||
| 510 | return struct { | ||
| 511 | b: B(), | ||
| 512 | |||
| 513 | const Self = @This(); | ||
| 514 | |||
| 515 | fn B() type { | ||
| 516 | return struct { | ||
| 517 | const Self = @This(); | ||
| 518 | }; | ||
| 519 | } | ||
| 520 | }; | ||
| 521 | } | ||
| 522 | test "non-ambiguous reference of shadowed decls" { | ||
| 523 | try expect(A().B().Self != A().Self); | ||
| 524 | } |
test/behavior/struct.zig+2-2| ... | @@ -162,14 +162,14 @@ const MemberFnRand = struct { | ... | @@ -162,14 +162,14 @@ const MemberFnRand = struct { |
| 162 | }; | 162 | }; |
| 163 | 163 | ||
| 164 | test "return struct byval from function" { | 164 | test "return struct byval from function" { |
| 165 | const bar = makeBar(1234, 5678); | 165 | const bar = makeBar2(1234, 5678); |
| 166 | try expect(bar.y == 5678); | 166 | try expect(bar.y == 5678); |
| 167 | } | 167 | } |
| 168 | const Bar = struct { | 168 | const Bar = struct { |
| 169 | x: i32, | 169 | x: i32, |
| 170 | y: i32, | 170 | y: i32, |
| 171 | }; | 171 | }; |
| 172 | fn makeBar(x: i32, y: i32) Bar { | 172 | fn makeBar2(x: i32, y: i32) Bar { |
| 173 | return Bar{ | 173 | return Bar{ |
| 174 | .x = x, | 174 | .x = x, |
| 175 | .y = y, | 175 | .y = y, |
test/compile_errors.zig+13-18| ... | @@ -6969,29 +6969,24 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -6969,29 +6969,24 @@ pub fn addCases(ctx: *TestContext) !void { |
| 6969 | "tmp.zig:2:30: error: cannot set section of local variable 'foo'", | 6969 | "tmp.zig:2:30: error: cannot set section of local variable 'foo'", |
| 6970 | }); | 6970 | }); |
| 6971 | 6971 | ||
| 6972 | ctx.objErrStage1("inner struct member shadowing outer struct member", | 6972 | ctx.objErrStage1("ambiguous decl reference", |
| 6973 | \\fn A() type { | 6973 | \\fn foo() void {} |
| 6974 | \\ return struct { | 6974 | \\fn bar() void { |
| 6975 | \\ b: B(), | 6975 | \\ const S = struct { |
| 6976 | \\ | 6976 | \\ fn baz() void { |
| 6977 | \\ const Self = @This(); | 6977 | \\ foo(); |
| 6978 | \\ | ||
| 6979 | \\ fn B() type { | ||
| 6980 | \\ return struct { | ||
| 6981 | \\ const Self = @This(); | ||
| 6982 | \\ }; | ||
| 6983 | \\ } | 6978 | \\ } |
| 6979 | \\ fn foo() void {} | ||
| 6984 | \\ }; | 6980 | \\ }; |
| 6981 | \\ S.baz(); | ||
| 6985 | \\} | 6982 | \\} |
| 6986 | \\comptime { | 6983 | \\export fn entry() void { |
| 6987 | \\ assert(A().B().Self != A().Self); | 6984 | \\ bar(); |
| 6988 | \\} | ||
| 6989 | \\fn assert(ok: bool) void { | ||
| 6990 | \\ if (!ok) unreachable; | ||
| 6991 | \\} | 6985 | \\} |
| 6992 | , &[_][]const u8{ | 6986 | , &[_][]const u8{ |
| 6993 | "tmp.zig:9:17: error: redefinition of 'Self'", | 6987 | "tmp.zig:5:13: error: ambiguous reference", |
| 6994 | "tmp.zig:5:9: note: previous definition here", | 6988 | "tmp.zig:7:9: note: declared here", |
| 6989 | "tmp.zig:1:1: note: also declared here", | ||
| 6995 | }); | 6990 | }); |
| 6996 | 6991 | ||
| 6997 | ctx.objErrStage1("while expected bool, got optional", | 6992 | ctx.objErrStage1("while expected bool, got optional", |