aboutsummaryrefslogtreecommitdiff
path: root/src/AstGen.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-08-27 21:34:13 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-08-27 21:34:13 -0700
commitf30aa25cbf9c9a415963b4ea69d7efa09237a704 (patch)
treef0150470b35bb7b55450c54dbb4553e3cc11b29f /src/AstGen.zig
parentcfae70ec8e736af3fcd465c78bd80e160968eea8 (diff)
downloadzig-f30aa25cbf9c9a415963b4ea69d7efa09237a704.tar.gz
zig-f30aa25cbf9c9a415963b4ea69d7efa09237a704.zip
declarations may collide with primitives with @"" syntax
* stage2 AstGen: add missing compile error for declaring a local that shadows a primitive. Even with `@""` syntax, it may not have the same name as a primitive. * stage2 AstGen: add a compile error for a global declaration whose name matches a primitive. However it is allowed when using `@""` syntax. * stage1: delete all "declaration shadows primitive" compile errors because they are now handled by stage2 AstGen. * stage1/stage2 AstGen: notice when using `@""` syntax and: - treat `_` as a regular identifier - skip checking if an identifire is a primitive Check the new test cases for clarifications on semantics. closes #6062
Diffstat (limited to 'src/AstGen.zig')
-rw-r--r--src/AstGen.zig100
1 files changed, 67 insertions, 33 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 0b0de11ea9..2b8e6a76a8 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -2891,7 +2891,7 @@ fn fnDecl(
};
const fn_name_str_index = try astgen.identAsString(fn_name_token);
- try astgen.declareNewName(scope, fn_name_str_index, decl_node);
+ try astgen.declareNewName(scope, fn_name_str_index, decl_node, fn_name_token);
// We insert this at the beginning so that its instruction index marks the
// start of the top level declaration.
@@ -3160,7 +3160,7 @@ fn globalVarDecl(
const name_token = var_decl.ast.mut_token + 1;
const name_str_index = try astgen.identAsString(name_token);
- try astgen.declareNewName(scope, name_str_index, node);
+ try astgen.declareNewName(scope, name_str_index, node, name_token);
var block_scope: GenZir = .{
.parent = scope,
@@ -6319,34 +6319,36 @@ fn identifier(
}
const ident_name = try astgen.identifierTokenString(ident_token);
- if (simple_types.get(ident_name)) |zir_const_ref| {
- return rvalue(gz, rl, zir_const_ref, ident);
- }
+ if (ident_name_raw[0] != '@') {
+ if (simple_types.get(ident_name)) |zir_const_ref| {
+ return rvalue(gz, rl, zir_const_ref, ident);
+ }
- if (ident_name.len >= 2) integer: {
- const first_c = ident_name[0];
- if (first_c == 'i' or first_c == 'u') {
- const signedness: std.builtin.Signedness = switch (first_c == 'i') {
- true => .signed,
- false => .unsigned,
- };
- const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
- error.Overflow => return astgen.failNode(
- ident,
- "primitive integer type '{s}' exceeds maximum bit width of 65535",
- .{ident_name},
- ),
- error.InvalidCharacter => break :integer,
- };
- const result = try gz.add(.{
- .tag = .int_type,
- .data = .{ .int_type = .{
- .src_node = gz.nodeIndexToRelative(ident),
- .signedness = signedness,
- .bit_count = bit_count,
- } },
- });
- return rvalue(gz, rl, result, ident);
+ if (ident_name.len >= 2) integer: {
+ const first_c = ident_name[0];
+ if (first_c == 'i' or first_c == 'u') {
+ const signedness: std.builtin.Signedness = switch (first_c == 'i') {
+ true => .signed,
+ false => .unsigned,
+ };
+ const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
+ error.Overflow => return astgen.failNode(
+ ident,
+ "primitive integer type '{s}' exceeds maximum bit width of 65535",
+ .{ident_name},
+ ),
+ error.InvalidCharacter => break :integer,
+ };
+ const result = try gz.add(.{
+ .tag = .int_type,
+ .data = .{ .int_type = .{
+ .src_node = gz.nodeIndexToRelative(ident),
+ .signedness = signedness,
+ .bit_count = bit_count,
+ } },
+ });
+ return rvalue(gz, rl, result, ident);
+ }
}
}
@@ -10031,8 +10033,21 @@ fn declareNewName(
start_scope: *Scope,
name_index: u32,
node: ast.Node.Index,
+ name_token: ast.TokenIndex,
) !void {
const gpa = astgen.gpa;
+
+ const token_bytes = astgen.tree.tokenSlice(name_token);
+ if (token_bytes[0] != '@' and isPrimitive(token_bytes)) {
+ return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{
+ token_bytes,
+ }, &[_]u32{
+ try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{
+ token_bytes,
+ }),
+ });
+ }
+
var scope = start_scope;
while (true) {
switch (scope.tag) {
@@ -10060,7 +10075,20 @@ fn declareNewName(
}
}
-/// Local variables shadowing detection, including function parameters.
+fn isPrimitive(name: []const u8) bool {
+ if (simple_types.get(name) != null) return true;
+ if (name.len < 2) return false;
+ const first_c = name[0];
+ if (first_c != 'i' and first_c != 'u') return false;
+ if (std.fmt.parseInt(u16, name[1..], 10)) |_| {
+ return true;
+ } else |err| switch (err) {
+ error.Overflow => return true,
+ error.InvalidCharacter => return false,
+ }
+}
+
+/// Local variables shadowing detection, including function parameters and primitives.
fn detectLocalShadowing(
astgen: *AstGen,
scope: *Scope,
@@ -10068,13 +10096,19 @@ fn detectLocalShadowing(
name_token: ast.TokenIndex,
) !void {
const gpa = astgen.gpa;
+ const name_slice = mem.spanZ(astgen.nullTerminatedString(ident_name));
+ if (isPrimitive(name_slice)) {
+ const name = try gpa.dupe(u8, name_slice);
+ defer gpa.free(name);
+ return astgen.failTok(name_token, "local shadows primitive '{s}'", .{name});
+ }
var s = scope;
while (true) switch (s.tag) {
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
if (local_val.name == ident_name) {
- const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
+ const name = try gpa.dupe(u8, name_slice);
defer gpa.free(name);
return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
@tagName(local_val.id_cat), name,
@@ -10091,7 +10125,7 @@ fn detectLocalShadowing(
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
if (local_ptr.name == ident_name) {
- const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
+ const name = try gpa.dupe(u8, name_slice);
defer gpa.free(name);
return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
@tagName(local_ptr.id_cat), name,
@@ -10111,7 +10145,7 @@ fn detectLocalShadowing(
s = ns.parent;
continue;
};
- const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
+ const name = try gpa.dupe(u8, name_slice);
defer gpa.free(name);
return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{
name,