]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: avoid spurious "undefined" errors" for invalid identifiers
authorRobert Griesemer <gri@golang.org>
Thu, 1 Aug 2024 18:16:27 +0000 (11:16 -0700)
committerGopher Robot <gobot@golang.org>
Tue, 6 Aug 2024 22:12:59 +0000 (22:12 +0000)
The syntax parser complains about invalid identifiers.
Don't report a typechecker error when such an identifier
cannot be found in the current scope.

For now add a local test for types2 only because the
go/parser behaves differently than the syntax parser
which leads to slightly different error positions.

Fixes #68183.

Change-Id: Idbfe62fafcd704886069182744ec5e6b37ffc4e1
Reviewed-on: https://go-review.googlesource.com/c/go/+/602476
Auto-Submit: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/testdata/local/issue68183.go [new file with mode: 0644]
src/cmd/compile/internal/types2/typexpr.go
src/go/types/call.go
src/go/types/predicates.go
src/go/types/typexpr.go

index 7df4e8250e4dcd8c60812693cba3debd339ca663..33bea5e9ffdf892ebad2c84387da04112621eaa8 100644 (file)
@@ -706,14 +706,16 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
                                        }
                                }
                                if exp == nil {
-                                       check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e)) // cast to syntax.Expr to silence vet
+                                       if isValidName(sel) {
+                                               check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e)) // cast to syntax.Expr to silence vet
+                                       }
                                        goto Error
                                }
                                check.objDecl(exp, nil)
                        } else {
                                exp = pkg.scope.Lookup(sel)
                                if exp == nil {
-                                       if !pkg.fake {
+                                       if !pkg.fake && isValidName(sel) {
                                                check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e))
                                        }
                                        goto Error
index 155a70fb1912846fb8cc41895ac74e13b96f4c8e..d40939e2b5d0c0a247390abdf1a47c29637d0410 100644 (file)
@@ -6,6 +6,8 @@
 
 package types2
 
+import "unicode"
+
 // isValid reports whether t is a valid type.
 func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
 
@@ -567,3 +569,13 @@ func clone[P *T, T any](p P) P {
        c := *p
        return &c
 }
+
+// isValidName reports whether s is a valid Go identifier.
+func isValidName(s string) bool {
+       for i, ch := range s {
+               if !(unicode.IsLetter(ch) || ch == '_' || i > 0 && unicode.IsDigit(ch)) {
+                       return false
+               }
+       }
+       return true
+}
diff --git a/src/cmd/compile/internal/types2/testdata/local/issue68183.go b/src/cmd/compile/internal/types2/testdata/local/issue68183.go
new file mode 100644 (file)
index 0000000..fcf1669
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2024 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.
+
+// Test that invalid identifiers reported by the parser
+// don't lead to additional errors during typechecking.
+
+package p
+
+import "fmt"
+
+var (
+       ☹x /* ERROR "invalid character" */ int
+       _ = ☹x // ERROR "invalid character"
+       _ = fmt.☹x // ERROR "invalid character"
+       _ = ☹fmt /* ERROR "invalid character" */ .Println
+       _ = _世界 // ERROR "undefined: _世界"
+       _ = ☹_世界 // ERROR "invalid character"
+)
+
+func ☹m /* ERROR "invalid character" */ () {}
+
+type T struct{}
+func (T) ☹m /* ERROR "invalid character" */ () {}
+
+func _() {
+       var x T
+       x.☹m /* ERROR "invalid character" */ ()
+}
index 3966a21693bc1496f553ef51823848fd37462ba5..b917a86c10e9944c4de172e10ab7b5f8c4e010d9 100644 (file)
@@ -29,7 +29,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
        case nil:
                if e.Value == "_" {
                        check.error(e, InvalidBlank, "cannot use _ as value or type")
-               } else {
+               } else if isValidName(e.Value) {
                        check.errorf(e, UndeclaredName, "undefined: %s", e.Value)
                }
                return
index 8f02ffc39729a3488dff5e8b5883fdc0f49e070d..d1324d425ae82a59ed803e760b67dfc46e9768f8 100644 (file)
@@ -709,14 +709,16 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
                                        }
                                }
                                if exp == nil {
-                                       check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e)) // cast to ast.Expr to silence vet
+                                       if isValidName(sel) {
+                                               check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e)) // cast to ast.Expr to silence vet
+                                       }
                                        goto Error
                                }
                                check.objDecl(exp, nil)
                        } else {
                                exp = pkg.scope.Lookup(sel)
                                if exp == nil {
-                                       if !pkg.fake {
+                                       if !pkg.fake && isValidName(sel) {
                                                check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e))
                                        }
                                        goto Error
index 4bfbdccc6f3b46ccc20b5e545531cc20f121f612..5261aaf1585cec04c90816e2ad5215f96403cc60 100644 (file)
@@ -9,6 +9,8 @@
 
 package types
 
+import "unicode"
+
 // isValid reports whether t is a valid type.
 func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
 
@@ -570,3 +572,13 @@ func clone[P *T, T any](p P) P {
        c := *p
        return &c
 }
+
+// isValidName reports whether s is a valid Go identifier.
+func isValidName(s string) bool {
+       for i, ch := range s {
+               if !(unicode.IsLetter(ch) || ch == '_' || i > 0 && unicode.IsDigit(ch)) {
+                       return false
+               }
+       }
+       return true
+}
index 62d75885a63e4aaff408ed8e270f143ac372e24b..926013b16cd482a0f48d07a6cc7d4a31cb3b1307 100644 (file)
@@ -30,7 +30,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo
        case nil:
                if e.Name == "_" {
                        check.error(e, InvalidBlank, "cannot use _ as value or type")
-               } else {
+               } else if isValidName(e.Name) {
                        check.errorf(e, UndeclaredName, "undefined: %s", e.Name)
                }
                return