From 790384c6c23f7ce44199ea3cd61c856d632b08aa Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 18 Nov 2025 15:47:44 -0800 Subject: [PATCH] spec: adjust rule for type parameter on RHS of alias declaration Per discussion on issue #75885, a type parameter on the RHS of an alias declaration must not be declared in the same declaration (but it may be declared by an enclosing function). This relaxes the spec slightly and allows for (pre-existing) test cases. Add a corresponding check to the type checker (there was no check for type parameters on the RHS of alias declarations at all, before). Fixes #75884. Fixes #75885. Change-Id: I1e5675978e6423d626c068829d4bf5e90035ea82 Reviewed-on: https://go-review.googlesource.com/c/go/+/721820 Auto-Submit: Robert Griesemer Reviewed-by: Robert Griesemer Reviewed-by: Mark Freeman Reviewed-by: Robert Findley LUCI-TryBot-Result: Go LUCI --- doc/go_spec.html | 14 +++++++++----- src/cmd/compile/internal/types2/decl.go | 9 +++++++-- src/go/types/decl.go | 9 +++++++-- .../types/testdata/fixedbugs/issue75885.go | 15 +++++++++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 src/internal/types/testdata/fixedbugs/issue75885.go diff --git a/doc/go_spec.html b/doc/go_spec.html index 77400ad210..b75845372d 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2487,11 +2487,15 @@ type set[P comparable] = map[P]bool

-In an alias declaration the given type cannot be a type parameter. +In an alias declaration the given type cannot be a type parameter declared in the same declaration.

-type A[P any] = P    // illegal: P is a type parameter
+type A[P any] = P   // illegal: P is a type parameter declared in the declaration of A
+
+func f[P any]() {
+	type A = P  // ok: T is a type parameter declared by the enclosing function
+}
 

Type definitions

@@ -2601,8 +2605,8 @@ In a type definition the given type cannot be a type parameter.
 type T[P any] P    // illegal: P is a type parameter
 
-func f[T any]() {
-	type L T   // illegal: T is a type parameter declared by the enclosing function
+func f[P any]() {
+	type L P   // illegal: P is a type parameter declared by the enclosing function
 }
 
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 60371651ab..5cb52fdbe4 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -497,9 +497,14 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *TypeN rhs = check.declaredType(tdecl.Type, obj) assert(rhs != nil) - alias.fromRHS = rhs - unalias(alias) // populate alias.actual + + // spec: In an alias declaration the given type cannot be a type parameter declared in the same declaration." + // (see also go.dev/issue/75884, go.dev/issue/#75885) + if tpar, ok := rhs.(*TypeParam); ok && alias.tparams != nil && slices.Index(alias.tparams.list(), tpar) >= 0 { + check.error(tdecl.Type, MisplacedTypeParam, "cannot use type parameter declared in alias declaration as RHS") + alias.fromRHS = Typ[Invalid] + } } else { if !versionErr && tparam0 != nil { check.error(tdecl, UnsupportedFeature, "generic type alias requires GODEBUG=gotypesalias=1 or unset") diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 4b374fb66d..fffcb590e6 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -572,9 +572,14 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *TypeName rhs = check.declaredType(tdecl.Type, obj) assert(rhs != nil) - alias.fromRHS = rhs - unalias(alias) // populate alias.actual + + // spec: In an alias declaration the given type cannot be a type parameter declared in the same declaration." + // (see also go.dev/issue/75884, go.dev/issue/#75885) + if tpar, ok := rhs.(*TypeParam); ok && alias.tparams != nil && slices.Index(alias.tparams.list(), tpar) >= 0 { + check.error(tdecl.Type, MisplacedTypeParam, "cannot use type parameter declared in alias declaration as RHS") + alias.fromRHS = Typ[Invalid] + } } else { // With Go1.23, the default behavior is to use Alias nodes, // reflected by check.enableAlias. Signal non-default behavior. diff --git a/src/internal/types/testdata/fixedbugs/issue75885.go b/src/internal/types/testdata/fixedbugs/issue75885.go new file mode 100644 index 0000000000..f0cf4a65ed --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue75885.go @@ -0,0 +1,15 @@ +// -gotypesalias=1 + +// Copyright 2025 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 + +type A[P any] = P // ERROR "cannot use type parameter declared in alias declaration as RHS" + +func _[P any]() { + type A[P any] = P // ERROR "cannot use type parameter declared in alias declaration as RHS" + type B = P + type C[Q any] = P +} -- 2.52.0