diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 10abbdace9ad..2b36eb5b906d 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -2562,8 +2562,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, @@ -2589,7 +2589,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); @@ -2612,7 +2612,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); @@ -2622,7 +2622,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"); } @@ -2632,7 +2632,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(); } @@ -2673,7 +2673,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) { diff --git a/src/AstGen.zig b/src/AstGen.zig index 790984dc8f10..5a1b55840a3e 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2355,6 +2355,7 @@ fn varDecl( .name = ident_name, .ptr = init_scope.rl_ptr, .token_src = name_token, + .is_comptime = true, }; return &sub_scope.base; }, @@ -2410,6 +2411,7 @@ fn varDecl( .name = ident_name, .ptr = var_data.alloc, .token_src = name_token, + .is_comptime = is_comptime, }; return &sub_scope.base; }, @@ -3354,7 +3356,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 = .{}; @@ -5347,6 +5349,7 @@ fn forExpr( .name = index_name, .ptr = index_ptr, .token_src = index_token, + .is_comptime = parent_gz.force_comptime, }; break :blk &index_scope.base; }; @@ -6072,9 +6075,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); } @@ -6083,6 +6093,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 => { @@ -6095,7 +6114,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, }; } @@ -8044,6 +8078,7 @@ const Scope = struct { token_src: ast.TokenIndex, /// String table index. name: u32, + is_comptime: bool, }; const Defer = struct { diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 15ccae474801..1e9dcd693610 100644 --- a/test/stage2/test.zig +++ b/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;