Skip to content

Commit

Permalink
go/types, types2: avoid spurious "undefined" errors" for invalid iden…
Browse files Browse the repository at this point in the history
…tifiers

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 <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Tim King <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
  • Loading branch information
griesemer authored and gopherbot committed Aug 6, 2024
1 parent 44ed517 commit 5bd442a
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 6 deletions.
6 changes: 4 additions & 2 deletions src/cmd/compile/internal/types2/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/cmd/compile/internal/types2/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -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] }

Expand Down Expand Up @@ -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
}
29 changes: 29 additions & 0 deletions src/cmd/compile/internal/types2/testdata/local/issue68183.go
Original file line number Diff line number Diff line change
@@ -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"
)

funcm /* ERROR "invalid character" */ () {}

type T struct{}
func (T) ☹m /* ERROR "invalid character" */ () {}

func _() {
var x T
x.☹m /* ERROR "invalid character" */ ()
}
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/types2/typexpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions src/go/types/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/go/types/predicates.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/go/types/typexpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 5bd442a

Please sign in to comment.