[dev.typeparams] cmd/compile/internal/types2: disallow "free" type parameter as RHS of a type declaration

For #45639.

Change-Id: I20e331b04f464db81e916af75f70ec8ae73eb989
Reviewed-on: https://go-review.googlesource.com/c/go/+/332411
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 d36da06..4f91bc7 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -626,8 +626,8 @@
 		alias = false
 	}
 
+	// alias declaration
 	if alias {
-		// type alias declaration
 		if !check.allowVersion(check.pkg, 1, 9) {
 			if check.conf.CompilerErrorMessages {
 				check.error(tdecl, "type aliases only supported as of -lang=go1.9")
@@ -638,40 +638,44 @@
 
 		obj.typ = Typ[Invalid]
 		obj.typ = check.anyType(tdecl.Type)
-
-	} else {
-		// defined type declaration
-
-		named := check.newNamed(obj, nil, nil, nil, nil)
-		def.setUnderlying(named)
-
-		if tdecl.TParamList != nil {
-			check.openScope(tdecl, "type parameters")
-			defer check.closeScope()
-			named.tparams = check.collectTypeParams(tdecl.TParamList)
-		}
-
-		// determine underlying type of named
-		named.fromRHS = check.definedType(tdecl.Type, named)
-
-		// 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)
+		return
 	}
 
+	// type definition or generic type declaration
+	named := check.newNamed(obj, nil, nil, nil, nil)
+	def.setUnderlying(named)
+
+	if tdecl.TParamList != nil {
+		check.openScope(tdecl, "type parameters")
+		defer check.closeScope()
+		named.tparams = check.collectTypeParams(tdecl.TParamList)
+	}
+
+	// determine underlying type of named
+	named.fromRHS = check.definedType(tdecl.Type, named)
+
+	// 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 RHS is a type parameter, it must be from this type declaration.
+	if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams, tpar) < 0 {
+		check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar)
+		named.underlying = Typ[Invalid]
+	}
 }
 
 func (check *Checker) collectTypeParams(list []*syntax.Field) []*TypeName {
diff --git a/src/cmd/compile/internal/types2/testdata/examples/types.go2 b/src/cmd/compile/internal/types2/testdata/examples/types.go2
index 66e7a7b..4ecc34d 100644
--- a/src/cmd/compile/internal/types2/testdata/examples/types.go2
+++ b/src/cmd/compile/internal/types2/testdata/examples/types.go2
@@ -155,30 +155,40 @@
 	List /* ERROR List redeclared */ [int]
 }
 
+// Issue #45639: We don't allow this anymore. Keep this code
+//               in case we decide to revisit this decision.
+//
 // It's possible to declare local types whose underlying types
 // are type parameters. As with ordinary type definitions, the
 // types underlying properties are "inherited" but the methods
 // are not.
-func _[T interface{ m(); ~int }]() {
-	type L T
-	var x L
+// func _[T interface{ m(); ~int }]() {
+// 	type L T
+// 	var x L
+// 
+// 	// m is not defined on L (it is not "inherited" from
+// 	// its underlying type).
+// 	x.m /* ERROR x.m undefined */ ()
+// 
+// 	// But the properties of T, such that as that it supports
+// 	// the operations of the types given by its type bound,
+// 	// are also the properties of L.
+// 	x++
+// 	_ = x - x
+// 
+// 	// On the other hand, if we define a local alias for T,
+// 	// that alias stands for T as expected.
+// 	type A = T
+// 	var y A
+// 	y.m()
+// 	_ = y < 0
+// }
 
-	// m is not defined on L (it is not "inherited" from
-	// its underlying type).
-	x.m /* ERROR x.m undefined */ ()
-
-	// But the properties of T, such that as that it supports
-	// the operations of the types given by its type bound,
-	// are also the properties of L.
-	x++
-	_ = x - x
-
-	// On the other hand, if we define a local alias for T,
-	// that alias stands for T as expected.
-	type A = T
-	var y A
-	y.m()
-	_ = y < 0
+// It is not permitted to declare a local type whose underlying
+// type is a type parameters not declared by that type declaration.
+func _[T any]() {
+	type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
+	type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
 }
 
 // As a special case, an explicit type argument may be omitted
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2
new file mode 100644
index 0000000..441fb4c
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2
@@ -0,0 +1,12 @@
+// 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
+
+// It is not permitted to declare a local type whose underlying
+// type is a type parameters not declared by that type declaration.
+func _[T any]() {
+	type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
+	type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
+}
diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go
index 4e1f832..7556227 100644
--- a/src/cmd/compile/internal/types2/unify.go
+++ b/src/cmd/compile/internal/types2/unify.go
@@ -150,10 +150,17 @@
 // If typ is a type parameter of d, index returns the type parameter index.
 // Otherwise, the result is < 0.
 func (d *tparamsList) index(typ Type) int {
-	if t, ok := typ.(*TypeParam); ok {
-		if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t {
-			return i
-		}
+	if tpar, ok := typ.(*TypeParam); ok {
+		return tparamIndex(d.tparams, tpar)
+	}
+	return -1
+}
+
+// If tpar is a type parameter in list, tparamIndex returns the type parameter index.
+// Otherwise, the result is < 0. tpar must not be nil.
+func tparamIndex(list []*TypeName, tpar *TypeParam) int {
+	if i := tpar.index; i < len(list) && list[i].typ == tpar {
+		return i
 	}
 	return -1
 }