diff --git a/changes/unreleased/duplicate-libraries-walk.fixed.md b/changes/unreleased/duplicate-libraries-walk.fixed.md new file mode 100644 index 0000000000..a7e1191df4 --- /dev/null +++ b/changes/unreleased/duplicate-libraries-walk.fixed.md @@ -0,0 +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. 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}