Skip to content

Commit

Permalink
cmd/compile/internal/types2: disallow lone type parameter on RHS of t…
Browse files Browse the repository at this point in the history
…ype declaration

We may revisit this decision in a future release. By disallowing this
for Go 1.18 we are ensuring that we don't lock in the generics design
in a place that may need to change later. (Type declarations are the
primary construct where it crucially matters what the underlying type
of a type parameter is.)

Comment out all tests that rely on this feature; add comments referring
to issue so we can find all places easily should we change our minds.

Fixes #45639.

Change-Id: I730510e4da66d3716d455a9071c7778a1e4a1152
Reviewed-on: https://go-review.googlesource.com/c/go/+/359177
Trust: Robert Griesemer <gri@golang.org>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Dan Scales <danscales@google.com>
  • Loading branch information
griesemer committed Oct 28, 2021
1 parent 79ff663 commit a91d0b6
Show file tree
Hide file tree
Showing 20 changed files with 297 additions and 309 deletions.
14 changes: 0 additions & 14 deletions src/cmd/compile/internal/types2/api_test.go
Expand Up @@ -622,13 +622,6 @@ func TestDefsInfo(t *testing.T) {
{`package p3; type x int`, `x`, `type p3.x int`},
{`package p4; func f()`, `f`, `func p4.f()`},
{`package p5; func f() int { x, _ := 1, 2; return x }`, `_`, `var _ int`},

// generic types must be sanitized
// (need to use sufficiently nested types to provoke unexpanded types)
{genericPkg + `g0; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
{genericPkg + `g1; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
{genericPkg + `g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
{genericPkg + `g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var generic_g3.g func(x struct{f generic_g3.t[string]})`},
}

for _, test := range tests {
Expand Down Expand Up @@ -667,13 +660,6 @@ func TestUsesInfo(t *testing.T) {
{`package p2; func _() { _ = x }; var x int`, `x`, `var p2.x int`},
{`package p3; func _() { type _ x }; type x int`, `x`, `type p3.x int`},
{`package p4; func _() { _ = f }; func f()`, `f`, `func p4.f()`},

// generic types must be sanitized
// (need to use sufficiently nested types to provoke unexpanded types)
{genericPkg + `g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
{genericPkg + `g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
{genericPkg + `g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
{genericPkg + `g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func generic_g3.f(x struct{f generic_g3.t[string]})`},
}

for _, test := range tests {
Expand Down
9 changes: 6 additions & 3 deletions src/cmd/compile/internal/types2/decl.go
Expand Up @@ -604,9 +604,12 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
named.underlying = Typ[Invalid]
}

// If the RHS is a type parameter, it must be from this type declaration.
if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TypeParams().list(), tpar) < 0 {
check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar)
// Disallow a lone type parameter as the RHS of a type declaration (issue #45639).
// We can look directly at named.underlying because even if it is still a *Named
// type (underlying not fully resolved yet) it cannot become a type parameter due
// to this very restriction.
if tpar, _ := named.underlying.(*TypeParam); tpar != nil {
check.error(tdecl.Type, "cannot use a type parameter as RHS in type declaration")
named.underlying = Typ[Invalid]
}
}
Expand Down
61 changes: 30 additions & 31 deletions src/cmd/compile/internal/types2/testdata/check/linalg.go2
Expand Up @@ -4,8 +4,6 @@

package linalg

import "math"

// Numeric is type bound that matches any numeric type.
// It would likely be in a constraints package in the standard library.
type Numeric interface {
Expand Down Expand Up @@ -52,32 +50,33 @@ type Complex interface {
~complex64 | ~complex128
}

// OrderedAbs is a helper type that defines an Abs method for
// ordered numeric types.
type OrderedAbs[T OrderedNumeric] T

func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
if a < 0 {
return -a
}
return a
}

// ComplexAbs is a helper type that defines an Abs method for
// complex types.
type ComplexAbs[T Complex] T

func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
r := float64(real(a))
i := float64(imag(a))
d := math.Sqrt(r * r + i * i)
return ComplexAbs[T](complex(d, 0))
}

func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
}

func ComplexAbsDifference[T Complex](a, b T) T {
return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
}
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// // OrderedAbs is a helper type that defines an Abs method for
// // ordered numeric types.
// type OrderedAbs[T OrderedNumeric] T
//
// func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
// if a < 0 {
// return -a
// }
// return a
// }
//
// // ComplexAbs is a helper type that defines an Abs method for
// // complex types.
// type ComplexAbs[T Complex] T
//
// func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
// r := float64(real(a))
// i := float64(imag(a))
// d := math.Sqrt(r * r + i * i)
// return ComplexAbs[T](complex(d, 0))
// }
//
// func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
// return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
// }
//
// func ComplexAbsDifference[T Complex](a, b T) T {
// return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
// }
5 changes: 3 additions & 2 deletions src/cmd/compile/internal/types2/testdata/check/typeinst.go2
Expand Up @@ -8,7 +8,8 @@ type myInt int

// Parameterized type declarations

type T1[P any] P
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
type T1[P any] P // ERROR cannot use a type parameter as RHS in type declaration

type T2[P any] struct {
f P
Expand All @@ -19,7 +20,7 @@ type List[P any] []P

// Alias type declarations cannot have type parameters.
// Issue #46477 proposses to change that.
type A1[P any] = /* ERROR cannot be alias */ P
type A1[P any] = /* ERROR cannot be alias */ struct{}

// Pending clarification of #46477 we disallow aliases
// of generic types.
Expand Down
30 changes: 16 additions & 14 deletions src/cmd/compile/internal/types2/testdata/check/typeinst2.go2
Expand Up @@ -87,25 +87,27 @@ type NumericAbs[T any] interface {

func AbsDifference[T NumericAbs[T]](x T) { panic(0) }

type OrderedAbs[T any] T

func (a OrderedAbs[T]) Abs() OrderedAbs[T]

func OrderedAbsDifference[T any](x T) {
AbsDifference(OrderedAbs[T](x))
}
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// type OrderedAbs[T any] T
//
// func (a OrderedAbs[T]) Abs() OrderedAbs[T]
//
// func OrderedAbsDifference[T any](x T) {
// AbsDifference(OrderedAbs[T](x))
// }

// same code, reduced to essence

func g[P interface{ m() P }](x P) { panic(0) }

type T4[P any] P

func (_ T4[P]) m() T4[P]

func _[Q any](x Q) {
g(T4[Q](x))
}
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// type T4[P any] P
//
// func (_ T4[P]) m() T4[P]
//
// func _[Q any](x Q) {
// g(T4[Q](x))
// }

// Another test case that caused problems in the past

Expand Down
19 changes: 10 additions & 9 deletions src/cmd/compile/internal/types2/testdata/check/typeparams.go2
Expand Up @@ -353,15 +353,16 @@ func _() {

// the previous example was extracted from

func f12[T interface{m() T}]() {}

type A[T any] T

func (a A[T]) m() A[T]

func _[T any]() {
f12[A[T]]()
}
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// func f12[T interface{m() T}]() {}
//
// type A[T any] T
//
// func (a A[T]) m() A[T]
//
// func _[T any]() {
// f12[A[T]]()
// }

// method expressions

Expand Down
31 changes: 15 additions & 16 deletions src/cmd/compile/internal/types2/testdata/examples/methods.go2
Expand Up @@ -6,8 +6,6 @@

package p

import "unsafe"

// Parameterized types may have methods.
type T1[A any] struct{ a A }

Expand Down Expand Up @@ -97,17 +95,18 @@ type T0 struct{}
func (T0) _() {}
func (T1[A]) _() {}

// A generic receiver type may constrain its type parameter such
// that it must be a pointer type. Such receiver types are not
// permitted.
type T3a[P interface{ ~int | ~string | ~float64 }] P

func (T3a[_]) m() {} // this is ok

type T3b[P interface{ ~unsafe.Pointer }] P

func (T3b /* ERROR invalid receiver */ [_]) m() {}

type T3c[P interface{ *int | *string }] P

func (T3c /* ERROR invalid receiver */ [_]) m() {}
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// // A generic receiver type may constrain its type parameter such
// // that it must be a pointer type. Such receiver types are not
// // permitted.
// type T3a[P interface{ ~int | ~string | ~float64 }] P
//
// func (T3a[_]) m() {} // this is ok
//
// type T3b[P interface{ ~unsafe.Pointer }] P
//
// func (T3b /* ERROR invalid receiver */ [_]) m() {}
//
// type T3c[P interface{ *int | *string }] P
//
// func (T3c /* ERROR invalid receiver */ [_]) m() {}
13 changes: 7 additions & 6 deletions src/cmd/compile/internal/types2/testdata/examples/types.go2
Expand Up @@ -185,12 +185,13 @@ type _ struct {
// _ = y < 0
// }

// It is not permitted to declare a local type whose underlying
// type is a type parameter 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
}
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// // It is not permitted to declare a local type whose underlying
// // type is a type parameter 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
// from a type parameter bound if the type bound expects exactly
Expand Down
Expand Up @@ -74,9 +74,10 @@ func F20[t Z20]() { F20(t /* ERROR invalid composite literal type */ {}) }
type Z21 /* ERROR illegal cycle */ interface{ Z21 }
func F21[T Z21]() { ( /* ERROR not used */ F21[Z21]) }

// crash 24
type T24[P any] P
func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() }
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// // crash 24
// type T24[P any] P
// func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() }

// crash 25
type T25[A any] int
Expand Down
Expand Up @@ -4,14 +4,15 @@

package p

type T[P any] P
type A = T // ERROR cannot use generic type
var x A[int]
var _ A

type B = T[int]
var y B = x
var _ B /* ERROR not a generic type */ [int]
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// type T[P any] P
// type A = T // ERROR cannot use generic type
// var x A[int]
// var _ A
//
// type B = T[int]
// var y B = x
// var _ B /* ERROR not a generic type */ [int]

// test case from issue

Expand Down
Expand Up @@ -8,7 +8,7 @@

package p

type E0[P any] P
type E0[P any] []P
type E1[P any] *P
type E2[P any] struct{ _ P }
type E3[P any] struct{ _ *P }
Expand Down
Expand Up @@ -4,9 +4,10 @@

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
}
// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
// // 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
// }

0 comments on commit a91d0b6

Please sign in to comment.