This change borrows code from CL 631356 by Emmanuel Odeke (thanks!).
Fixes #70549.
Change-Id: Id6f794ea2a95b4297999456f22c6e02890fce13b
Reviewed-on: https://go-review.googlesource.com/c/go/+/662775
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Mark Freeman <mark@golang.org>
exp = pkg.scope.Lookup(sel)
if exp == nil {
if !pkg.fake && isValidName(sel) {
- check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e))
+ // Try to give a better error message when selector matches an object name ignoring case.
+ exps := pkg.scope.lookupIgnoringCase(sel, true)
+ if len(exps) >= 1 {
+ // report just the first one
+ check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s (but have %s)", syntax.Expr(e), exps[0].Name())
+ } else {
+ check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e))
+ }
}
goto Error
}
return obj
}
+// lookupIgnoringCase returns the objects in scope s whose names match
+// the given name ignoring case. If exported is set, only exported names
+// are returned.
+func (s *Scope) lookupIgnoringCase(name string, exported bool) []Object {
+ var matches []Object
+ for _, n := range s.Names() {
+ if (!exported || isExported(n)) && strings.EqualFold(n, name) {
+ matches = append(matches, s.Lookup(n))
+ }
+ }
+ return matches
+}
+
// Insert attempts to insert an object obj into scope s.
// If s already contains an alternative object alt with
// the same name, Insert leaves s unchanged and returns alt.
exp = pkg.scope.Lookup(sel)
if exp == nil {
if !pkg.fake && isValidName(sel) {
- check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e))
+ // Try to give a better error message when selector matches an object name ignoring case.
+ exps := pkg.scope.lookupIgnoringCase(sel, true)
+ if len(exps) >= 1 {
+ // report just the first one
+ check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s (but have %s)", ast.Expr(e), exps[0].Name())
+ } else {
+ check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e))
+ }
}
goto Error
}
return obj
}
+// lookupIgnoringCase returns the objects in scope s whose names match
+// the given name ignoring case. If exported is set, only exported names
+// are returned.
+func (s *Scope) lookupIgnoringCase(name string, exported bool) []Object {
+ var matches []Object
+ for _, n := range s.Names() {
+ if (!exported || isExported(n)) && strings.EqualFold(n, name) {
+ matches = append(matches, s.Lookup(n))
+ }
+ }
+ return matches
+}
+
// Insert attempts to insert an object obj into scope s.
// If s already contains an alternative object alt with
// the same name, Insert leaves s unchanged and returns alt.
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import "math"
+
+var (
+ _ = math.Sin
+ _ = math.SIn /* ERROR "undefined: math.SIn (but have Sin)" */
+ _ = math.sin /* ERROR "name sin not exported by package math" */
+ _ = math.Foo /* ERROR "undefined: math.Foo" */
+ _ = math.foo /* ERROR "undefined: math.foo" */
+)