1
0
mirror of https://github.com/golang/go synced 2024-11-17 14:04:48 -07:00

cmd/compile/internal/types2: delay expansion of underlying in typeDecl

This is a clean port of CL 356533 from go/types to types2.

Fixes #49043.

Change-Id: If389b94ece28042b0c8b436959dd21f26147a144
Reviewed-on: https://go-review.googlesource.com/c/go/+/356517
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-10-18 17:42:21 -07:00
parent a73c6cf762
commit 99fad12e47
4 changed files with 48 additions and 19 deletions

View File

@ -597,22 +597,12 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
rhs = check.definedType(tdecl.Type, 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 {
@ -711,7 +701,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 != "_" {

View File

@ -130,6 +130,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()
@ -139,7 +151,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
@ -223,6 +237,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 syntax.Pos) (tparams *TypeParamList, underlying Type, methods []*Func) {
n.orig.resolve(ctxt)
assert(n.orig.underlying != nil)
check := n.check

View File

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

View 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]
)