Commit b57ac48773

jacob gw <jacoblevgw@gmail.com>
2021-05-28 03:29:14
stage2: compile error for ambiguous decl refrences
std: fix compile errors from this change. This is a stage1 bug.
1 parent 143688e
Changed files (3)
lib
std
src
test
stage2
lib/std/zig/render.zig
@@ -2564,8 +2564,8 @@ fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex
 fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
     return struct {
         const Self = @This();
-        pub const Error = UnderlyingWriter.Error;
-        pub const Writer = std.io.Writer(*Self, Error, write);
+        pub const WriteError = UnderlyingWriter.Error;
+        pub const Writer = std.io.Writer(*Self, WriteError, write);
 
         underlying_writer: UnderlyingWriter,
 
@@ -2591,7 +2591,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
             return .{ .context = self };
         }
 
-        pub fn write(self: *Self, bytes: []const u8) Error!usize {
+        pub fn write(self: *Self, bytes: []const u8) WriteError!usize {
             if (bytes.len == 0)
                 return @as(usize, 0);
 
@@ -2614,7 +2614,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
             self.indent_delta = new_indent_delta;
         }
 
-        fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize {
+        fn writeNoIndent(self: *Self, bytes: []const u8) WriteError!usize {
             if (bytes.len == 0)
                 return @as(usize, 0);
 
@@ -2624,7 +2624,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
             return bytes.len;
         }
 
-        pub fn insertNewline(self: *Self) Error!void {
+        pub fn insertNewline(self: *Self) WriteError!void {
             _ = try self.writeNoIndent("\n");
         }
 
@@ -2634,7 +2634,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
         }
 
         /// Insert a newline unless the current line is blank
-        pub fn maybeInsertNewline(self: *Self) Error!void {
+        pub fn maybeInsertNewline(self: *Self) WriteError!void {
             if (!self.current_line_empty)
                 try self.insertNewline();
         }
@@ -2675,7 +2675,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
         }
 
         /// Writes ' ' bytes if the current line is empty
-        fn applyIndent(self: *Self) Error!void {
+        fn applyIndent(self: *Self) WriteError!void {
             const current_indent = self.currentIndent();
             if (self.current_line_empty and current_indent > 0) {
                 if (self.disabled_offset == null) {
src/AstGen.zig
@@ -2353,6 +2353,7 @@ fn varDecl(
                 .name = ident_name,
                 .ptr = init_scope.rl_ptr,
                 .token_src = name_token,
+                .is_comptime = true,
             };
             return &sub_scope.base;
         },
@@ -2408,6 +2409,7 @@ fn varDecl(
                 .name = ident_name,
                 .ptr = var_data.alloc,
                 .token_src = name_token,
+                .is_comptime = is_comptime,
             };
             return &sub_scope.base;
         },
@@ -3352,7 +3354,7 @@ fn structDeclInner(
     };
     defer block_scope.instructions.deinit(gpa);
 
-    var namespace: Scope.Namespace = .{ .parent = &gz.base };
+    var namespace: Scope.Namespace = .{ .parent = scope };
     defer namespace.decls.deinit(gpa);
 
     var wip_decls: WipDecls = .{};
@@ -5345,6 +5347,7 @@ fn forExpr(
             .name = index_name,
             .ptr = index_ptr,
             .token_src = index_token,
+            .is_comptime = parent_gz.force_comptime,
         };
         break :blk &index_scope.base;
     };
@@ -6070,9 +6073,16 @@ fn identifier(
     const name_str_index = try astgen.identAsString(ident_token);
     {
         var s = scope;
+        var found_already: ?ast.Node.Index = null; // we have found a decl with the same name already
+        var hit_namespace = false;
         while (true) switch (s.tag) {
             .local_val => {
                 const local_val = s.cast(Scope.LocalVal).?;
+                if (hit_namespace) {
+                    // captures of non-locals need to be emitted as decl_val or decl_ref
+                    // This *might* be capturable depending on if it is comptime known
+                    break;
+                }
                 if (local_val.name == name_str_index) {
                     return rvalue(gz, scope, rl, local_val.inst, ident);
                 }
@@ -6081,6 +6091,15 @@ fn identifier(
             .local_ptr => {
                 const local_ptr = s.cast(Scope.LocalPtr).?;
                 if (local_ptr.name == name_str_index) {
+                    if (hit_namespace) {
+                        if (local_ptr.is_comptime)
+                            break
+                        else
+                            return astgen.failNodeNotes(ident, "'{s}' not accessible from inner function", .{ident_name}, &.{
+                                try astgen.errNoteTok(local_ptr.token_src, "declared here", .{}),
+                                // TODO add crossed function definition here note.
+                            });
+                    }
                     switch (rl) {
                         .ref, .none_or_ref => return local_ptr.ptr,
                         else => {
@@ -6093,7 +6112,22 @@ fn identifier(
             },
             .gen_zir => s = s.cast(GenZir).?.parent,
             .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
-            .namespace, .top => break, // TODO look for ambiguous references to decls
+            // look for ambiguous references to decls
+            .namespace => {
+                const ns = s.cast(Scope.Namespace).?;
+                if (ns.decls.get(name_str_index)) |i| {
+                    if (found_already) |f|
+                        return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{
+                            try astgen.errNoteNode(i, "declared here", .{}),
+                            try astgen.errNoteNode(f, "also declared here", .{}),
+                        })
+                    else
+                        found_already = i;
+                }
+                hit_namespace = true;
+                s = ns.parent;
+            },
+            .top => break,
         };
     }
 
@@ -8042,6 +8076,7 @@ const Scope = struct {
         token_src: ast.TokenIndex,
         /// String table index.
         name: u32,
+        is_comptime: bool,
     };
 
     const Defer = struct {
test/stage2/test.zig
@@ -943,6 +943,34 @@ pub fn addCases(ctx: *TestContext) !void {
         ":10:8: error: cannot return from defer expression",
     });
 
+    ctx.compileError("ambiguous references", linux_x64,
+        \\const T = struct {
+        \\    const T = struct {
+        \\        fn f() void {
+        \\            _ = T;
+        \\        }
+        \\    };
+        \\};
+    , &.{
+        ":4:17: error: ambiguous reference",
+        ":1:1: note: declared here",
+        ":2:5: note: also declared here",
+    });
+
+    ctx.compileError("inner func accessing outer var", linux_x64,
+        \\pub fn f() void {
+        \\    var bar: bool = true;
+        \\    const S = struct {
+        \\        fn baz() bool {
+        \\            return bar;
+        \\        }
+        \\    };
+        \\}
+    , &.{
+        ":5:20: error: 'bar' not accessible from inner function",
+        ":2:9: note: declared here",
+    });
+
     ctx.compileError("global variable redeclaration", linux_x64,
         \\// dummy comment
         \\var foo = false;