]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile/internal/types2: disallow "free" type parameter as RHS...
authorRobert Griesemer <gri@golang.org>
Fri, 2 Jul 2021 05:10:01 +0000 (22:10 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 7 Jul 2021 23:42:06 +0000 (23:42 +0000)
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>
src/cmd/compile/internal/types2/decl.go
src/cmd/compile/internal/types2/testdata/examples/types.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/unify.go

index d36da06f421a357ca84b546bd1ef238743a3812b..4f91bc70c78564f045c819b8e5d85631214ee95e 100644 (file)
@@ -626,8 +626,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
                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 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
 
                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 {
index 66e7a7b90e14ee50c5bee98f904154c6b03e7472..4ecc34dfa45beee8bcb44fb65c6200d8c0420593 100644 (file)
@@ -155,30 +155,40 @@ type _ struct {
        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
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 (file)
index 0000000..441fb4c
--- /dev/null
@@ -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
+}
index 4e1f8322030cbf21704b86d274d101b15551888f..755622738a6fccde736032677c06b9122974e012 100644 (file)
@@ -150,10 +150,17 @@ func (u *unifier) join(i, j int) bool {
 // 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
 }