From: Robert Griesemer Date: Tue, 19 Oct 2021 00:42:21 +0000 (-0700) Subject: cmd/compile/internal/types2: delay expansion of underlying in typeDecl X-Git-Tag: go1.18beta1~844 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=99fad12e4788fdf67e49dadd16571238f935b408;p=gostls13.git 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 Reviewed-by: Robert Findley --- diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index a605057579..63be4b3223 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -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 != "_" { diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index eb8b5d1ba8..6ebad8fbb5 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -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 diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst.go2 index 3fab2cb9ad..14f1b07ee2 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeinst.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinst.go2 @@ -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 diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2 new file mode 100644 index 0000000000..c37b0f1267 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2 @@ -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] +)