]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: don't look up fields or methods when expecting a type
authorRobert Findley <rfindley@google.com>
Wed, 11 Jan 2023 19:41:03 +0000 (14:41 -0500)
committerGopher Robot <gobot@golang.org>
Wed, 11 Jan 2023 22:29:34 +0000 (22:29 +0000)
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>
12 files changed:
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/typexpr.go
src/go/types/call.go
src/go/types/expr.go
src/go/types/typexpr.go
src/internal/types/testdata/check/cycles0.go
src/internal/types/testdata/check/decls0.go
src/internal/types/testdata/check/issues0.go
src/internal/types/testdata/fixedbugs/issue39634.go
src/internal/types/testdata/fixedbugs/issue57522.go [new file with mode: 0644]
test/fixedbugs/issue18392.go

index 50343bf77a6aecde608f31310409aaf949497031..7d660ca77244c7dcebf1be68948527784f766c51 100644 (file)
@@ -447,7 +447,7 @@ var cgoPrefixes = [...]string{
        "_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
@@ -559,6 +559,25 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) {
                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).
index 9a0348e0250a4fbd9441d47c292bfc805083b132..a3abbb9532ec36c99924c5da0abbb4172bbc2b7d 100644 (file)
@@ -1587,7 +1587,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                return kind
 
        case *syntax.SelectorExpr:
-               check.selector(x, e, nil)
+               check.selector(x, e, nil, false)
 
        case *syntax.IndexExpr:
                if check.indexExpr(x, e) {
index 4de658b0c4fe8bb42e6d2603e83052dcef930c0b..0f3106d70aa9c3f8f86bf769324fa5957ae71061 100644 (file)
@@ -256,7 +256,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
 
        case *syntax.SelectorExpr:
                var x operand
-               check.selector(&x, e, def)
+               check.selector(&x, e, def, true)
 
                switch x.mode {
                case typexpr:
index 5558244f1beadf8b28a1d7aea418d0b850dbeb2b..db603b5260467cb5289230302e727a4e1f80255d 100644 (file)
@@ -450,7 +450,7 @@ var cgoPrefixes = [...]string{
        "_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
@@ -563,6 +563,25 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named) {
                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).
index e09b461d8c6b9c41abcf05bb9bf1fe84129223e7..aa90145b367e51dc4c69ddba409261b2de1d9696 100644 (file)
@@ -1568,7 +1568,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                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)
index 3d1f0b8bbb0ca2c5bf27504e53b36105e449368c..03817dded19ace430e04a3db12c659583f500c0f 100644 (file)
@@ -256,7 +256,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
 
        case *ast.SelectorExpr:
                var x operand
-               check.selector(&x, e, def)
+               check.selector(&x, e, def, true)
 
                switch x.mode {
                case typexpr:
index d4e7e60f832ac08e7971ffffe66e99922fdba8c7..7c00c7d625f81fa42d85c449fe8369929b7dc8b7 100644 (file)
@@ -45,7 +45,7 @@ type (
 
        // 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)
index 6002a9e8a74d8001a92e0870bebc4e5acb39d2ea..868b318a70f59964f9874a26936c322ec7131d1b 100644 (file)
@@ -63,7 +63,7 @@ type (
 
 
 type (
-       p1 pi.foo /* ERROR "no field or method foo" */
+       p1 pi.foo /* ERROR "pi.foo is not a type" */
        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
 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 {
index 0cea36c01f126efd709103123eb42f28c646e83b..4a6664136969f9fce3bf79af12dfeced05d2a538 100644 (file)
@@ -97,7 +97,7 @@ func issue10979() {
                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()
        }
 }
index 7b458f22f28720ee50f199033e1ce512e657a593..6ee15489c5d23566b47ea470fb89d16647952a16 100644 (file)
@@ -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]}}
 
 // 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 */ }
diff --git a/src/internal/types/testdata/fixedbugs/issue57522.go b/src/internal/types/testdata/fixedbugs/issue57522.go
new file mode 100644 (file)
index 0000000..d83e5b2
--- /dev/null
@@ -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) {}
+
index e0640ed2ee48b408b4a5e6f72c0c1195425e126f..32c39c3a7fea3a924e474138ca4436c9f8179d2e 100644 (file)
@@ -10,5 +10,5 @@ type A interface {
        // 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"
 }