Skip to content

Commit 7c694fb

Browse files
committed
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 <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 55e5b03 commit 7c694fb

File tree

8 files changed

+274
-99
lines changed

8 files changed

+274
-99
lines changed

src/cmd/compile/internal/types2/signature.go

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -194,66 +194,69 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
194194
case 1:
195195
recv = recvList[0]
196196
}
197+
sig.recv = recv
197198

198-
// TODO(gri) We should delay rtyp expansion to when we actually need the
199-
// receiver; thus all checks here should be delayed to later.
200-
rtyp, _ := deref(recv.typ)
199+
// Delay validation of receiver type as it may cause premature expansion
200+
// of types the receiver type is dependent on (see issues #51232, #51233).
201+
check.later(func() {
202+
rtyp, _ := deref(recv.typ)
201203

202-
// spec: "The receiver type must be of the form T or *T where T is a type name."
203-
// (ignore invalid types - error was reported before)
204-
if rtyp != Typ[Invalid] {
205-
var err string
206-
switch T := rtyp.(type) {
207-
case *Named:
208-
T.resolve(check.bestContext(nil))
209-
// The receiver type may be an instantiated type referred to
210-
// by an alias (which cannot have receiver parameters for now).
211-
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
212-
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
213-
break
214-
}
215-
// spec: "The type denoted by T is called the receiver base type; it must not
216-
// be a pointer or interface type and it must be declared in the same package
217-
// as the method."
218-
if T.obj.pkg != check.pkg {
219-
err = "type not defined in this package"
204+
// spec: "The receiver type must be of the form T or *T where T is a type name."
205+
// (ignore invalid types - error was reported before)
206+
if rtyp != Typ[Invalid] {
207+
var err string
208+
switch T := rtyp.(type) {
209+
case *Named:
210+
T.resolve(check.bestContext(nil))
211+
// The receiver type may be an instantiated type referred to
212+
// by an alias (which cannot have receiver parameters for now).
213+
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
214+
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
215+
break
216+
}
217+
// spec: "The type denoted by T is called the receiver base type; it must not
218+
// be a pointer or interface type and it must be declared in the same package
219+
// as the method."
220+
if T.obj.pkg != check.pkg {
221+
err = "type not defined in this package"
222+
if check.conf.CompilerErrorMessages {
223+
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
224+
err = ""
225+
}
226+
} else {
227+
// The underlying type of a receiver base type can be a type parameter;
228+
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
229+
// TODO(gri) Such declarations are currently disallowed.
230+
// Revisit the need for underIs.
231+
underIs(T, func(u Type) bool {
232+
switch u := u.(type) {
233+
case *Basic:
234+
// unsafe.Pointer is treated like a regular pointer
235+
if u.kind == UnsafePointer {
236+
err = "unsafe.Pointer"
237+
return false
238+
}
239+
case *Pointer, *Interface:
240+
err = "pointer or interface type"
241+
return false
242+
}
243+
return true
244+
})
245+
}
246+
case *Basic:
247+
err = "basic or unnamed type"
220248
if check.conf.CompilerErrorMessages {
221249
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
222250
err = ""
223251
}
224-
} else {
225-
// The underlying type of a receiver base type can be a type parameter;
226-
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
227-
underIs(T, func(u Type) bool {
228-
switch u := u.(type) {
229-
case *Basic:
230-
// unsafe.Pointer is treated like a regular pointer
231-
if u.kind == UnsafePointer {
232-
err = "unsafe.Pointer"
233-
return false
234-
}
235-
case *Pointer, *Interface:
236-
err = "pointer or interface type"
237-
return false
238-
}
239-
return true
240-
})
252+
default:
253+
check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
241254
}
242-
case *Basic:
243-
err = "basic or unnamed type"
244-
if check.conf.CompilerErrorMessages {
245-
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
246-
err = ""
255+
if err != "" {
256+
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
247257
}
248-
default:
249-
check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
250258
}
251-
if err != "" {
252-
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
253-
// ok to continue
254-
}
255-
}
256-
sig.recv = recv
259+
}).describef(recv, "validate receiver %s", recv)
257260
}
258261

259262
sig.params = NewTuple(params...)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
type RC[RG any] interface {
8+
~[]RG
9+
}
10+
11+
type Fn[RCT RC[RG], RG any] func(RCT)
12+
13+
type F[RCT RC[RG], RG any] interface {
14+
Fn() Fn[RCT]
15+
}
16+
17+
type concreteF[RCT RC[RG], RG any] struct {
18+
makeFn func() Fn[RCT]
19+
}
20+
21+
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
22+
return c.makeFn()
23+
}
24+
25+
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
26+
return &concreteF[RCT]{
27+
makeFn: nil,
28+
}
29+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
type RC[RG any] interface {
8+
~[]RG
9+
}
10+
11+
type Fn[RCT RC[RG], RG any] func(RCT)
12+
13+
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
14+
15+
type F[RCT RC[RG], RG any] interface {
16+
Fn() Fn[RCT]
17+
}
18+
19+
type concreteF[RCT RC[RG], RG any] struct {
20+
makeFn FFn[RCT]
21+
}
22+
23+
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
24+
return c.makeFn()
25+
}

src/go/types/signature.go

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -193,66 +193,77 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
193193
switch len(recvList) {
194194
case 0:
195195
// error reported by resolver
196-
recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
196+
recv = NewParam(token.NoPos, nil, "", Typ[Invalid]) // ignore recv below
197197
default:
198198
// more than one receiver
199-
check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver")
199+
check.error(recvList[len(recvList)-1], _InvalidRecv, "method must have exactly one receiver")
200200
fallthrough // continue with first receiver
201201
case 1:
202202
recv = recvList[0]
203203
}
204+
sig.recv = recv
204205

205-
// TODO(gri) We should delay rtyp expansion to when we actually need the
206-
// receiver; thus all checks here should be delayed to later.
207-
rtyp, _ := deref(recv.typ)
206+
// Delay validation of receiver type as it may cause premature expansion
207+
// of types the receiver type is dependent on (see issues #51232, #51233).
208+
check.later(func() {
209+
rtyp, _ := deref(recv.typ)
208210

209-
// spec: "The receiver type must be of the form T or *T where T is a type name."
210-
// (ignore invalid types - error was reported before)
211-
if rtyp != Typ[Invalid] {
212-
var err string
213-
switch T := rtyp.(type) {
214-
case *Named:
215-
T.resolve(check.bestContext(nil))
216-
// The receiver type may be an instantiated type referred to
217-
// by an alias (which cannot have receiver parameters for now).
218-
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
219-
check.errorf(atPos(recv.pos), _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
220-
break
221-
}
222-
// spec: "The type denoted by T is called the receiver base type; it must not
223-
// be a pointer or interface type and it must be declared in the same package
224-
// as the method."
225-
if T.obj.pkg != check.pkg {
226-
err = "type not defined in this package"
227-
} else {
228-
// The underlying type of a receiver base type can be a type parameter;
229-
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
230-
underIs(T, func(u Type) bool {
231-
switch u := u.(type) {
232-
case *Basic:
233-
// unsafe.Pointer is treated like a regular pointer
234-
if u.kind == UnsafePointer {
235-
err = "unsafe.Pointer"
211+
// spec: "The receiver type must be of the form T or *T where T is a type name."
212+
// (ignore invalid types - error was reported before)
213+
if rtyp != Typ[Invalid] {
214+
var err string
215+
switch T := rtyp.(type) {
216+
case *Named:
217+
T.resolve(check.bestContext(nil))
218+
// The receiver type may be an instantiated type referred to
219+
// by an alias (which cannot have receiver parameters for now).
220+
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
221+
check.errorf(recv, _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
222+
break
223+
}
224+
// spec: "The type denoted by T is called the receiver base type; it must not
225+
// be a pointer or interface type and it must be declared in the same package
226+
// as the method."
227+
if T.obj.pkg != check.pkg {
228+
err = "type not defined in this package"
229+
if compilerErrorMessages {
230+
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
231+
err = ""
232+
}
233+
} else {
234+
// The underlying type of a receiver base type can be a type parameter;
235+
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
236+
// TODO(gri) Such declarations are currently disallowed.
237+
// Revisit the need for underIs.
238+
underIs(T, func(u Type) bool {
239+
switch u := u.(type) {
240+
case *Basic:
241+
// unsafe.Pointer is treated like a regular pointer
242+
if u.kind == UnsafePointer {
243+
err = "unsafe.Pointer"
244+
return false
245+
}
246+
case *Pointer, *Interface:
247+
err = "pointer or interface type"
236248
return false
237249
}
238-
case *Pointer, *Interface:
239-
err = "pointer or interface type"
240-
return false
241-
}
242-
return true
243-
})
250+
return true
251+
})
252+
}
253+
case *Basic:
254+
err = "basic or unnamed type"
255+
if compilerErrorMessages {
256+
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
257+
err = ""
258+
}
259+
default:
260+
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
261+
}
262+
if err != "" {
263+
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
244264
}
245-
case *Basic:
246-
err = "basic or unnamed type"
247-
default:
248-
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
249-
}
250-
if err != "" {
251-
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
252-
// ok to continue
253265
}
254-
}
255-
sig.recv = recv
266+
}).describef(recv, "validate receiver %s", recv)
256267
}
257268

258269
sig.params = NewTuple(params...)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
type RC[RG any] interface {
8+
~[]RG
9+
}
10+
11+
type Fn[RCT RC[RG], RG any] func(RCT)
12+
13+
type F[RCT RC[RG], RG any] interface {
14+
Fn() Fn[RCT]
15+
}
16+
17+
type concreteF[RCT RC[RG], RG any] struct {
18+
makeFn func() Fn[RCT]
19+
}
20+
21+
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
22+
return c.makeFn()
23+
}
24+
25+
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
26+
return &concreteF[RCT]{
27+
makeFn: nil,
28+
}
29+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
type RC[RG any] interface {
8+
~[]RG
9+
}
10+
11+
type Fn[RCT RC[RG], RG any] func(RCT)
12+
13+
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
14+
15+
type F[RCT RC[RG], RG any] interface {
16+
Fn() Fn[RCT]
17+
}
18+
19+
type concreteF[RCT RC[RG], RG any] struct {
20+
makeFn FFn[RCT]
21+
}
22+
23+
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
24+
return c.makeFn()
25+
}

test/typeparam/issue51232.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// compile -G=3
2+
3+
// Copyright 2022 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package p
8+
9+
type RC[RG any] interface {
10+
~[]RG
11+
}
12+
13+
type Fn[RCT RC[RG], RG any] func(RCT)
14+
15+
type F[RCT RC[RG], RG any] interface {
16+
Fn() Fn[RCT]
17+
}
18+
19+
type concreteF[RCT RC[RG], RG any] struct {
20+
makeFn func() Fn[RCT]
21+
}
22+
23+
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
24+
return c.makeFn()
25+
}
26+
27+
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
28+
return &concreteF[RCT]{
29+
makeFn: nil,
30+
}
31+
}

0 commit comments

Comments
 (0)