Skip to content

Commit 5bd442a

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: avoid spurious "undefined" errors" for invalid identifiers
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>
1 parent 44ed517 commit 5bd442a

File tree

7 files changed

+63
-6
lines changed

7 files changed

+63
-6
lines changed

src/cmd/compile/internal/types2/call.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -706,14 +706,16 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
706706
}
707707
}
708708
if exp == nil {
709-
check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e)) // cast to syntax.Expr to silence vet
709+
if isValidName(sel) {
710+
check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e)) // cast to syntax.Expr to silence vet
711+
}
710712
goto Error
711713
}
712714
check.objDecl(exp, nil)
713715
} else {
714716
exp = pkg.scope.Lookup(sel)
715717
if exp == nil {
716-
if !pkg.fake {
718+
if !pkg.fake && isValidName(sel) {
717719
check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", syntax.Expr(e))
718720
}
719721
goto Error

src/cmd/compile/internal/types2/predicates.go

+12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
package types2
88

9+
import "unicode"
10+
911
// isValid reports whether t is a valid type.
1012
func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
1113

@@ -567,3 +569,13 @@ func clone[P *T, T any](p P) P {
567569
c := *p
568570
return &c
569571
}
572+
573+
// isValidName reports whether s is a valid Go identifier.
574+
func isValidName(s string) bool {
575+
for i, ch := range s {
576+
if !(unicode.IsLetter(ch) || ch == '_' || i > 0 && unicode.IsDigit(ch)) {
577+
return false
578+
}
579+
}
580+
return true
581+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Test that invalid identifiers reported by the parser
6+
// don't lead to additional errors during typechecking.
7+
8+
package p
9+
10+
import "fmt"
11+
12+
var (
13+
x /* ERROR "invalid character" */ int
14+
_ =x // ERROR "invalid character"
15+
_ = fmt.☹x // ERROR "invalid character"
16+
_ =fmt /* ERROR "invalid character" */ .Println
17+
_ = _世界 // ERROR "undefined: _世界"
18+
_ =_世界 // ERROR "invalid character"
19+
)
20+
21+
funcm /* ERROR "invalid character" */ () {}
22+
23+
type T struct{}
24+
func (T) ☹m /* ERROR "invalid character" */ () {}
25+
26+
func _() {
27+
var x T
28+
x.☹m /* ERROR "invalid character" */ ()
29+
}

src/cmd/compile/internal/types2/typexpr.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
2929
case nil:
3030
if e.Value == "_" {
3131
check.error(e, InvalidBlank, "cannot use _ as value or type")
32-
} else {
32+
} else if isValidName(e.Value) {
3333
check.errorf(e, UndeclaredName, "undefined: %s", e.Value)
3434
}
3535
return

src/go/types/call.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -709,14 +709,16 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
709709
}
710710
}
711711
if exp == nil {
712-
check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e)) // cast to ast.Expr to silence vet
712+
if isValidName(sel) {
713+
check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e)) // cast to ast.Expr to silence vet
714+
}
713715
goto Error
714716
}
715717
check.objDecl(exp, nil)
716718
} else {
717719
exp = pkg.scope.Lookup(sel)
718720
if exp == nil {
719-
if !pkg.fake {
721+
if !pkg.fake && isValidName(sel) {
720722
check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e))
721723
}
722724
goto Error

src/go/types/predicates.go

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/go/types/typexpr.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo
3030
case nil:
3131
if e.Name == "_" {
3232
check.error(e, InvalidBlank, "cannot use _ as value or type")
33-
} else {
33+
} else if isValidName(e.Name) {
3434
check.errorf(e, UndeclaredName, "undefined: %s", e.Name)
3535
}
3636
return

0 commit comments

Comments
 (0)