From 76b39959f4edc8b877506fe7cfe674ceaf64a627 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 16 Jul 2021 13:15:24 -0400 Subject: [PATCH] [dev.typeparams] go/types: don't permit method calls on ptr to type parameter receivers This is a port of CL 332609 to go/types. Change-Id: I3482ea1b97bc7101b987ef312cd6cade80a5843f Reviewed-on: https://go-review.googlesource.com/c/go/+/335112 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/lookup.go | 10 ++++++---- src/go/types/testdata/check/issues.go2 | 10 ++++------ .../types/testdata/fixedbugs/issue47031.go2 | 20 +++++++++++++++++++ src/go/types/type.go | 12 +++++------ 4 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 src/go/types/testdata/fixedbugs/issue47031.go2 diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 70e3b4281d7..304ae6e3c90 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -75,10 +75,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o typ, isPtr := deref(T) - // *typ where typ is an interface has no methods. - // Be cautious: typ may be nil (issue 39634, crash #3). - if typ == nil || isPtr && IsInterface(typ) { - return + // *typ where typ is an interface or type parameter has no methods. + switch under(typ).(type) { + case *Interface, *TypeParam: + if isPtr { + return + } } // Start with typ as single entry at shallowest depth. diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index c655fb99a4f..607da1df19e 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -24,22 +24,20 @@ func _() { eql[io.Reader](nil, nil) } -// If we have a receiver of pointer type (below: *T) we must ignore -// the pointer in the implementation of the method lookup because -// the type bound of T is an interface and pointer to interface types -// have no methods and then the lookup would fail. +// If we have a receiver of pointer to type parameter type (below: *T) +// we don't have any methods, like for interfaces. type C[T any] interface { m() } // using type bound C func _[T C[T]](x *T) { - x.m() + x.m /* ERROR x\.m undefined */ () } // using an interface literal as bound func _[T interface{ m() }](x *T) { - x.m() + x.m /* ERROR x\.m undefined */ () } // In a generic function body all method calls will be pointer method calls. diff --git a/src/go/types/testdata/fixedbugs/issue47031.go2 b/src/go/types/testdata/fixedbugs/issue47031.go2 new file mode 100644 index 00000000000..b184f9b5b7d --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue47031.go2 @@ -0,0 +1,20 @@ +// Copyright 2021 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 + +type Mer interface { M() } + +func F[T Mer](p *T) { + p.M /* ERROR p\.M undefined */ () +} + +type MyMer int + +func (MyMer) M() {} + +func _() { + F(new(MyMer)) + F[Mer](nil) +} diff --git a/src/go/types/type.go b/src/go/types/type.go index 662dd859f09..0a6fff0dcab 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -113,11 +113,6 @@ func asSignature(t Type) *Signature { return op } -func asInterface(t Type) *Interface { - op, _ := optype(t).(*Interface) - return op -} - func asMap(t Type) *Map { op, _ := optype(t).(*Map) return op @@ -128,10 +123,15 @@ func asChan(t Type) *Chan { return op } -// If the argument to asNamed and asTypeParam is of the respective types +// If the argument to asInterface, asNamed, or asTypeParam is of the respective type // (possibly after expanding an instance type), these methods return that type. // Otherwise the result is nil. +func asInterface(t Type) *Interface { + op, _ := optype(t).(*Interface) + return op +} + func asNamed(t Type) *Named { e, _ := expand(t).(*Named) return e