Skip to content

Commit 245e95d

Browse files
findleyrgopherbot
authored andcommitted
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#57522 Change-Id: I7ed31b859cca263276e3a0647d1f1b49670023a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/461577 Run-TryBot: Robert Findley <[email protected]> Auto-Submit: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent 18625d9 commit 245e95d

File tree

12 files changed

+77
-15
lines changed

12 files changed

+77
-15
lines changed

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ var cgoPrefixes = [...]string{
447447
"_Cmacro_", // function to evaluate the expanded expression
448448
}
449449

450-
func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) {
450+
func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named, wantType bool) {
451451
// these must be declared before the "goto Error" statements
452452
var (
453453
obj Object
@@ -559,6 +559,25 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) {
559559
goto Error
560560
}
561561

562+
// Avoid crashing when checking an invalid selector in a method declaration
563+
// (i.e., where def is not set):
564+
//
565+
// type S[T any] struct{}
566+
// type V = S[any]
567+
// func (fs *S[T]) M(x V.M) {}
568+
//
569+
// All codepaths below return a non-type expression. If we get here while
570+
// expecting a type expression, it is an error.
571+
//
572+
// See issue #57522 for more details.
573+
//
574+
// TODO(rfindley): We should do better by refusing to check selectors in all cases where
575+
// x.typ is incomplete.
576+
if wantType {
577+
check.errorf(e.Sel, NotAType, "%s is not a type", syntax.Expr(e))
578+
goto Error
579+
}
580+
562581
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
563582
if obj == nil {
564583
// Don't report another error if the underlying type was invalid (issue #49541).

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1587,7 +1587,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
15871587
return kind
15881588

15891589
case *syntax.SelectorExpr:
1590-
check.selector(x, e, nil)
1590+
check.selector(x, e, nil, false)
15911591

15921592
case *syntax.IndexExpr:
15931593
if check.indexExpr(x, e) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
256256

257257
case *syntax.SelectorExpr:
258258
var x operand
259-
check.selector(&x, e, def)
259+
check.selector(&x, e, def, true)
260260

261261
switch x.mode {
262262
case typexpr:

src/go/types/call.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ var cgoPrefixes = [...]string{
450450
"_Cmacro_", // function to evaluate the expanded expression
451451
}
452452

453-
func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named) {
453+
func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named, wantType bool) {
454454
// these must be declared before the "goto Error" statements
455455
var (
456456
obj Object
@@ -563,6 +563,25 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named) {
563563
goto Error
564564
}
565565

566+
// Avoid crashing when checking an invalid selector in a method declaration
567+
// (i.e., where def is not set):
568+
//
569+
// type S[T any] struct{}
570+
// type V = S[any]
571+
// func (fs *S[T]) M(x V.M) {}
572+
//
573+
// All codepaths below return a non-type expression. If we get here while
574+
// expecting a type expression, it is an error.
575+
//
576+
// See issue #57522 for more details.
577+
//
578+
// TODO(rfindley): We should do better by refusing to check selectors in all cases where
579+
// x.typ is incomplete.
580+
if wantType {
581+
check.errorf(e.Sel, NotAType, "%s is not a type", ast.Expr(e))
582+
goto Error
583+
}
584+
566585
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
567586
if obj == nil {
568587
// Don't report another error if the underlying type was invalid (issue #49541).

src/go/types/expr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
15681568
return kind
15691569

15701570
case *ast.SelectorExpr:
1571-
check.selector(x, e, nil)
1571+
check.selector(x, e, nil, false)
15721572

15731573
case *ast.IndexExpr, *ast.IndexListExpr:
15741574
ix := typeparams.UnpackIndexExpr(e)

src/go/types/typexpr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
256256

257257
case *ast.SelectorExpr:
258258
var x operand
259-
check.selector(&x, e, def)
259+
check.selector(&x, e, def, true)
260260

261261
switch x.mode {
262262
case typexpr:

src/internal/types/testdata/check/cycles0.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type (
4545

4646
// pointers
4747
P0 *P0
48-
PP *struct{ PP.f /* ERROR no field or method f */ }
48+
PP *struct{ PP.f /* ERROR PP.f is not a type */ }
4949

5050
// functions
5151
F0 func(F0)

src/internal/types/testdata/check/decls0.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type (
6363

6464

6565
type (
66-
p1 pi.foo /* ERROR "no field or method foo" */
66+
p1 pi.foo /* ERROR "pi.foo is not a type" */
6767
p2 unsafe.Pointer
6868
)
6969

@@ -189,10 +189,10 @@ func f4() (x *f4 /* ERROR "not a type" */ ) { return }
189189
// TODO(#43215) this should be detected as a cycle error
190190
func f5([unsafe.Sizeof(f5)]int) {}
191191

192-
func (S0) m1 (x S0 /* ERROR illegal cycle in method declaration */ .m1) {}
193-
func (S0) m2 (x *S0 /* ERROR illegal cycle in method declaration */ .m2) {}
194-
func (S0) m3 () (x S0 /* ERROR illegal cycle in method declaration */ .m3) { return }
195-
func (S0) m4 () (x *S0 /* ERROR illegal cycle in method declaration */ .m4) { return }
192+
func (S0) m1 (x S0.m1 /* ERROR S0.m1 is not a type */ ) {}
193+
func (S0) m2 (x *S0.m2 /* ERROR S0.m2 is not a type */ ) {}
194+
func (S0) m3 () (x S0.m3 /* ERROR S0.m3 is not a type */ ) { return }
195+
func (S0) m4 () (x *S0.m4 /* ERROR S0.m4 is not a type */ ) { return }
196196

197197
// interfaces may not have any blank methods
198198
type BlankI interface {

src/internal/types/testdata/check/issues0.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func issue10979() {
9797
nosuchpkg /* ERROR undefined: nosuchpkg */ .Nosuchtype
9898
}
9999
type I interface {
100-
I.m /* ERROR no field or method m */
100+
I.m /* ERROR I.m is not a type */
101101
m()
102102
}
103103
}

src/internal/types/testdata/fixedbugs/issue39634.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func(*ph1[e,e /* ERROR redeclared */ ])h(d /* ERROR undefined */ )
1919
// func t2[T Numeric2](s[]T){0 /* ERROR not a type */ []{s /* ERROR cannot index */ [0][0]}}
2020

2121
// crash 3
22-
type t3 *interface{ t3.p /* ERROR no field or method p */ }
22+
type t3 *interface{ t3.p /* ERROR t3.p is not a type */ }
2323

2424
// crash 4
2525
type Numeric4 interface{t4 /* ERROR not a type */ }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2023 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+
package p
6+
7+
// A simplified version of the code in the original report.
8+
type S[T any] struct{}
9+
var V = S[any]{}
10+
func (fs *S[T]) M(V.M /* ERROR "V.M is not a type" */) {}
11+
12+
// Other minimal reproducers.
13+
type S1[T any] V1.M /* ERROR "V1.M is not a type" */
14+
type V1 = S1[any]
15+
16+
type S2[T any] struct{}
17+
type V2 = S2[any]
18+
func (fs *S2[T]) M(x V2.M /* ERROR "V2.M is not a type" */ ) {}
19+
20+
// The following still panics, as the selector is reached from check.expr
21+
// rather than check.typexpr. TODO(rfindley): fix this.
22+
// type X[T any] int
23+
// func (X[T]) M(x [X[int].M]int) {}
24+

test/fixedbugs/issue18392.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ type A interface {
1010
// TODO(mdempsky): This should be an error, but this error is
1111
// nonsense. The error should actually mention that there's a
1212
// type loop.
13-
Fn(A.Fn) // ERROR "type A has no method Fn|A.Fn undefined"
13+
Fn(A.Fn) // ERROR "type A has no method Fn|A.Fn undefined|A.Fn is not a type"
1414
}

0 commit comments

Comments
 (0)