Skip to content

Commit 47547d8

Browse files
committed
[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 <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 60cb2ca commit 47547d8

File tree

4 files changed

+87
-54
lines changed

4 files changed

+87
-54
lines changed

src/cmd/compile/internal/types2/decl.go

+34-30
Original file line numberDiff line numberDiff line change
@@ -626,8 +626,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
626626
alias = false
627627
}
628628

629+
// alias declaration
629630
if alias {
630-
// type alias declaration
631631
if !check.allowVersion(check.pkg, 1, 9) {
632632
if check.conf.CompilerErrorMessages {
633633
check.error(tdecl, "type aliases only supported as of -lang=go1.9")
@@ -638,40 +638,44 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
638638

639639
obj.typ = Typ[Invalid]
640640
obj.typ = check.anyType(tdecl.Type)
641+
return
642+
}
641643

642-
} else {
643-
// defined type declaration
644-
645-
named := check.newNamed(obj, nil, nil, nil, nil)
646-
def.setUnderlying(named)
644+
// type definition or generic type declaration
645+
named := check.newNamed(obj, nil, nil, nil, nil)
646+
def.setUnderlying(named)
647647

648-
if tdecl.TParamList != nil {
649-
check.openScope(tdecl, "type parameters")
650-
defer check.closeScope()
651-
named.tparams = check.collectTypeParams(tdecl.TParamList)
652-
}
648+
if tdecl.TParamList != nil {
649+
check.openScope(tdecl, "type parameters")
650+
defer check.closeScope()
651+
named.tparams = check.collectTypeParams(tdecl.TParamList)
652+
}
653653

654-
// determine underlying type of named
655-
named.fromRHS = check.definedType(tdecl.Type, named)
654+
// determine underlying type of named
655+
named.fromRHS = check.definedType(tdecl.Type, named)
656656

657-
// The underlying type of named may be itself a named type that is
658-
// incomplete:
659-
//
660-
// type (
661-
// A B
662-
// B *C
663-
// C A
664-
// )
665-
//
666-
// The type of C is the (named) type of A which is incomplete,
667-
// and which has as its underlying type the named type B.
668-
// Determine the (final, unnamed) underlying type by resolving
669-
// any forward chain.
670-
// TODO(gri) Investigate if we can just use named.fromRHS here
671-
// and rely on lazy computation of the underlying type.
672-
named.underlying = under(named)
657+
// The underlying type of named may be itself a named type that is
658+
// incomplete:
659+
//
660+
// type (
661+
// A B
662+
// B *C
663+
// C A
664+
// )
665+
//
666+
// The type of C is the (named) type of A which is incomplete,
667+
// and which has as its underlying type the named type B.
668+
// Determine the (final, unnamed) underlying type by resolving
669+
// any forward chain.
670+
// TODO(gri) Investigate if we can just use named.fromRHS here
671+
// and rely on lazy computation of the underlying type.
672+
named.underlying = under(named)
673+
674+
// If the RHS is a type parameter, it must be from this type declaration.
675+
if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.tparams, tpar) < 0 {
676+
check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar)
677+
named.underlying = Typ[Invalid]
673678
}
674-
675679
}
676680

677681
func (check *Checker) collectTypeParams(list []*syntax.Field) []*TypeName {

src/cmd/compile/internal/types2/testdata/examples/types.go2

+30-20
Original file line numberDiff line numberDiff line change
@@ -155,30 +155,40 @@ type _ struct {
155155
List /* ERROR List redeclared */ [int]
156156
}
157157

158+
// Issue #45639: We don't allow this anymore. Keep this code
159+
// in case we decide to revisit this decision.
160+
//
158161
// It's possible to declare local types whose underlying types
159162
// are type parameters. As with ordinary type definitions, the
160163
// types underlying properties are "inherited" but the methods
161164
// are not.
162-
func _[T interface{ m(); ~int }]() {
163-
type L T
164-
var x L
165-
166-
// m is not defined on L (it is not "inherited" from
167-
// its underlying type).
168-
x.m /* ERROR x.m undefined */ ()
169-
170-
// But the properties of T, such that as that it supports
171-
// the operations of the types given by its type bound,
172-
// are also the properties of L.
173-
x++
174-
_ = x - x
175-
176-
// On the other hand, if we define a local alias for T,
177-
// that alias stands for T as expected.
178-
type A = T
179-
var y A
180-
y.m()
181-
_ = y < 0
165+
// func _[T interface{ m(); ~int }]() {
166+
// type L T
167+
// var x L
168+
//
169+
// // m is not defined on L (it is not "inherited" from
170+
// // its underlying type).
171+
// x.m /* ERROR x.m undefined */ ()
172+
//
173+
// // But the properties of T, such that as that it supports
174+
// // the operations of the types given by its type bound,
175+
// // are also the properties of L.
176+
// x++
177+
// _ = x - x
178+
//
179+
// // On the other hand, if we define a local alias for T,
180+
// // that alias stands for T as expected.
181+
// type A = T
182+
// var y A
183+
// y.m()
184+
// _ = y < 0
185+
// }
186+
187+
// It is not permitted to declare a local type whose underlying
188+
// type is a type parameters not declared by that type declaration.
189+
func _[T any]() {
190+
type _ T // ERROR cannot use function type parameter T as RHS in type declaration
191+
type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
182192
}
183193

184194
// As a special case, an explicit type argument may be omitted
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package P
6+
7+
// It is not permitted to declare a local type whose underlying
8+
// type is a type parameters not declared by that type declaration.
9+
func _[T any]() {
10+
type _ T // ERROR cannot use function type parameter T as RHS in type declaration
11+
type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
12+
}

src/cmd/compile/internal/types2/unify.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,17 @@ func (u *unifier) join(i, j int) bool {
150150
// If typ is a type parameter of d, index returns the type parameter index.
151151
// Otherwise, the result is < 0.
152152
func (d *tparamsList) index(typ Type) int {
153-
if t, ok := typ.(*TypeParam); ok {
154-
if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t {
155-
return i
156-
}
153+
if tpar, ok := typ.(*TypeParam); ok {
154+
return tparamIndex(d.tparams, tpar)
155+
}
156+
return -1
157+
}
158+
159+
// If tpar is a type parameter in list, tparamIndex returns the type parameter index.
160+
// Otherwise, the result is < 0. tpar must not be nil.
161+
func tparamIndex(list []*TypeName, tpar *TypeParam) int {
162+
if i := tpar.index; i < len(list) && list[i].typ == tpar {
163+
return i
157164
}
158165
return -1
159166
}

0 commit comments

Comments
 (0)