mirror of
https://github.com/golang/go
synced 2024-11-17 16:04:47 -07:00
go/types: delay expansion of underlying in typeDecl
Even after type-checking the RHS of a type declaration, we may not yet be able to expand, if the RHS is itself an instance (see #49043). We can instead rely on the mechanisms we have in place for delayed expansion. Fixes #49043 Change-Id: Ibffa4c1b1163c824b5c7e151aaac35f3e8c84ec7 Reviewed-on: https://go-review.googlesource.com/c/go/+/356533 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
323e009c75
commit
eba0e866fa
@ -647,22 +647,11 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
|
||||
assert(rhs != nil)
|
||||
named.fromRHS = rhs
|
||||
|
||||
// The underlying type of named may be itself a named type that is
|
||||
// incomplete:
|
||||
//
|
||||
// type (
|
||||
// A B
|
||||
// B *C
|
||||
// C A
|
||||
// )
|
||||
//
|
||||
// The type of C is the (named) type of A which is incomplete,
|
||||
// and which has as its underlying type the named type B.
|
||||
// Determine the (final, unnamed) underlying type by resolving
|
||||
// any forward chain.
|
||||
// TODO(gri) Investigate if we can just use named.fromRHS here
|
||||
// and rely on lazy computation of the underlying type.
|
||||
named.underlying = under(named)
|
||||
// If the underlying was not set while type-checking the right-hand side, it
|
||||
// is invalid and an error should have been reported elsewhere.
|
||||
if named.underlying == nil {
|
||||
named.underlying = Typ[Invalid]
|
||||
}
|
||||
|
||||
// If the RHS is a type parameter, it must be from this type declaration.
|
||||
if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TypeParams().list(), tpar) < 0 {
|
||||
@ -776,7 +765,7 @@ func (check *Checker) collectMethods(obj *TypeName) {
|
||||
// and field names must be distinct."
|
||||
base := asNamed(obj.typ) // shouldn't fail but be conservative
|
||||
if base != nil {
|
||||
u := safeUnderlying(base) // base should be expanded, but use safeUnderlying to be conservative
|
||||
u := base.under()
|
||||
if t, _ := u.(*Struct); t != nil {
|
||||
for _, fld := range t.fields {
|
||||
if fld.name != "_" {
|
||||
|
@ -132,6 +132,18 @@ func (t *Named) String() string { return TypeString(t, nil) }
|
||||
// chain before returning it. If no underlying type is found or a cycle
|
||||
// is detected, the result is Typ[Invalid]. If a cycle is detected and
|
||||
// n0.check != nil, the cycle is reported.
|
||||
//
|
||||
// This is necessary because the underlying type of named may be itself a
|
||||
// named type that is incomplete:
|
||||
//
|
||||
// type (
|
||||
// A B
|
||||
// B *C
|
||||
// C A
|
||||
// )
|
||||
//
|
||||
// The type of C is the (named) type of A which is incomplete,
|
||||
// and which has as its underlying type the named type B.
|
||||
func (n0 *Named) under() Type {
|
||||
u := n0.Underlying()
|
||||
|
||||
@ -141,7 +153,9 @@ func (n0 *Named) under() Type {
|
||||
var n1 *Named
|
||||
switch u1 := u.(type) {
|
||||
case nil:
|
||||
return Typ[Invalid]
|
||||
// After expansion via Underlying(), we should never encounter a nil
|
||||
// underlying.
|
||||
panic("nil underlying")
|
||||
default:
|
||||
// common case
|
||||
return u
|
||||
@ -225,6 +239,7 @@ func (check *Checker) bestContext(ctxt *Context) *Context {
|
||||
// The underlying type will be Typ[Invalid] if there was an error.
|
||||
func expandNamed(ctxt *Context, n *Named, instPos token.Pos) (tparams *TypeParamList, underlying Type, methods []*Func) {
|
||||
n.orig.resolve(ctxt)
|
||||
assert(n.orig.underlying != nil)
|
||||
|
||||
check := n.check
|
||||
|
||||
|
2
src/go/types/testdata/check/typeinst.go2
vendored
2
src/go/types/testdata/check/typeinst.go2
vendored
@ -57,5 +57,5 @@ var _ T3[int] = T3[int](List[int]{1, 2, 3})
|
||||
|
||||
// Self-recursive generic types are not permitted
|
||||
|
||||
type self1[P any] self1 /* ERROR illegal cycle */ [P]
|
||||
type self1 /* ERROR illegal cycle */ [P any] self1[P]
|
||||
type self2[P any] *self2[P] // this is ok
|
||||
|
24
src/go/types/testdata/fixedbugs/issue49043.go2
vendored
Normal file
24
src/go/types/testdata/fixedbugs/issue49043.go2
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// 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
|
||||
|
||||
// The example from the issue.
|
||||
type (
|
||||
N /* ERROR illegal cycle */ [P any] M[P]
|
||||
M[P any] N[P]
|
||||
)
|
||||
|
||||
// A slightly more complicated case.
|
||||
type (
|
||||
A /* ERROR illegal cycle */ [P any] B[P]
|
||||
B[P any] C[P]
|
||||
C[P any] A[P]
|
||||
)
|
||||
|
||||
// Confusing but valid (note that `type T *T` is valid).
|
||||
type (
|
||||
N1[P any] *M1[P]
|
||||
M1[P any] *N1[P]
|
||||
)
|
Loading…
Reference in New Issue
Block a user