Commit 9c95f38a7c

Andrew Kelley <andrew@ziglang.org>
2021-08-25 03:56:16
stage1: remove incorrect compile error for var redeclaration
Locals are not allowed to shadow declarations, but declarations are allowed to shadow each other, as long as there are no ambiguous references. closes #678
1 parent f1f28af
src/stage1/analyze.cpp
@@ -4171,46 +4171,11 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
     } else {
         variable_entry->align_bytes = get_abi_alignment(g, var_type);
 
-        ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr);
-        if (existing_var && !existing_var->shadowable) {
-            if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) {
-                ErrorMsg *msg = add_node_error(g, source_node,
-                        buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
-                add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration here"));
-            }
+        ZigType *type;
+        if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) {
+            add_node_error(g, source_node,
+                    buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
             variable_entry->var_type = g->builtin_types.entry_invalid;
-        } else {
-            ZigType *type;
-            if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) {
-                add_node_error(g, source_node,
-                        buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
-                variable_entry->var_type = g->builtin_types.entry_invalid;
-            } else {
-                Scope *search_scope = nullptr;
-                if (src_tld == nullptr) {
-                    search_scope = parent_scope;
-                } else if (src_tld->parent_scope != nullptr && src_tld->parent_scope->parent != nullptr) {
-                    search_scope = src_tld->parent_scope->parent;
-                }
-                if (search_scope != nullptr) {
-                    Tld *tld = find_decl(g, search_scope, name);
-                    if (tld != nullptr && tld != src_tld) {
-                        bool want_err_msg = true;
-                        if (tld->id == TldIdVar) {
-                            ZigVar *var = reinterpret_cast<TldVar *>(tld)->var;
-                            if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) {
-                                want_err_msg = false;
-                            }
-                        }
-                        if (want_err_msg) {
-                            ErrorMsg *msg = add_node_error(g, source_node,
-                                    buf_sprintf("redefinition of '%s'", buf_ptr(name)));
-                            add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition here"));
-                        }
-                        variable_entry->var_type = g->builtin_types.entry_invalid;
-                    }
-                }
-            }
         }
     }
 
src/stage1/astgen.cpp
@@ -3200,23 +3200,6 @@ ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope,
                     add_node_error(codegen, node,
                             buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
                     variable_entry->var_type = codegen->builtin_types.entry_invalid;
-                } else {
-                    Tld *tld = find_decl(codegen, parent_scope, name);
-                    if (tld != nullptr) {
-                        bool want_err_msg = true;
-                        if (tld->id == TldIdVar) {
-                            ZigVar *var = reinterpret_cast<TldVar *>(tld)->var;
-                            if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) {
-                                want_err_msg = false;
-                            }
-                        }
-                        if (want_err_msg) {
-                            ErrorMsg *msg = add_node_error(codegen, node,
-                                    buf_sprintf("redefinition of '%s'", buf_ptr(name)));
-                            add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition here"));
-                        }
-                        variable_entry->var_type = codegen->builtin_types.entry_invalid;
-                    }
                 }
             }
         }
@@ -3875,7 +3858,31 @@ static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode
         }
     }
 
-    Tld *tld = find_decl(ag->codegen, scope, variable_name);
+    Tld *tld = nullptr;
+    {
+        Scope *s = scope;
+        while (s) {
+            if (s->id == ScopeIdDecls) {
+                ScopeDecls *decls_scope = (ScopeDecls *)s;
+
+                Tld *result = find_container_decl(ag->codegen, decls_scope, variable_name);
+                if (result != nullptr) {
+                    if (tld != nullptr && tld != result) {
+                        ErrorMsg *msg = add_node_error(ag->codegen, node,
+                                buf_sprintf("ambiguous reference"));
+                        add_error_note(ag->codegen, msg, tld->source_node,
+                                buf_sprintf("declared here"));
+                        add_error_note(ag->codegen, msg, result->source_node,
+                                buf_sprintf("also declared here"));
+                        return ag->codegen->invalid_inst_src;
+                    }
+                    tld = result;
+                }
+            }
+            s = s->parent;
+        }
+    }
+
     if (tld) {
         Stage1ZirInst *decl_ref = ir_build_decl_ref(ag, scope, node, tld, lval);
         if (lval == LValPtr || lval == LValAssign) {
test/behavior/error.zig
@@ -412,19 +412,19 @@ test "function pointer with return type that is error union with payload which i
 test "return result loc as peer result loc in inferred error set function" {
     const S = struct {
         fn doTheTest() !void {
-            if (foo(2)) |x| {
+            if (quux(2)) |x| {
                 try expect(x.Two);
             } else |e| switch (e) {
                 error.Whatever => @panic("fail"),
             }
-            try expectError(error.Whatever, foo(99));
+            try expectError(error.Whatever, quux(99));
         }
         const FormValue = union(enum) {
             One: void,
             Two: bool,
         };
 
-        fn foo(id: u64) !FormValue {
+        fn quux(id: u64) !FormValue {
             return switch (id) {
                 2 => FormValue{ .Two = true },
                 1 => FormValue{ .One = {} },
@@ -452,11 +452,11 @@ test "error payload type is correctly resolved" {
 
 test "error union comptime caching" {
     const S = struct {
-        fn foo(comptime arg: anytype) void {
+        fn quux(comptime arg: anytype) void {
             arg catch {};
         }
     };
 
-    S.foo(@as(anyerror!void, {}));
-    S.foo(@as(anyerror!void, {}));
+    S.quux(@as(anyerror!void, {}));
+    S.quux(@as(anyerror!void, {}));
 }
test/behavior/misc.zig
@@ -505,3 +505,20 @@ test "lazy typeInfo value as generic parameter" {
     };
     S.foo(@typeInfo(@TypeOf(.{})));
 }
+
+fn A() type {
+    return struct {
+        b: B(),
+
+        const Self = @This();
+
+        fn B() type {
+            return struct {
+                const Self = @This();
+            };
+        }
+    };
+}
+test "non-ambiguous reference of shadowed decls" {
+    try expect(A().B().Self != A().Self);
+}
test/behavior/struct.zig
@@ -162,14 +162,14 @@ const MemberFnRand = struct {
 };
 
 test "return struct byval from function" {
-    const bar = makeBar(1234, 5678);
+    const bar = makeBar2(1234, 5678);
     try expect(bar.y == 5678);
 }
 const Bar = struct {
     x: i32,
     y: i32,
 };
-fn makeBar(x: i32, y: i32) Bar {
+fn makeBar2(x: i32, y: i32) Bar {
     return Bar{
         .x = x,
         .y = y,
test/compile_errors.zig
@@ -6969,29 +6969,24 @@ pub fn addCases(ctx: *TestContext) !void {
         "tmp.zig:2:30: error: cannot set section of local variable 'foo'",
     });
 
-    ctx.objErrStage1("inner struct member shadowing outer struct member",
-        \\fn A() type {
-        \\    return struct {
-        \\        b: B(),
-        \\
-        \\        const Self = @This();
-        \\
-        \\        fn B() type {
-        \\            return struct {
-        \\                const Self = @This();
-        \\            };
+    ctx.objErrStage1("ambiguous decl reference",
+        \\fn foo() void {}
+        \\fn bar() void {
+        \\    const S = struct {
+        \\        fn baz() void {
+        \\            foo();
         \\        }
+        \\        fn foo() void {}
         \\    };
+        \\    S.baz();
         \\}
-        \\comptime {
-        \\    assert(A().B().Self != A().Self);
-        \\}
-        \\fn assert(ok: bool) void {
-        \\    if (!ok) unreachable;
+        \\export fn entry() void {
+        \\    bar();
         \\}
     , &[_][]const u8{
-        "tmp.zig:9:17: error: redefinition of 'Self'",
-        "tmp.zig:5:9: note: previous definition here",
+        "tmp.zig:5:13: error: ambiguous reference",
+        "tmp.zig:7:9: note: declared here",
+        "tmp.zig:1:1: note: also declared here",
     });
 
     ctx.objErrStage1("while expected bool, got optional",