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>
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")
obj.typ = Typ[Invalid]
obj.typ = check.anyType(tdecl.Type)
+ return
+ }
- } else {
- // defined type declaration
-
- named := check.newNamed(obj, nil, nil, nil, nil)
- def.setUnderlying(named)
+ // 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)
- }
+ 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)
+ // 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)
+ // 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 {
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
-
- // 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
+// 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
+// }
+
+// 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
--- /dev/null
+// 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
+}
// 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
}