| ... | ... | @@ -4053,7 +4053,7 @@ fn fnDecl( |
| 4053 | 4053 | // The source slice is added towards the *end* of this function. |
| 4054 | 4054 | astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column)); |
| 4055 | 4055 | |
| 4056 | | // missing function name already happened in scanDecls() |
| 4056 | // missing function name already happened in scanContainer() |
| 4057 | 4057 | const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; |
| 4058 | 4058 | |
| 4059 | 4059 | // We insert this at the beginning so that its instruction index marks the |
| ... | ... | @@ -5019,7 +5019,7 @@ fn structDeclInner( |
| 5019 | 5019 | } |
| 5020 | 5020 | }; |
| 5021 | 5021 | |
| 5022 | | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 5022 | const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"struct"); |
| 5023 | 5023 | const field_count: u32 = @intCast(container_decl.ast.members.len - decl_count); |
| 5024 | 5024 | |
| 5025 | 5025 | const bits_per_field = 4; |
| ... | ... | @@ -5088,15 +5088,6 @@ fn structDeclInner( |
| 5088 | 5088 | astgen.src_hasher.update(tree.getNodeSource(backing_int_node)); |
| 5089 | 5089 | } |
| 5090 | 5090 | |
| 5091 | | var sfba = std.heap.stackFallback(256, astgen.arena); |
| 5092 | | const sfba_allocator = sfba.get(); |
| 5093 | | |
| 5094 | | var duplicate_names = std.AutoArrayHashMap(Zir.NullTerminatedString, std.ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); |
| 5095 | | try duplicate_names.ensureTotalCapacity(field_count); |
| 5096 | | |
| 5097 | | // When there aren't errors, use this to avoid a second iteration. |
| 5098 | | var any_duplicate = false; |
| 5099 | | |
| 5100 | 5091 | var known_non_opv = false; |
| 5101 | 5092 | var known_comptime_only = false; |
| 5102 | 5093 | var any_comptime_fields = false; |
| ... | ... | @@ -5117,16 +5108,6 @@ fn structDeclInner( |
| 5117 | 5108 | assert(!member.ast.tuple_like); |
| 5118 | 5109 | |
| 5119 | 5110 | wip_members.appendToField(@intFromEnum(field_name)); |
| 5120 | | |
| 5121 | | const gop = try duplicate_names.getOrPut(field_name); |
| 5122 | | |
| 5123 | | if (gop.found_existing) { |
| 5124 | | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); |
| 5125 | | any_duplicate = true; |
| 5126 | | } else { |
| 5127 | | gop.value_ptr.* = .{}; |
| 5128 | | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); |
| 5129 | | } |
| 5130 | 5111 | } else if (!member.ast.tuple_like) { |
| 5131 | 5112 | return astgen.failTok(member.ast.main_token, "tuple field has a name", .{}); |
| 5132 | 5113 | } |
| ... | ... | @@ -5211,32 +5192,6 @@ fn structDeclInner( |
| 5211 | 5192 | } |
| 5212 | 5193 | } |
| 5213 | 5194 | |
| 5214 | | if (any_duplicate) { |
| 5215 | | var it = duplicate_names.iterator(); |
| 5216 | | |
| 5217 | | while (it.next()) |entry| { |
| 5218 | | const record = entry.value_ptr.*; |
| 5219 | | if (record.items.len > 1) { |
| 5220 | | var error_notes = std.ArrayList(u32).init(astgen.arena); |
| 5221 | | |
| 5222 | | for (record.items[1..]) |duplicate| { |
| 5223 | | try error_notes.append(try astgen.errNoteTok(duplicate, "duplicate field here", .{})); |
| 5224 | | } |
| 5225 | | |
| 5226 | | try error_notes.append(try astgen.errNoteNode(node, "struct declared here", .{})); |
| 5227 | | |
| 5228 | | try astgen.appendErrorTokNotes( |
| 5229 | | record.items[0], |
| 5230 | | "duplicate struct field name", |
| 5231 | | .{}, |
| 5232 | | error_notes.items, |
| 5233 | | ); |
| 5234 | | } |
| 5235 | | } |
| 5236 | | |
| 5237 | | return error.AnalysisFail; |
| 5238 | | } |
| 5239 | | |
| 5240 | 5195 | var fields_hash: std.zig.SrcHash = undefined; |
| 5241 | 5196 | astgen.src_hasher.final(&fields_hash); |
| 5242 | 5197 | |
| ... | ... | @@ -5317,7 +5272,7 @@ fn unionDeclInner( |
| 5317 | 5272 | }; |
| 5318 | 5273 | defer block_scope.unstack(); |
| 5319 | 5274 | |
| 5320 | | const decl_count = try astgen.scanDecls(&namespace, members); |
| 5275 | const decl_count = try astgen.scanContainer(&namespace, members, .@"union"); |
| 5321 | 5276 | const field_count: u32 = @intCast(members.len - decl_count); |
| 5322 | 5277 | |
| 5323 | 5278 | if (layout != .auto and (auto_enum_tok != null or arg_node != 0)) { |
| ... | ... | @@ -5348,15 +5303,6 @@ fn unionDeclInner( |
| 5348 | 5303 | astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node)); |
| 5349 | 5304 | } |
| 5350 | 5305 | |
| 5351 | | var sfba = std.heap.stackFallback(256, astgen.arena); |
| 5352 | | const sfba_allocator = sfba.get(); |
| 5353 | | |
| 5354 | | var duplicate_names = std.AutoArrayHashMap(Zir.NullTerminatedString, std.ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); |
| 5355 | | try duplicate_names.ensureTotalCapacity(field_count); |
| 5356 | | |
| 5357 | | // When there aren't errors, use this to avoid a second iteration. |
| 5358 | | var any_duplicate = false; |
| 5359 | | |
| 5360 | 5306 | for (members) |member_node| { |
| 5361 | 5307 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 5362 | 5308 | .decl => continue, |
| ... | ... | @@ -5374,16 +5320,6 @@ fn unionDeclInner( |
| 5374 | 5320 | const field_name = try astgen.identAsString(member.ast.main_token); |
| 5375 | 5321 | wip_members.appendToField(@intFromEnum(field_name)); |
| 5376 | 5322 | |
| 5377 | | const gop = try duplicate_names.getOrPut(field_name); |
| 5378 | | |
| 5379 | | if (gop.found_existing) { |
| 5380 | | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); |
| 5381 | | any_duplicate = true; |
| 5382 | | } else { |
| 5383 | | gop.value_ptr.* = .{}; |
| 5384 | | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); |
| 5385 | | } |
| 5386 | | |
| 5387 | 5323 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); |
| 5388 | 5324 | wip_members.appendToField(@intFromEnum(doc_comment_index)); |
| 5389 | 5325 | |
| ... | ... | @@ -5438,32 +5374,6 @@ fn unionDeclInner( |
| 5438 | 5374 | } |
| 5439 | 5375 | } |
| 5440 | 5376 | |
| 5441 | | if (any_duplicate) { |
| 5442 | | var it = duplicate_names.iterator(); |
| 5443 | | |
| 5444 | | while (it.next()) |entry| { |
| 5445 | | const record = entry.value_ptr.*; |
| 5446 | | if (record.items.len > 1) { |
| 5447 | | var error_notes = std.ArrayList(u32).init(astgen.arena); |
| 5448 | | |
| 5449 | | for (record.items[1..]) |duplicate| { |
| 5450 | | try error_notes.append(try astgen.errNoteTok(duplicate, "duplicate field here", .{})); |
| 5451 | | } |
| 5452 | | |
| 5453 | | try error_notes.append(try astgen.errNoteNode(node, "union declared here", .{})); |
| 5454 | | |
| 5455 | | try astgen.appendErrorTokNotes( |
| 5456 | | record.items[0], |
| 5457 | | "duplicate union field name", |
| 5458 | | .{}, |
| 5459 | | error_notes.items, |
| 5460 | | ); |
| 5461 | | } |
| 5462 | | } |
| 5463 | | |
| 5464 | | return error.AnalysisFail; |
| 5465 | | } |
| 5466 | | |
| 5467 | 5377 | var fields_hash: std.zig.SrcHash = undefined; |
| 5468 | 5378 | astgen.src_hasher.final(&fields_hash); |
| 5469 | 5379 | |
| ... | ... | @@ -5666,7 +5576,7 @@ fn containerDecl( |
| 5666 | 5576 | }; |
| 5667 | 5577 | defer block_scope.unstack(); |
| 5668 | 5578 | |
| 5669 | | _ = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 5579 | _ = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"enum"); |
| 5670 | 5580 | namespace.base.tag = .namespace; |
| 5671 | 5581 | |
| 5672 | 5582 | const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) |
| ... | ... | @@ -5687,15 +5597,6 @@ fn containerDecl( |
| 5687 | 5597 | } |
| 5688 | 5598 | astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)}); |
| 5689 | 5599 | |
| 5690 | | var sfba = std.heap.stackFallback(256, astgen.arena); |
| 5691 | | const sfba_allocator = sfba.get(); |
| 5692 | | |
| 5693 | | var duplicate_names = std.AutoArrayHashMap(Zir.NullTerminatedString, std.ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); |
| 5694 | | try duplicate_names.ensureTotalCapacity(counts.total_fields); |
| 5695 | | |
| 5696 | | // When there aren't errors, use this to avoid a second iteration. |
| 5697 | | var any_duplicate = false; |
| 5698 | | |
| 5699 | 5600 | for (container_decl.ast.members) |member_node| { |
| 5700 | 5601 | if (member_node == counts.nonexhaustive_node) |
| 5701 | 5602 | continue; |
| ... | ... | @@ -5712,16 +5613,6 @@ fn containerDecl( |
| 5712 | 5613 | const field_name = try astgen.identAsString(member.ast.main_token); |
| 5713 | 5614 | wip_members.appendToField(@intFromEnum(field_name)); |
| 5714 | 5615 | |
| 5715 | | const gop = try duplicate_names.getOrPut(field_name); |
| 5716 | | |
| 5717 | | if (gop.found_existing) { |
| 5718 | | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); |
| 5719 | | any_duplicate = true; |
| 5720 | | } else { |
| 5721 | | gop.value_ptr.* = .{}; |
| 5722 | | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); |
| 5723 | | } |
| 5724 | | |
| 5725 | 5616 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); |
| 5726 | 5617 | wip_members.appendToField(@intFromEnum(doc_comment_index)); |
| 5727 | 5618 | |
| ... | ... | @@ -5748,32 +5639,6 @@ fn containerDecl( |
| 5748 | 5639 | } |
| 5749 | 5640 | } |
| 5750 | 5641 | |
| 5751 | | if (any_duplicate) { |
| 5752 | | var it = duplicate_names.iterator(); |
| 5753 | | |
| 5754 | | while (it.next()) |entry| { |
| 5755 | | const record = entry.value_ptr.*; |
| 5756 | | if (record.items.len > 1) { |
| 5757 | | var error_notes = std.ArrayList(u32).init(astgen.arena); |
| 5758 | | |
| 5759 | | for (record.items[1..]) |duplicate| { |
| 5760 | | try error_notes.append(try astgen.errNoteTok(duplicate, "duplicate field here", .{})); |
| 5761 | | } |
| 5762 | | |
| 5763 | | try error_notes.append(try astgen.errNoteNode(node, "enum declared here", .{})); |
| 5764 | | |
| 5765 | | try astgen.appendErrorTokNotes( |
| 5766 | | record.items[0], |
| 5767 | | "duplicate enum field name", |
| 5768 | | .{}, |
| 5769 | | error_notes.items, |
| 5770 | | ); |
| 5771 | | } |
| 5772 | | } |
| 5773 | | |
| 5774 | | return error.AnalysisFail; |
| 5775 | | } |
| 5776 | | |
| 5777 | 5642 | if (!block_scope.isEmpty()) { |
| 5778 | 5643 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 5779 | 5644 | } |
| ... | ... | @@ -5833,7 +5698,7 @@ fn containerDecl( |
| 5833 | 5698 | }; |
| 5834 | 5699 | defer block_scope.unstack(); |
| 5835 | 5700 | |
| 5836 | | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 5701 | const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"opaque"); |
| 5837 | 5702 | |
| 5838 | 5703 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); |
| 5839 | 5704 | defer wip_members.deinit(); |
| ... | ... | @@ -13594,31 +13459,67 @@ fn advanceSourceCursor(astgen: *AstGen, end: usize) void { |
| 13594 | 13459 | astgen.source_column = column; |
| 13595 | 13460 | } |
| 13596 | 13461 | |
| 13597 | | fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !u32 { |
| 13462 | /// Detects name conflicts for decls and fields, and populates `namespace.decls` with all named declarations. |
| 13463 | /// Returns the number of declarations in the namespace, including unnamed declarations (e.g. `comptime` decls). |
| 13464 | fn scanContainer( |
| 13465 | astgen: *AstGen, |
| 13466 | namespace: *Scope.Namespace, |
| 13467 | members: []const Ast.Node.Index, |
| 13468 | container_kind: enum { @"struct", @"union", @"enum", @"opaque" }, |
| 13469 | ) !u32 { |
| 13598 | 13470 | const gpa = astgen.gpa; |
| 13599 | 13471 | const tree = astgen.tree; |
| 13600 | 13472 | const node_tags = tree.nodes.items(.tag); |
| 13601 | 13473 | const main_tokens = tree.nodes.items(.main_token); |
| 13602 | 13474 | const token_tags = tree.tokens.items(.tag); |
| 13603 | 13475 | |
| 13604 | | // We don't have shadowing for test names, so we just track those for duplicate reporting locally. |
| 13605 | | var named_tests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}; |
| 13606 | | var decltests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}; |
| 13476 | // This type forms a linked list of source tokens declaring the same name. |
| 13477 | const NameEntry = struct { |
| 13478 | tok: Ast.TokenIndex, |
| 13479 | /// Using a linked list here simplifies memory management, and is acceptable since |
| 13480 | ///ewntries are only allocated in error situations. The entries are allocated into the |
| 13481 | /// AstGen arena. |
| 13482 | next: ?*@This(), |
| 13483 | }; |
| 13484 | |
| 13485 | // The maps below are allocated into this SFBA to avoid using the GPA for small namespaces. |
| 13486 | var sfba_state = std.heap.stackFallback(512, astgen.gpa); |
| 13487 | const sfba = sfba_state.get(); |
| 13488 | |
| 13489 | var names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .{}; |
| 13490 | var test_names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .{}; |
| 13491 | var decltest_names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .{}; |
| 13607 | 13492 | defer { |
| 13608 | | named_tests.deinit(gpa); |
| 13609 | | decltests.deinit(gpa); |
| 13493 | names.deinit(sfba); |
| 13494 | test_names.deinit(sfba); |
| 13495 | decltest_names.deinit(sfba); |
| 13610 | 13496 | } |
| 13611 | 13497 | |
| 13498 | var any_duplicates = false; |
| 13612 | 13499 | var decl_count: u32 = 0; |
| 13613 | 13500 | for (members) |member_node| { |
| 13614 | | const name_token = switch (node_tags[member_node]) { |
| 13501 | const Kind = enum { decl, field }; |
| 13502 | const kind: Kind, const name_token = switch (node_tags[member_node]) { |
| 13503 | .container_field_init, |
| 13504 | .container_field_align, |
| 13505 | .container_field, |
| 13506 | => blk: { |
| 13507 | var full = tree.fullContainerField(member_node).?; |
| 13508 | switch (container_kind) { |
| 13509 | .@"struct", .@"opaque" => {}, |
| 13510 | .@"union", .@"enum" => full.convertToNonTupleLike(astgen.tree.nodes), |
| 13511 | } |
| 13512 | if (full.ast.tuple_like) continue; |
| 13513 | break :blk .{ .field, full.ast.main_token }; |
| 13514 | }, |
| 13515 | |
| 13615 | 13516 | .global_var_decl, |
| 13616 | 13517 | .local_var_decl, |
| 13617 | 13518 | .simple_var_decl, |
| 13618 | 13519 | .aligned_var_decl, |
| 13619 | 13520 | => blk: { |
| 13620 | 13521 | decl_count += 1; |
| 13621 | | break :blk main_tokens[member_node] + 1; |
| 13522 | break :blk .{ .decl, main_tokens[member_node] + 1 }; |
| 13622 | 13523 | }, |
| 13623 | 13524 | |
| 13624 | 13525 | .fn_proto_simple, |
| ... | ... | @@ -13630,12 +13531,10 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13630 | 13531 | decl_count += 1; |
| 13631 | 13532 | const ident = main_tokens[member_node] + 1; |
| 13632 | 13533 | if (token_tags[ident] != .identifier) { |
| 13633 | | switch (astgen.failNode(member_node, "missing function name", .{})) { |
| 13634 | | error.AnalysisFail => continue, |
| 13635 | | error.OutOfMemory => return error.OutOfMemory, |
| 13636 | | } |
| 13534 | try astgen.appendErrorNode(member_node, "missing function name", .{}); |
| 13535 | continue; |
| 13637 | 13536 | } |
| 13638 | | break :blk ident; |
| 13537 | break :blk .{ .decl, ident }; |
| 13639 | 13538 | }, |
| 13640 | 13539 | |
| 13641 | 13540 | .@"comptime", .@"usingnamespace" => { |
| ... | ... | @@ -13648,70 +13547,87 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13648 | 13547 | // We don't want shadowing detection here, and test names work a bit differently, so |
| 13649 | 13548 | // we must do the redeclaration detection ourselves. |
| 13650 | 13549 | const test_name_token = main_tokens[member_node] + 1; |
| 13550 | const new_ent: NameEntry = .{ |
| 13551 | .tok = test_name_token, |
| 13552 | .next = null, |
| 13553 | }; |
| 13651 | 13554 | switch (token_tags[test_name_token]) { |
| 13652 | 13555 | else => {}, // unnamed test |
| 13653 | 13556 | .string_literal => { |
| 13654 | 13557 | const name = try astgen.strLitAsString(test_name_token); |
| 13655 | | const gop = try named_tests.getOrPut(gpa, name.index); |
| 13558 | const gop = try test_names.getOrPut(sfba, name.index); |
| 13656 | 13559 | if (gop.found_existing) { |
| 13657 | | const name_slice = astgen.string_bytes.items[@intFromEnum(name.index)..][0..name.len]; |
| 13658 | | const name_duped = try gpa.dupe(u8, name_slice); |
| 13659 | | defer gpa.free(name_duped); |
| 13660 | | try astgen.appendErrorNodeNotes(member_node, "duplicate test name '{s}'", .{name_duped}, &.{ |
| 13661 | | try astgen.errNoteNode(gop.value_ptr.*, "other test here", .{}), |
| 13662 | | }); |
| 13560 | var e = gop.value_ptr; |
| 13561 | while (e.next) |n| e = n; |
| 13562 | e.next = try astgen.arena.create(NameEntry); |
| 13563 | e.next.?.* = new_ent; |
| 13564 | any_duplicates = true; |
| 13663 | 13565 | } else { |
| 13664 | | gop.value_ptr.* = member_node; |
| 13566 | gop.value_ptr.* = new_ent; |
| 13665 | 13567 | } |
| 13666 | 13568 | }, |
| 13667 | 13569 | .identifier => { |
| 13668 | 13570 | const name = try astgen.identAsString(test_name_token); |
| 13669 | | const gop = try decltests.getOrPut(gpa, name); |
| 13571 | const gop = try decltest_names.getOrPut(sfba, name); |
| 13670 | 13572 | if (gop.found_existing) { |
| 13671 | | const name_slice = mem.span(astgen.nullTerminatedString(name)); |
| 13672 | | const name_duped = try gpa.dupe(u8, name_slice); |
| 13673 | | defer gpa.free(name_duped); |
| 13674 | | try astgen.appendErrorNodeNotes(member_node, "duplicate decltest '{s}'", .{name_duped}, &.{ |
| 13675 | | try astgen.errNoteNode(gop.value_ptr.*, "other decltest here", .{}), |
| 13676 | | }); |
| 13573 | var e = gop.value_ptr; |
| 13574 | while (e.next) |n| e = n; |
| 13575 | e.next = try astgen.arena.create(NameEntry); |
| 13576 | e.next.?.* = new_ent; |
| 13577 | any_duplicates = true; |
| 13677 | 13578 | } else { |
| 13678 | | gop.value_ptr.* = member_node; |
| 13579 | gop.value_ptr.* = new_ent; |
| 13679 | 13580 | } |
| 13680 | 13581 | }, |
| 13681 | 13582 | } |
| 13682 | 13583 | continue; |
| 13683 | 13584 | }, |
| 13684 | 13585 | |
| 13685 | | else => continue, |
| 13586 | else => unreachable, |
| 13686 | 13587 | }; |
| 13687 | 13588 | |
| 13589 | const name_str_index = try astgen.identAsString(name_token); |
| 13590 | |
| 13591 | if (kind == .decl) { |
| 13592 | // Put the name straight into `decls`, even if there are compile errors. |
| 13593 | // This avoids incorrect "undeclared identifier" errors later on. |
| 13594 | try namespace.decls.put(gpa, name_str_index, member_node); |
| 13595 | } |
| 13596 | |
| 13597 | { |
| 13598 | const gop = try names.getOrPut(sfba, name_str_index); |
| 13599 | const new_ent: NameEntry = .{ |
| 13600 | .tok = name_token, |
| 13601 | .next = null, |
| 13602 | }; |
| 13603 | if (gop.found_existing) { |
| 13604 | var e = gop.value_ptr; |
| 13605 | while (e.next) |n| e = n; |
| 13606 | e.next = try astgen.arena.create(NameEntry); |
| 13607 | e.next.?.* = new_ent; |
| 13608 | any_duplicates = true; |
| 13609 | continue; |
| 13610 | } else { |
| 13611 | gop.value_ptr.* = new_ent; |
| 13612 | } |
| 13613 | } |
| 13614 | |
| 13615 | // For fields, we only needed the duplicate check! Decls have some more checks to do, though. |
| 13616 | switch (kind) { |
| 13617 | .decl => {}, |
| 13618 | .field => continue, |
| 13619 | } |
| 13620 | |
| 13688 | 13621 | const token_bytes = astgen.tree.tokenSlice(name_token); |
| 13689 | 13622 | if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { |
| 13690 | | switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ |
| 13623 | try astgen.appendErrorTokNotes(name_token, "name shadows primitive '{s}'", .{ |
| 13691 | 13624 | token_bytes, |
| 13692 | | }, &[_]u32{ |
| 13625 | }, &.{ |
| 13693 | 13626 | try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ |
| 13694 | 13627 | token_bytes, |
| 13695 | 13628 | }), |
| 13696 | | })) { |
| 13697 | | error.AnalysisFail => continue, |
| 13698 | | error.OutOfMemory => return error.OutOfMemory, |
| 13699 | | } |
| 13700 | | } |
| 13701 | | |
| 13702 | | const name_str_index = try astgen.identAsString(name_token); |
| 13703 | | const gop = try namespace.decls.getOrPut(gpa, name_str_index); |
| 13704 | | if (gop.found_existing) { |
| 13705 | | const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index))); |
| 13706 | | defer gpa.free(name); |
| 13707 | | switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{ |
| 13708 | | name, |
| 13709 | | }, &[_]u32{ |
| 13710 | | try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}), |
| 13711 | | })) { |
| 13712 | | error.AnalysisFail => continue, |
| 13713 | | error.OutOfMemory => return error.OutOfMemory, |
| 13714 | | } |
| 13629 | }); |
| 13630 | continue; |
| 13715 | 13631 | } |
| 13716 | 13632 | |
| 13717 | 13633 | var s = namespace.parent; |
| ... | ... | @@ -13719,30 +13635,32 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13719 | 13635 | .local_val => { |
| 13720 | 13636 | const local_val = s.cast(Scope.LocalVal).?; |
| 13721 | 13637 | if (local_val.name == name_str_index) { |
| 13722 | | return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ |
| 13638 | try astgen.appendErrorTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ |
| 13723 | 13639 | token_bytes, @tagName(local_val.id_cat), |
| 13724 | | }, &[_]u32{ |
| 13640 | }, &.{ |
| 13725 | 13641 | try astgen.errNoteTok( |
| 13726 | 13642 | local_val.token_src, |
| 13727 | 13643 | "previous declaration here", |
| 13728 | 13644 | .{}, |
| 13729 | 13645 | ), |
| 13730 | 13646 | }); |
| 13647 | break; |
| 13731 | 13648 | } |
| 13732 | 13649 | s = local_val.parent; |
| 13733 | 13650 | }, |
| 13734 | 13651 | .local_ptr => { |
| 13735 | 13652 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 13736 | 13653 | if (local_ptr.name == name_str_index) { |
| 13737 | | return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ |
| 13654 | try astgen.appendErrorTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ |
| 13738 | 13655 | token_bytes, @tagName(local_ptr.id_cat), |
| 13739 | | }, &[_]u32{ |
| 13656 | }, &.{ |
| 13740 | 13657 | try astgen.errNoteTok( |
| 13741 | 13658 | local_ptr.token_src, |
| 13742 | 13659 | "previous declaration here", |
| 13743 | 13660 | .{}, |
| 13744 | 13661 | ), |
| 13745 | 13662 | }); |
| 13663 | break; |
| 13746 | 13664 | } |
| 13747 | 13665 | s = local_ptr.parent; |
| 13748 | 13666 | }, |
| ... | ... | @@ -13751,8 +13669,46 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13751 | 13669 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, |
| 13752 | 13670 | .top => break, |
| 13753 | 13671 | }; |
| 13754 | | gop.value_ptr.* = member_node; |
| 13755 | 13672 | } |
| 13673 | |
| 13674 | if (!any_duplicates) return decl_count; |
| 13675 | |
| 13676 | for (names.keys(), names.values()) |name, first| { |
| 13677 | if (first.next == null) continue; |
| 13678 | var notes: std.ArrayListUnmanaged(u32) = .{}; |
| 13679 | var prev: NameEntry = first; |
| 13680 | while (prev.next) |cur| : (prev = cur.*) { |
| 13681 | try notes.append(astgen.arena, try astgen.errNoteTok(cur.tok, "duplicate name here", .{})); |
| 13682 | } |
| 13683 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13684 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13685 | try astgen.appendErrorTokNotes(first.tok, "duplicate {s} member name '{s}'", .{ @tagName(container_kind), name_duped }, notes.items); |
| 13686 | } |
| 13687 | |
| 13688 | for (test_names.keys(), test_names.values()) |name, first| { |
| 13689 | if (first.next == null) continue; |
| 13690 | var notes: std.ArrayListUnmanaged(u32) = .{}; |
| 13691 | var prev: NameEntry = first; |
| 13692 | while (prev.next) |cur| : (prev = cur.*) { |
| 13693 | try notes.append(astgen.arena, try astgen.errNoteTok(cur.tok, "duplicate test here", .{})); |
| 13694 | } |
| 13695 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13696 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13697 | try astgen.appendErrorTokNotes(first.tok, "duplicate test name '{s}'", .{name_duped}, notes.items); |
| 13698 | } |
| 13699 | |
| 13700 | for (decltest_names.keys(), decltest_names.values()) |name, first| { |
| 13701 | if (first.next == null) continue; |
| 13702 | var notes: std.ArrayListUnmanaged(u32) = .{}; |
| 13703 | var prev: NameEntry = first; |
| 13704 | while (prev.next) |cur| : (prev = cur.*) { |
| 13705 | try notes.append(astgen.arena, try astgen.errNoteTok(cur.tok, "duplicate decltest here", .{})); |
| 13706 | } |
| 13707 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); |
| 13708 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); |
| 13709 | try astgen.appendErrorTokNotes(first.tok, "duplicate decltest '{s}'", .{name_duped}, notes.items); |
| 13710 | } |
| 13711 | |
| 13756 | 13712 | return decl_count; |
| 13757 | 13713 | } |
| 13758 | 13714 | |