]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: better error messages for invalid qualified identifiers
authorMark Freeman <markfreeman@google.com>
Thu, 3 Apr 2025 21:26:55 +0000 (14:26 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 3 Apr 2025 22:36:36 +0000 (15:36 -0700)
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>
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/scope.go
src/go/types/call.go
src/go/types/scope.go
src/internal/types/testdata/fixedbugs/issue70549.go [new file with mode: 0644]

index 4d1c7b5f881893064b10f5fc53d1510d62c42173..b7a2ebb41ec9765d3807ab447a58919e9f9f1241 100644 (file)
@@ -720,7 +720,14 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
                                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
                                }
index fc2a261ad6916a37ffe12784fae965be04b8f968..566184df7391375be3616493843c8eeb6fadd1f7 100644 (file)
@@ -83,6 +83,19 @@ func (s *Scope) Lookup(name string) Object {
        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.
index 41663eac8e5222edd2f449e7aca4de60d0de8a4a..33fe8bb9bfa84f8c3f5eb942463585581182825d 100644 (file)
@@ -722,7 +722,14 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
                                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
                                }
index e3fb7b6effb06e3e0a1ecf45803eb42e741dd293..81366df7418ef597e6311e91b741ae9aa0e1f31f 100644 (file)
@@ -86,6 +86,19 @@ func (s *Scope) Lookup(name string) Object {
        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.
diff --git a/src/internal/types/testdata/fixedbugs/issue70549.go b/src/internal/types/testdata/fixedbugs/issue70549.go
new file mode 100644 (file)
index 0000000..eadca0c
--- /dev/null
@@ -0,0 +1,15 @@
+// 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" */
+)