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:
Robert Griesemer 2022-02-24 13:35:16 -08:00
parent 55e5b03cb3
commit 7c694fbad1
8 changed files with 274 additions and 99 deletions

View file

@ -194,9 +194,11 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
case 1:
recv = recvList[0]
}
sig.recv = recv
// TODO(gri) We should delay rtyp expansion to when we actually need the
// receiver; thus all checks here should be delayed to later.
// Delay validation of receiver type as it may cause premature expansion
// of types the receiver type is dependent on (see issues #51232, #51233).
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."
@ -224,6 +226,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
} 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:
@ -250,10 +254,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
}
if 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...)

View file

@ -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,
}
}

View file

@ -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()
}

View file

@ -193,17 +193,19 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
switch len(recvList) {
case 0:
// error reported by resolver
recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
recv = NewParam(token.NoPos, nil, "", Typ[Invalid]) // ignore recv below
default:
// 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
case 1:
recv = recvList[0]
}
sig.recv = recv
// TODO(gri) We should delay rtyp expansion to when we actually need the
// receiver; thus all checks here should be delayed to later.
// Delay validation of receiver type as it may cause premature expansion
// of types the receiver type is dependent on (see issues #51232, #51233).
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."
@ -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
// by an alias (which cannot have receiver parameters for now).
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
}
// 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."
if T.obj.pkg != check.pkg {
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 {
// 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:
@ -244,15 +252,18 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
}
case *Basic:
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)
// ok to continue
}
}
sig.recv = recv
}).describef(recv, "validate receiver %s", recv)
}
sig.params = NewTuple(params...)

View file

@ -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,
}
}

View file

@ -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()
}

View file

@ -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,
}
}

View file

@ -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()
}