mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
go/types, types2: don't look up fields or methods when expecting a type
As we have seen many times, the type checker must be careful to avoid accessing named type information before the type is fully set up. We need a more systematic solution to this problem, but for now avoid one case that causes a crash: checking a selector expression on an incomplete type when a type expression is expected. For golang/go#57522 Change-Id: I7ed31b859cca263276e3a0647d1f1b49670023a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/461577 Run-TryBot: Robert Findley <rfindley@google.com> Auto-Submit: Robert Findley <rfindley@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
18625d9bec
commit
245e95dfab
@ -447,7 +447,7 @@ var cgoPrefixes = [...]string{
|
|||||||
"_Cmacro_", // function to evaluate the expanded expression
|
"_Cmacro_", // function to evaluate the expanded expression
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) {
|
func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named, wantType bool) {
|
||||||
// these must be declared before the "goto Error" statements
|
// these must be declared before the "goto Error" statements
|
||||||
var (
|
var (
|
||||||
obj Object
|
obj Object
|
||||||
@ -559,6 +559,25 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) {
|
|||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid crashing when checking an invalid selector in a method declaration
|
||||||
|
// (i.e., where def is not set):
|
||||||
|
//
|
||||||
|
// type S[T any] struct{}
|
||||||
|
// type V = S[any]
|
||||||
|
// func (fs *S[T]) M(x V.M) {}
|
||||||
|
//
|
||||||
|
// All codepaths below return a non-type expression. If we get here while
|
||||||
|
// expecting a type expression, it is an error.
|
||||||
|
//
|
||||||
|
// See issue #57522 for more details.
|
||||||
|
//
|
||||||
|
// TODO(rfindley): We should do better by refusing to check selectors in all cases where
|
||||||
|
// x.typ is incomplete.
|
||||||
|
if wantType {
|
||||||
|
check.errorf(e.Sel, NotAType, "%s is not a type", syntax.Expr(e))
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
|
||||||
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
// Don't report another error if the underlying type was invalid (issue #49541).
|
// Don't report another error if the underlying type was invalid (issue #49541).
|
||||||
|
@ -1587,7 +1587,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
|||||||
return kind
|
return kind
|
||||||
|
|
||||||
case *syntax.SelectorExpr:
|
case *syntax.SelectorExpr:
|
||||||
check.selector(x, e, nil)
|
check.selector(x, e, nil, false)
|
||||||
|
|
||||||
case *syntax.IndexExpr:
|
case *syntax.IndexExpr:
|
||||||
if check.indexExpr(x, e) {
|
if check.indexExpr(x, e) {
|
||||||
|
@ -256,7 +256,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
|
|||||||
|
|
||||||
case *syntax.SelectorExpr:
|
case *syntax.SelectorExpr:
|
||||||
var x operand
|
var x operand
|
||||||
check.selector(&x, e, def)
|
check.selector(&x, e, def, true)
|
||||||
|
|
||||||
switch x.mode {
|
switch x.mode {
|
||||||
case typexpr:
|
case typexpr:
|
||||||
|
@ -450,7 +450,7 @@ var cgoPrefixes = [...]string{
|
|||||||
"_Cmacro_", // function to evaluate the expanded expression
|
"_Cmacro_", // function to evaluate the expanded expression
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named) {
|
func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named, wantType bool) {
|
||||||
// these must be declared before the "goto Error" statements
|
// these must be declared before the "goto Error" statements
|
||||||
var (
|
var (
|
||||||
obj Object
|
obj Object
|
||||||
@ -563,6 +563,25 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named) {
|
|||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid crashing when checking an invalid selector in a method declaration
|
||||||
|
// (i.e., where def is not set):
|
||||||
|
//
|
||||||
|
// type S[T any] struct{}
|
||||||
|
// type V = S[any]
|
||||||
|
// func (fs *S[T]) M(x V.M) {}
|
||||||
|
//
|
||||||
|
// All codepaths below return a non-type expression. If we get here while
|
||||||
|
// expecting a type expression, it is an error.
|
||||||
|
//
|
||||||
|
// See issue #57522 for more details.
|
||||||
|
//
|
||||||
|
// TODO(rfindley): We should do better by refusing to check selectors in all cases where
|
||||||
|
// x.typ is incomplete.
|
||||||
|
if wantType {
|
||||||
|
check.errorf(e.Sel, NotAType, "%s is not a type", ast.Expr(e))
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
|
||||||
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
// Don't report another error if the underlying type was invalid (issue #49541).
|
// Don't report another error if the underlying type was invalid (issue #49541).
|
||||||
|
@ -1568,7 +1568,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||||||
return kind
|
return kind
|
||||||
|
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
check.selector(x, e, nil)
|
check.selector(x, e, nil, false)
|
||||||
|
|
||||||
case *ast.IndexExpr, *ast.IndexListExpr:
|
case *ast.IndexExpr, *ast.IndexListExpr:
|
||||||
ix := typeparams.UnpackIndexExpr(e)
|
ix := typeparams.UnpackIndexExpr(e)
|
||||||
|
@ -256,7 +256,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
|
|||||||
|
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
var x operand
|
var x operand
|
||||||
check.selector(&x, e, def)
|
check.selector(&x, e, def, true)
|
||||||
|
|
||||||
switch x.mode {
|
switch x.mode {
|
||||||
case typexpr:
|
case typexpr:
|
||||||
|
2
src/internal/types/testdata/check/cycles0.go
vendored
2
src/internal/types/testdata/check/cycles0.go
vendored
@ -45,7 +45,7 @@ type (
|
|||||||
|
|
||||||
// pointers
|
// pointers
|
||||||
P0 *P0
|
P0 *P0
|
||||||
PP *struct{ PP.f /* ERROR no field or method f */ }
|
PP *struct{ PP.f /* ERROR PP.f is not a type */ }
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
F0 func(F0)
|
F0 func(F0)
|
||||||
|
10
src/internal/types/testdata/check/decls0.go
vendored
10
src/internal/types/testdata/check/decls0.go
vendored
@ -63,7 +63,7 @@ type (
|
|||||||
|
|
||||||
|
|
||||||
type (
|
type (
|
||||||
p1 pi.foo /* ERROR "no field or method foo" */
|
p1 pi.foo /* ERROR "pi.foo is not a type" */
|
||||||
p2 unsafe.Pointer
|
p2 unsafe.Pointer
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -189,10 +189,10 @@ func f4() (x *f4 /* ERROR "not a type" */ ) { return }
|
|||||||
// TODO(#43215) this should be detected as a cycle error
|
// TODO(#43215) this should be detected as a cycle error
|
||||||
func f5([unsafe.Sizeof(f5)]int) {}
|
func f5([unsafe.Sizeof(f5)]int) {}
|
||||||
|
|
||||||
func (S0) m1 (x S0 /* ERROR illegal cycle in method declaration */ .m1) {}
|
func (S0) m1 (x S0.m1 /* ERROR S0.m1 is not a type */ ) {}
|
||||||
func (S0) m2 (x *S0 /* ERROR illegal cycle in method declaration */ .m2) {}
|
func (S0) m2 (x *S0.m2 /* ERROR S0.m2 is not a type */ ) {}
|
||||||
func (S0) m3 () (x S0 /* ERROR illegal cycle in method declaration */ .m3) { return }
|
func (S0) m3 () (x S0.m3 /* ERROR S0.m3 is not a type */ ) { return }
|
||||||
func (S0) m4 () (x *S0 /* ERROR illegal cycle in method declaration */ .m4) { return }
|
func (S0) m4 () (x *S0.m4 /* ERROR S0.m4 is not a type */ ) { return }
|
||||||
|
|
||||||
// interfaces may not have any blank methods
|
// interfaces may not have any blank methods
|
||||||
type BlankI interface {
|
type BlankI interface {
|
||||||
|
2
src/internal/types/testdata/check/issues0.go
vendored
2
src/internal/types/testdata/check/issues0.go
vendored
@ -97,7 +97,7 @@ func issue10979() {
|
|||||||
nosuchpkg /* ERROR undefined: nosuchpkg */ .Nosuchtype
|
nosuchpkg /* ERROR undefined: nosuchpkg */ .Nosuchtype
|
||||||
}
|
}
|
||||||
type I interface {
|
type I interface {
|
||||||
I.m /* ERROR no field or method m */
|
I.m /* ERROR I.m is not a type */
|
||||||
m()
|
m()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ func(*ph1[e,e /* ERROR redeclared */ ])h(d /* ERROR undefined */ )
|
|||||||
// func t2[T Numeric2](s[]T){0 /* ERROR not a type */ []{s /* ERROR cannot index */ [0][0]}}
|
// func t2[T Numeric2](s[]T){0 /* ERROR not a type */ []{s /* ERROR cannot index */ [0][0]}}
|
||||||
|
|
||||||
// crash 3
|
// crash 3
|
||||||
type t3 *interface{ t3.p /* ERROR no field or method p */ }
|
type t3 *interface{ t3.p /* ERROR t3.p is not a type */ }
|
||||||
|
|
||||||
// crash 4
|
// crash 4
|
||||||
type Numeric4 interface{t4 /* ERROR not a type */ }
|
type Numeric4 interface{t4 /* ERROR not a type */ }
|
||||||
|
24
src/internal/types/testdata/fixedbugs/issue57522.go
vendored
Normal file
24
src/internal/types/testdata/fixedbugs/issue57522.go
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2023 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
|
||||||
|
|
||||||
|
// A simplified version of the code in the original report.
|
||||||
|
type S[T any] struct{}
|
||||||
|
var V = S[any]{}
|
||||||
|
func (fs *S[T]) M(V.M /* ERROR "V.M is not a type" */) {}
|
||||||
|
|
||||||
|
// Other minimal reproducers.
|
||||||
|
type S1[T any] V1.M /* ERROR "V1.M is not a type" */
|
||||||
|
type V1 = S1[any]
|
||||||
|
|
||||||
|
type S2[T any] struct{}
|
||||||
|
type V2 = S2[any]
|
||||||
|
func (fs *S2[T]) M(x V2.M /* ERROR "V2.M is not a type" */ ) {}
|
||||||
|
|
||||||
|
// The following still panics, as the selector is reached from check.expr
|
||||||
|
// rather than check.typexpr. TODO(rfindley): fix this.
|
||||||
|
// type X[T any] int
|
||||||
|
// func (X[T]) M(x [X[int].M]int) {}
|
||||||
|
|
@ -10,5 +10,5 @@ type A interface {
|
|||||||
// TODO(mdempsky): This should be an error, but this error is
|
// TODO(mdempsky): This should be an error, but this error is
|
||||||
// nonsense. The error should actually mention that there's a
|
// nonsense. The error should actually mention that there's a
|
||||||
// type loop.
|
// type loop.
|
||||||
Fn(A.Fn) // ERROR "type A has no method Fn|A.Fn undefined"
|
Fn(A.Fn) // ERROR "type A has no method Fn|A.Fn undefined|A.Fn is not a type"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user