Commit b57ac48773
Changed files (3)
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;