mirror of https://github.com/golang/go.git
go/types, types2: delay receiver type validation
Delay validation of receiver type as it may cause premature expansion of types the receiver type is dependent on. This was actually a TODO. While the diff looks large-ish, the actual change is small: all the receiver validation code has been moved inside the delayed function body, and a couple of comments have been adjusted. Fixes #51232. Fixes #51233. Change-Id: I44edf0ba615996266791724b832d81b9ccb8b435 Reviewed-on: https://go-review.googlesource.com/c/go/+/387918 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
55e5b03cb3
commit
7c694fbad1
|
|
@ -194,66 +194,69 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||||
case 1:
|
case 1:
|
||||||
recv = recvList[0]
|
recv = recvList[0]
|
||||||
}
|
}
|
||||||
|
sig.recv = recv
|
||||||
|
|
||||||
// TODO(gri) We should delay rtyp expansion to when we actually need the
|
// Delay validation of receiver type as it may cause premature expansion
|
||||||
// receiver; thus all checks here should be delayed to later.
|
// of types the receiver type is dependent on (see issues #51232, #51233).
|
||||||
rtyp, _ := deref(recv.typ)
|
check.later(func() {
|
||||||
|
rtyp, _ := deref(recv.typ)
|
||||||
|
|
||||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||||
// (ignore invalid types - error was reported before)
|
// (ignore invalid types - error was reported before)
|
||||||
if rtyp != Typ[Invalid] {
|
if rtyp != Typ[Invalid] {
|
||||||
var err string
|
var err string
|
||||||
switch T := rtyp.(type) {
|
switch T := rtyp.(type) {
|
||||||
case *Named:
|
case *Named:
|
||||||
T.resolve(check.bestContext(nil))
|
T.resolve(check.bestContext(nil))
|
||||||
// The receiver type may be an instantiated type referred to
|
// The receiver type may be an instantiated type referred to
|
||||||
// by an alias (which cannot have receiver parameters for now).
|
// by an alias (which cannot have receiver parameters for now).
|
||||||
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
||||||
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
|
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||||
// be a pointer or interface type and it must be declared in the same package
|
// be a pointer or interface type and it must be declared in the same package
|
||||||
// as the method."
|
// as the method."
|
||||||
if T.obj.pkg != check.pkg {
|
if T.obj.pkg != check.pkg {
|
||||||
err = "type not defined in this package"
|
err = "type not defined in this package"
|
||||||
|
if check.conf.CompilerErrorMessages {
|
||||||
|
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
|
||||||
|
err = ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The underlying type of a receiver base type can be a type parameter;
|
||||||
|
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
||||||
|
// TODO(gri) Such declarations are currently disallowed.
|
||||||
|
// Revisit the need for underIs.
|
||||||
|
underIs(T, func(u Type) bool {
|
||||||
|
switch u := u.(type) {
|
||||||
|
case *Basic:
|
||||||
|
// unsafe.Pointer is treated like a regular pointer
|
||||||
|
if u.kind == UnsafePointer {
|
||||||
|
err = "unsafe.Pointer"
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case *Pointer, *Interface:
|
||||||
|
err = "pointer or interface type"
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case *Basic:
|
||||||
|
err = "basic or unnamed type"
|
||||||
if check.conf.CompilerErrorMessages {
|
if check.conf.CompilerErrorMessages {
|
||||||
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
|
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
|
||||||
err = ""
|
err = ""
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
// The underlying type of a receiver base type can be a type parameter;
|
check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
|
||||||
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
|
||||||
underIs(T, func(u Type) bool {
|
|
||||||
switch u := u.(type) {
|
|
||||||
case *Basic:
|
|
||||||
// unsafe.Pointer is treated like a regular pointer
|
|
||||||
if u.kind == UnsafePointer {
|
|
||||||
err = "unsafe.Pointer"
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case *Pointer, *Interface:
|
|
||||||
err = "pointer or interface type"
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
case *Basic:
|
if err != "" {
|
||||||
err = "basic or unnamed type"
|
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
|
||||||
if check.conf.CompilerErrorMessages {
|
|
||||||
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
|
|
||||||
err = ""
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
|
|
||||||
}
|
}
|
||||||
if err != "" {
|
}).describef(recv, "validate receiver %s", recv)
|
||||||
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
|
|
||||||
// ok to continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sig.recv = recv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sig.params = NewTuple(params...)
|
sig.params = NewTuple(params...)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2022 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 RC[RG any] interface {
|
||||||
|
~[]RG
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||||
|
|
||||||
|
type F[RCT RC[RG], RG any] interface {
|
||||||
|
Fn() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
type concreteF[RCT RC[RG], RG any] struct {
|
||||||
|
makeFn func() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||||
|
return c.makeFn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||||
|
return &concreteF[RCT]{
|
||||||
|
makeFn: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2022 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 RC[RG any] interface {
|
||||||
|
~[]RG
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||||
|
|
||||||
|
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||||
|
|
||||||
|
type F[RCT RC[RG], RG any] interface {
|
||||||
|
Fn() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
type concreteF[RCT RC[RG], RG any] struct {
|
||||||
|
makeFn FFn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||||
|
return c.makeFn()
|
||||||
|
}
|
||||||
|
|
@ -193,66 +193,77 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
||||||
switch len(recvList) {
|
switch len(recvList) {
|
||||||
case 0:
|
case 0:
|
||||||
// error reported by resolver
|
// error reported by resolver
|
||||||
recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
|
recv = NewParam(token.NoPos, nil, "", Typ[Invalid]) // ignore recv below
|
||||||
default:
|
default:
|
||||||
// more than one receiver
|
// more than one receiver
|
||||||
check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver")
|
check.error(recvList[len(recvList)-1], _InvalidRecv, "method must have exactly one receiver")
|
||||||
fallthrough // continue with first receiver
|
fallthrough // continue with first receiver
|
||||||
case 1:
|
case 1:
|
||||||
recv = recvList[0]
|
recv = recvList[0]
|
||||||
}
|
}
|
||||||
|
sig.recv = recv
|
||||||
|
|
||||||
// TODO(gri) We should delay rtyp expansion to when we actually need the
|
// Delay validation of receiver type as it may cause premature expansion
|
||||||
// receiver; thus all checks here should be delayed to later.
|
// of types the receiver type is dependent on (see issues #51232, #51233).
|
||||||
rtyp, _ := deref(recv.typ)
|
check.later(func() {
|
||||||
|
rtyp, _ := deref(recv.typ)
|
||||||
|
|
||||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||||
// (ignore invalid types - error was reported before)
|
// (ignore invalid types - error was reported before)
|
||||||
if rtyp != Typ[Invalid] {
|
if rtyp != Typ[Invalid] {
|
||||||
var err string
|
var err string
|
||||||
switch T := rtyp.(type) {
|
switch T := rtyp.(type) {
|
||||||
case *Named:
|
case *Named:
|
||||||
T.resolve(check.bestContext(nil))
|
T.resolve(check.bestContext(nil))
|
||||||
// The receiver type may be an instantiated type referred to
|
// The receiver type may be an instantiated type referred to
|
||||||
// by an alias (which cannot have receiver parameters for now).
|
// by an alias (which cannot have receiver parameters for now).
|
||||||
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
||||||
check.errorf(atPos(recv.pos), _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
|
check.errorf(recv, _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||||
// be a pointer or interface type and it must be declared in the same package
|
// be a pointer or interface type and it must be declared in the same package
|
||||||
// as the method."
|
// as the method."
|
||||||
if T.obj.pkg != check.pkg {
|
if T.obj.pkg != check.pkg {
|
||||||
err = "type not defined in this package"
|
err = "type not defined in this package"
|
||||||
} else {
|
if compilerErrorMessages {
|
||||||
// The underlying type of a receiver base type can be a type parameter;
|
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
|
||||||
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
err = ""
|
||||||
underIs(T, func(u Type) bool {
|
}
|
||||||
switch u := u.(type) {
|
} else {
|
||||||
case *Basic:
|
// The underlying type of a receiver base type can be a type parameter;
|
||||||
// unsafe.Pointer is treated like a regular pointer
|
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
||||||
if u.kind == UnsafePointer {
|
// TODO(gri) Such declarations are currently disallowed.
|
||||||
err = "unsafe.Pointer"
|
// Revisit the need for underIs.
|
||||||
|
underIs(T, func(u Type) bool {
|
||||||
|
switch u := u.(type) {
|
||||||
|
case *Basic:
|
||||||
|
// unsafe.Pointer is treated like a regular pointer
|
||||||
|
if u.kind == UnsafePointer {
|
||||||
|
err = "unsafe.Pointer"
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case *Pointer, *Interface:
|
||||||
|
err = "pointer or interface type"
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case *Pointer, *Interface:
|
return true
|
||||||
err = "pointer or interface type"
|
})
|
||||||
return false
|
}
|
||||||
}
|
case *Basic:
|
||||||
return true
|
err = "basic or unnamed type"
|
||||||
})
|
if compilerErrorMessages {
|
||||||
|
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
|
||||||
|
err = ""
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
|
||||||
|
}
|
||||||
|
if err != "" {
|
||||||
|
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
|
||||||
}
|
}
|
||||||
case *Basic:
|
|
||||||
err = "basic or unnamed type"
|
|
||||||
default:
|
|
||||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
|
|
||||||
}
|
}
|
||||||
if err != "" {
|
}).describef(recv, "validate receiver %s", recv)
|
||||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
|
|
||||||
// ok to continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sig.recv = recv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sig.params = NewTuple(params...)
|
sig.params = NewTuple(params...)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2022 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 RC[RG any] interface {
|
||||||
|
~[]RG
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||||
|
|
||||||
|
type F[RCT RC[RG], RG any] interface {
|
||||||
|
Fn() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
type concreteF[RCT RC[RG], RG any] struct {
|
||||||
|
makeFn func() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||||
|
return c.makeFn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||||
|
return &concreteF[RCT]{
|
||||||
|
makeFn: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2022 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 RC[RG any] interface {
|
||||||
|
~[]RG
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||||
|
|
||||||
|
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||||
|
|
||||||
|
type F[RCT RC[RG], RG any] interface {
|
||||||
|
Fn() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
type concreteF[RCT RC[RG], RG any] struct {
|
||||||
|
makeFn FFn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||||
|
return c.makeFn()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// compile -G=3
|
||||||
|
|
||||||
|
// Copyright 2022 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 RC[RG any] interface {
|
||||||
|
~[]RG
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||||
|
|
||||||
|
type F[RCT RC[RG], RG any] interface {
|
||||||
|
Fn() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
type concreteF[RCT RC[RG], RG any] struct {
|
||||||
|
makeFn func() Fn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||||
|
return c.makeFn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||||
|
return &concreteF[RCT]{
|
||||||
|
makeFn: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
// compile -G=3
|
||||||
|
|
||||||
|
// Copyright 2022 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 RC[RG any] interface {
|
||||||
|
~[]RG
|
||||||
|
}
|
||||||
|
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||||
|
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||||
|
type F[RCT RC[RG], RG any] interface {
|
||||||
|
Fn() Fn[RCT]
|
||||||
|
}
|
||||||
|
type concreteF[RCT RC[RG], RG any] struct {
|
||||||
|
makeFn FFn[RCT]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||||
|
return c.makeFn()
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue