From 518e097767ad9890d997447fd9c0390b7dd6112c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 03:10:35 +0000 Subject: [PATCH 1/2] perf(check): keep one declaration per library package name until a second is met Co-Authored-By: jason.han --- .../unreleased/duplicate-libraries-walk.fixed.md | 5 +++++ internal/check/workspace/duplicate_library.go | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 changes/unreleased/duplicate-libraries-walk.fixed.md diff --git a/changes/unreleased/duplicate-libraries-walk.fixed.md b/changes/unreleased/duplicate-libraries-walk.fixed.md new file mode 100644 index 0000000000..1cf932a6e6 --- /dev/null +++ b/changes/unreleased/duplicate-libraries-walk.fixed.md @@ -0,0 +1,5 @@ +The duplicate-library check of #1462 keeps only the first declaration of each library package +name until a second is met, instead of a list per name. Loading an empty model into a REPL +allocates 2 038 times instead of 2 155, recovering most of what #1462 added over 0.11.0's 2 022 +on the same toolchain; the walk over every library document's root packages remains, so the +load is not back to 0.11.0's time. diff --git a/internal/check/workspace/duplicate_library.go b/internal/check/workspace/duplicate_library.go index c14b4c0d52..0b7e03e677 100644 --- a/internal/check/workspace/duplicate_library.go +++ b/internal/check/workspace/duplicate_library.go @@ -53,6 +53,9 @@ type duplicate struct { // are grouped by the pair of trees the copies lie in, so two copies of the whole // standard library are one warning, not one per file. func DuplicateLibraries(idx *symbols.Index) []Finding { + // Nearly every library package is declared once, so only the first + // declaration of a name is kept until a second is met. + first := map[string]*symbols.Symbol{} byName := map[string][]*symbols.Symbol{} var order []string for _, doc := range idx.Documents() { @@ -65,19 +68,20 @@ func DuplicateLibraries(idx *symbols.Index) []Finding { if sym.Name == "" || sym.Kind != symbols.SymbolPackage || !(library || symbols.IsLibraryPackage(sym)) { return true } - if _, seen := byName[sym.Name]; !seen { + if before, seen := first[sym.Name]; !seen { + first[sym.Name] = sym + } else if syms := byName[sym.Name]; syms == nil { order = append(order, sym.Name) + byName[sym.Name] = []*symbols.Symbol{before, sym} + } else { + byName[sym.Name] = append(syms, sym) } - byName[sym.Name] = append(byName[sym.Name], sym) return true }) } var dups []duplicate for _, name := range order { syms := byName[name] - if len(syms) < 2 { - continue - } used := usedDeclaration(idx, name, syms) d := duplicate{name: name, used: used} seen := map[string]bool{used.DocName: true} From d0e4d1fdb93848270718fc0b49d03e04eaa63ec0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 06:38:05 +0000 Subject: [PATCH 2/2] docs(changes): write the fragment as the list item the changelog check requires Co-Authored-By: jason.han --- changes/unreleased/duplicate-libraries-walk.fixed.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/changes/unreleased/duplicate-libraries-walk.fixed.md b/changes/unreleased/duplicate-libraries-walk.fixed.md index 1cf932a6e6..a7e1191df4 100644 --- a/changes/unreleased/duplicate-libraries-walk.fixed.md +++ b/changes/unreleased/duplicate-libraries-walk.fixed.md @@ -1,5 +1 @@ -The duplicate-library check of #1462 keeps only the first declaration of each library package -name until a second is met, instead of a list per name. Loading an empty model into a REPL -allocates 2 038 times instead of 2 155, recovering most of what #1462 added over 0.11.0's 2 022 -on the same toolchain; the walk over every library document's root packages remains, so the -load is not back to 0.11.0's time. +- The duplicate-library check of #1462 keeps only the first declaration of each library package name until a second is met, instead of a list per name. Loading an empty model into a REPL allocates 2 038 times instead of 2 155, recovering most of what #1462 added over 0.11.0's 2 022 on the same toolchain; the walk over every library document's root packages remains, so the load is not back to 0.11.0's time.