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>
}
}
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
package types2
+import "unicode"
+
// isValid reports whether t is a valid type.
func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
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
+}
--- /dev/null
+// 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" */ ()
+}
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
}
}
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
package types
+import "unicode"
+
// isValid reports whether t is a valid type.
func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
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
+}
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