"_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
var (
obj Object
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)
if obj == nil {
// Don't report another error if the underlying type was invalid (issue #49541).
return kind
case *syntax.SelectorExpr:
- check.selector(x, e, nil)
+ check.selector(x, e, nil, false)
case *syntax.IndexExpr:
if check.indexExpr(x, e) {
case *syntax.SelectorExpr:
var x operand
- check.selector(&x, e, def)
+ check.selector(&x, e, def, true)
switch x.mode {
case typexpr:
"_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
var (
obj Object
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)
if obj == nil {
// Don't report another error if the underlying type was invalid (issue #49541).
return kind
case *ast.SelectorExpr:
- check.selector(x, e, nil)
+ check.selector(x, e, nil, false)
case *ast.IndexExpr, *ast.IndexListExpr:
ix := typeparams.UnpackIndexExpr(e)
case *ast.SelectorExpr:
var x operand
- check.selector(&x, e, def)
+ check.selector(&x, e, def, true)
switch x.mode {
case typexpr:
// pointers
P0 *P0
- PP *struct{ PP.f /* ERROR no field or method f */ }
+ PP *struct{ PP.f /* ERROR PP.f is not a type */ }
// functions
F0 func(F0)
type (
- p1 pi.foo /* ERROR "no field or method foo" */
+ p1 pi.foo /* ERROR "pi.foo is not a type" */
p2 unsafe.Pointer
)
// TODO(#43215) this should be detected as a cycle error
func f5([unsafe.Sizeof(f5)]int) {}
-func (S0) m1 (x S0 /* ERROR illegal cycle in method declaration */ .m1) {}
-func (S0) m2 (x *S0 /* ERROR illegal cycle in method declaration */ .m2) {}
-func (S0) m3 () (x S0 /* ERROR illegal cycle in method declaration */ .m3) { return }
-func (S0) m4 () (x *S0 /* ERROR illegal cycle in method declaration */ .m4) { return }
+func (S0) m1 (x S0.m1 /* ERROR S0.m1 is not a type */ ) {}
+func (S0) m2 (x *S0.m2 /* ERROR S0.m2 is not a type */ ) {}
+func (S0) m3 () (x S0.m3 /* ERROR S0.m3 is not a type */ ) { return }
+func (S0) m4 () (x *S0.m4 /* ERROR S0.m4 is not a type */ ) { return }
// interfaces may not have any blank methods
type BlankI interface {
nosuchpkg /* ERROR undefined: nosuchpkg */ .Nosuchtype
}
type I interface {
- I.m /* ERROR no field or method m */
+ I.m /* ERROR I.m is not a type */
m()
}
}
// func t2[T Numeric2](s[]T){0 /* ERROR not a type */ []{s /* ERROR cannot index */ [0][0]}}
// 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
type Numeric4 interface{t4 /* ERROR not a type */ }
--- /dev/null
+// 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) {}
+
// TODO(mdempsky): This should be an error, but this error is
// nonsense. The error should actually mention that there's a
// 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"
}