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,9 +194,11 @@ 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).
|
||||||
|
check.later(func() {
|
||||||
rtyp, _ := deref(recv.typ)
|
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."
|
||||||
|
|
@ -224,6 +226,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||||
} else {
|
} else {
|
||||||
// The underlying type of a receiver base type can be a type parameter;
|
// 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.
|
// 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 {
|
underIs(T, func(u Type) bool {
|
||||||
switch u := u.(type) {
|
switch u := u.(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
|
|
@ -250,10 +254,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||||
}
|
}
|
||||||
if err != "" {
|
if err != "" {
|
||||||
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
|
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
|
||||||
// ok to continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sig.recv = recv
|
}).describef(recv, "validate receiver %s", 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,17 +193,19 @@ 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).
|
||||||
|
check.later(func() {
|
||||||
rtyp, _ := deref(recv.typ)
|
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."
|
||||||
|
|
@ -216,7 +218,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
||||||
// 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
|
||||||
|
|
@ -224,9 +226,15 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
||||||
// 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 compilerErrorMessages {
|
||||||
|
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
|
||||||
|
err = ""
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// The underlying type of a receiver base type can be a type parameter;
|
// 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.
|
// 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 {
|
underIs(T, func(u Type) bool {
|
||||||
switch u := u.(type) {
|
switch u := u.(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
|
|
@ -244,15 +252,18 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
||||||
}
|
}
|
||||||
case *Basic:
|
case *Basic:
|
||||||
err = "basic or unnamed type"
|
err = "basic or unnamed type"
|
||||||
|
if compilerErrorMessages {
|
||||||
|
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
|
||||||
|
err = ""
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
|
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
|
||||||
}
|
}
|
||||||
if err != "" {
|
if err != "" {
|
||||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
|
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
|
||||||
// ok to continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sig.recv = recv
|
}).describef(recv, "validate receiver %s", 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