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>
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index a605057..63be4b3 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -597,22 +597,12 @@
 	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 @@
 	// 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 eb8b5d1..6ebad8f 100644
--- a/src/cmd/compile/internal/types2/named.go
+++ b/src/cmd/compile/internal/types2/named.go
@@ -130,6 +130,18 @@
 // 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 @@
 	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 @@
 // 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 3fab2cb..14f1b07 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 @@
 
 // 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 0000000..c37b0f1
--- /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]
+)