From 1964d562957d94ebc105e09eabee12a5eec9c0fd Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 Aug 2020 21:36:02 -0700 Subject: [PATCH] [dev.go2go] go/types: adjust all tests to use latest syntax - use square brackets for type parameters - otherwise, use same syntax as for ordinary parameters: all type parameters must have a constraint, can be "any" - remove (rename) all *B.go2 tests in favor of adjusted *.go2 tests - remove tests related to pointer notation for type parameters (we are going to use constraint type inference instead) - adjust type string computation accordingly - minor related adjustments This change can be reverted if we don't like it. Change-Id: Ie1034e0996df8f5ca6fbdf9ecaa3c93fcfd7106d Reviewed-on: https://go-review.googlesource.com/c/go/+/249741 Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer --- src/go/types/api_test.go | 52 +- src/go/types/check_test.go | 2 +- src/go/types/examples/functions.go2 | 54 +-- src/go/types/examples/functionsB.go2 | 204 -------- src/go/types/examples/methods.go2 | 57 +-- src/go/types/examples/methodsB.go2 | 96 ---- src/go/types/examples/types.go2 | 93 ++-- src/go/types/examples/typesB.go2 | 284 ----------- src/go/types/fixedbugs/issue39634.go2 | 54 ++- src/go/types/fixedbugs/issue39664.go2 | 4 +- src/go/types/fixedbugs/issue39680.go2 | 6 +- src/go/types/fixedbugs/issue39693.go2 | 2 +- src/go/types/fixedbugs/issue39723.go2 | 2 +- src/go/types/fixedbugs/issue39725.go2 | 4 +- src/go/types/fixedbugs/issue39754.go2 | 12 +- src/go/types/fixedbugs/issue39755.go2 | 6 +- src/go/types/fixedbugs/issue39768.go2 | 12 +- src/go/types/fixedbugs/issue39938.go2 | 26 +- src/go/types/fixedbugs/issue39948.go2 | 2 +- src/go/types/fixedbugs/issue39976.go2 | 12 +- src/go/types/fixedbugs/issue39982.go2 | 22 +- src/go/types/fixedbugs/issue40038.go2 | 4 +- src/go/types/fixedbugs/issue40056.go2 | 4 +- src/go/types/fixedbugs/issue40057.go2 | 4 +- src/go/types/fixedbugs/issue40301.go2 | 2 +- src/go/types/subst.go | 4 +- src/go/types/testdata/builtins.go2 | 10 +- src/go/types/testdata/chans.go2 | 18 +- src/go/types/testdata/chansB.go2 | 62 --- src/go/types/testdata/expr3.src | 3 +- src/go/types/testdata/issues.go2 | 100 ++-- src/go/types/testdata/issuesB.go2 | 247 ---------- src/go/types/testdata/linalg.go2 | 24 +- src/go/types/testdata/linalgB.go2 | 83 ---- src/go/types/testdata/map.go2 | 40 +- src/go/types/testdata/map2.go2 | 55 +-- src/go/types/testdata/map2B.go2 | 146 ------ src/go/types/testdata/mapB.go2 | 116 ----- src/go/types/testdata/mtypeparams.go2 | 12 +- src/go/types/testdata/mtypeparamsB.go2 | 48 -- src/go/types/testdata/slices.go2 | 12 +- src/go/types/testdata/slicesB.go2 | 68 --- src/go/types/testdata/syntaxB.go2 | 28 -- .../{tinferenceB.go2 => tinference.go2} | 22 +- src/go/types/testdata/tmp.go2 | 8 +- src/go/types/testdata/tmpB.go2 | 17 - src/go/types/testdata/todos.go2 | 17 +- src/go/types/testdata/todosB.go2 | 22 - src/go/types/testdata/typeargs.go2 | 136 ------ src/go/types/testdata/typeargsB.go2 | 136 ------ src/go/types/testdata/typeinst.go2 | 36 +- src/go/types/testdata/typeinst2.go2 | 152 +++--- src/go/types/testdata/typeinst2B.go2 | 256 ---------- src/go/types/testdata/typeinstB.go2 | 51 -- src/go/types/testdata/typeparams.go2 | 297 ++++++------ src/go/types/testdata/typeparamsB.go2 | 445 ------------------ src/go/types/typestring.go | 13 +- src/go/types/typexpr.go | 2 +- src/go/types/unify.go | 4 +- 59 files changed, 634 insertions(+), 3076 deletions(-) delete mode 100644 src/go/types/examples/functionsB.go2 delete mode 100644 src/go/types/examples/methodsB.go2 delete mode 100644 src/go/types/examples/typesB.go2 delete mode 100644 src/go/types/testdata/chansB.go2 delete mode 100644 src/go/types/testdata/issuesB.go2 delete mode 100644 src/go/types/testdata/linalgB.go2 delete mode 100644 src/go/types/testdata/map2B.go2 delete mode 100644 src/go/types/testdata/mapB.go2 delete mode 100644 src/go/types/testdata/mtypeparamsB.go2 delete mode 100644 src/go/types/testdata/slicesB.go2 delete mode 100644 src/go/types/testdata/syntaxB.go2 rename src/go/types/testdata/{tinferenceB.go2 => tinference.go2} (66%) delete mode 100644 src/go/types/testdata/tmpB.go2 delete mode 100644 src/go/types/testdata/todosB.go2 delete mode 100644 src/go/types/testdata/typeargs.go2 delete mode 100644 src/go/types/testdata/typeargsB.go2 delete mode 100644 src/go/types/testdata/typeinst2B.go2 delete mode 100644 src/go/types/testdata/typeinstB.go2 delete mode 100644 src/go/types/testdata/typeparamsB.go2 diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 6f78de1cbb12c..04748644f77bb 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -277,20 +277,20 @@ func TestTypesInfo(t *testing.T) { {`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`}, // parameterized functions - {`package p0; func f(type T)(T); var _ = f(int)`, `f`, `func(type T₁)(T₁)`}, - {`package p1; func f(type T)(T); var _ = f(int)`, `f(int)`, `func(int)`}, - {`package p2; func f(type T)(T); var _ = f(42)`, `f`, `func(type T₁)(T₁)`}, - {`package p2; func f(type T)(T); var _ = f(42)`, `f(42)`, `()`}, + {`package p0; func f[T any](T); var _ = f(int)`, `f`, `func[T₁ any](T₁)`}, + {`package p1; func f[T any](T); var _ = f(int)`, `f(int)`, `func(int)`}, + {`package p2; func f[T any](T); var _ = f(42)`, `f`, `func[T₁ any](T₁)`}, + {`package p2; func f[T any](T); var _ = f(42)`, `f(42)`, `()`}, // type parameters - {`package t0; type t(type) int; var _ t`, `t`, `t0.t`}, - {`package t1; type t(type P) int; var _ t(int)`, `t`, `t1.t(type P₁)`}, - {`package t2; type t(type P interface{}) int; var _ t(int)`, `t`, `t2.t(type P₁)`}, - {`package t3; type t(type P, Q interface{}) int; var _ t(int, int)`, `t`, `t3.t(type P₁, Q₂)`}, - {`package t4; type t(type P, Q interface{ m() }) int; var _ t(int, int)`, `t`, `t4.t(type P₁, Q₂ interface{m()})`}, + {`package t0; type t[any] int; var _ t`, `t`, `t0.t`}, + {`package t1; type t[P any] int; var _ t[int]`, `t`, `t1.t[P₁ any]`}, + {`package t2; type t[P interface{}] int; var _ t[int]`, `t`, `t2.t[P₁ interface{}]`}, + {`package t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `t3.t[P₁, Q₂ interface{}]`}, + {`package t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `t4.t[P₁, Q₂ interface{m()}]`}, // instantiated types must be sanitized - {`package g0; type t(type P) int; var x struct{ f t(int) }; var _ = x.f`, `x.f`, `g0.t(int)`}, + {`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`}, } for _, test := range tests { @@ -324,17 +324,17 @@ func TestInferredInfo(t *testing.T) { targs []string sig string }{ - {`package p0; func f(type T)(T); func _() { f(42) }`, + {`package p0; func f[T any](T); func _() { f(42) }`, `f`, []string{`int`}, `func(int)`, }, - {`package p1; func f(type T)(T) T; func _() { f('@') }`, + {`package p1; func f[T any](T) T; func _() { f('@') }`, `f`, []string{`rune`}, `func(rune) rune`, }, - {`package p2; func f(type T)(...T) T; func _() { f(0i) }`, + {`package p2; func f[T any](...T) T; func _() { f(0i) }`, `f`, []string{`complex128`}, `func(...complex128) complex128`, @@ -351,17 +351,17 @@ func TestInferredInfo(t *testing.T) { }, // we don't know how to translate these but we can type-check them - {`package q0; type T struct{}; func (T) m(type P)(P); func _(x T) { x.m(42) }`, + {`package q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`, `x.m`, []string{`int`}, `func(int)`, }, - {`package q1; type T struct{}; func (T) m(type P)(P) P; func _(x T) { x.m(42) }`, + {`package q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`, `x.m`, []string{`int`}, `func(int) int`, }, - {`package q2; type T struct{}; func (T) m(type P)(...P) P; func _(x T) { x.m(42) }`, + {`package q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`, `x.m`, []string{`int`}, `func(...int) int`, @@ -377,12 +377,12 @@ func TestInferredInfo(t *testing.T) { `func(float64, *byte, ...[]byte)`, }, - {`package r0; type T(type P) struct{}; func (_ T(P)) m(type Q)(Q); func _(type P)(x T(P)) { x.m(42) }`, + {`package r0; type T[P any] struct{}; func (_ T[P]) m[type Q](Q); func _[P any](x T[P]) { x.m(42) }`, `x.m`, []string{`int`}, `func(int)`, }, - {`package r1; type T interface{ m(type P)(P) }; func _(x T) { x.m(4.2) }`, + {`package r1; type T interface{ m(type P any)(P) }; func _(x T) { x.m(4.2) }`, `x.m`, []string{`float64`}, `func(float64)`, @@ -445,10 +445,10 @@ func TestDefsInfo(t *testing.T) { // generic types must be sanitized // (need to use sufficiently nested types to provoke unexpanded types) - {`package g0; type t(type P) P; const x = (t(int))(42)`, `x`, `const g0.x g0.t(int)`}, - {`package g1; type t(type P) P; var x = (t(int))(42)`, `x`, `var g1.x g1.t(int)`}, - {`package g2; type t(type P) P; type x struct{ f t(int) }`, `x`, `type g2.x struct{f g2.t(int)}`}, - {`package g3; type t(type P) P; func f(x struct{ f t(string) }); var g = f`, `g`, `var g3.g func(x struct{f g3.t(string)})`}, + {`package g0; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`}, + {`package g1; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`}, + {`package g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`}, + {`package g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var g3.g func(x struct{f g3.t[string]})`}, } for _, test := range tests { @@ -490,10 +490,10 @@ func TestUsesInfo(t *testing.T) { // generic types must be sanitized // (need to use sufficiently nested types to provoke unexpanded types) - {`package g0; func _() { _ = x }; type t(type P) P; const x = (t(int))(42)`, `x`, `const g0.x g0.t(int)`}, - {`package g1; func _() { _ = x }; type t(type P) P; var x = (t(int))(42)`, `x`, `var g1.x g1.t(int)`}, - {`package g2; func _() { type _ x }; type t(type P) P; type x struct{ f t(int) }`, `x`, `type g2.x struct{f g2.t(int)}`}, - {`package g3; func _() { _ = f }; type t(type P) P; func f(x struct{ f t(string) })`, `f`, `func g3.f(x struct{f g3.t(string)})`}, + {`package g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`}, + {`package g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`}, + {`package g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`}, + {`package g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func g3.f(x struct{f g3.t[string]})`}, } for _, test := range tests { diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 16ee4e82142be..08fc78459e9a7 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -71,7 +71,7 @@ func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) { var files []*ast.File var errlist []error for _, filename := range filenames { - file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) + file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors|parser.UnifiedParamLists) if file == nil { t.Fatalf("%s: %s", filename, err) } diff --git a/src/go/types/examples/functions.go2 b/src/go/types/examples/functions.go2 index 396ddca452e19..6c09f890940ce 100644 --- a/src/go/types/examples/functions.go2 +++ b/src/go/types/examples/functions.go2 @@ -8,7 +8,7 @@ package p // Reverse is a generic function that takes a []T argument and // reverses that slice in place. -func Reverse (type T) (list []T) { +func Reverse[T any](list []T) { i := 0 j := len(list)-1 for i < j { @@ -20,9 +20,9 @@ func Reverse (type T) (list []T) { func _() { // Reverse can be called with an explicit type argument. - Reverse(int)(nil) - Reverse(string)([]string{"foo", "bar"}) - Reverse(struct{x, y int})([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}}) + Reverse[int](nil) + Reverse[string]([]string{"foo", "bar"}) + Reverse[struct{x, y int}]([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}}) // Since the type parameter is used for an incoming argument, // it can be inferred from the provided argument's type. @@ -34,12 +34,12 @@ func _() { // Reverse(nil) // this won't type-check // A typed nil will work, though. - Reverse([]int(nil)) + Reverse[[]int(nil)] } // Certain functions, such as the built-in `new` could be written using // type parameters. -func new (type T) () *T { +func new[T any]() *T { var x T return &x } @@ -49,56 +49,56 @@ func new (type T) () *T { // result type could be inferred. We don't try to infer the // result type from the assignment to keep things simple and // easy to understand. -var _ = new(int)() +var _ = new[int]() var _ *float64 = new(float64)() // the result type is indeed *float64 // A function may have multiple type parameters, of course. -func foo (type A, B, C) (a A, b []B, c *C) B { +func foo[A, B, C any](a A, b []B, c *C) B { // do something here return b[0] } // As before, we can pass type parameters explicitly. -var s = foo(int, string, float64)(1, []string{"first"}, new(float64)()) +var s = foo[int, string, float64](1, []string{"first"}, new(float64)()) // Or we can use type inference. var _ float64 = foo(42, []float64{1.0}, &s) // Type inference works in a straight-forward manner even // for variadic functions. -func variadic(type A, B)(A, B, ...B) int +func variadic[A, B any](A, B, ...B) int // var _ = variadic(1) // ERROR not enough arguments var _ = variadic(1, 2.3) var _ = variadic(1, 2.3, 3.4, 4.5) -var _ = variadic(int, float64)(1, 2.3, 3.4, 4) +var _ = variadic[int, float64](1, 2.3, 3.4, 4) // Type inference also works in recursive function calls where // the inferred type is the type parameter of the caller. -func f1(type T)(x T) { +func f1[T any](x T) { f1(x) } -func f2a(type T)(x, y T) { +func f2a[T any](x, y T) { f2a(x, y) } -func f2b(type T)(x, y T) { +func f2b[T any](x, y T) { f2b(y, x) } -func g2a(type P, Q)(x P, y Q) { +func g2a[P, Q any](x P, y Q) { g2a(x, y) } -func g2b(type P, Q)(x P, y Q) { +func g2b[P, Q any](x P, y Q) { g2b(y, x) } // Here's an example of a recursive function call with variadic // arguments and type inference inferring the type parameter of // the caller (i.e., itself). -func max(type T interface{ type int })(x ...T) T { +func max[T interface{ type int }](x ...T) T { var x0 T if len(x) > 0 { x0 = x[0] @@ -118,9 +118,9 @@ func max(type T interface{ type int })(x ...T) T { // Thus even if a type can be inferred successfully, the function // call may not be valid. -func fboth(type T)(chan T) -func frecv(type T)(<-chan T) -func fsend(type T)(chan<- T) +func fboth[T any](chan T) +func frecv[T any](<-chan T) +func fsend[T any](chan<- T) func _() { var both chan int @@ -140,9 +140,9 @@ func _() { fsend(send) } -func ffboth(type T)(func(chan T)) -func ffrecv(type T)(func(<-chan T)) -func ffsend(type T)(func(chan<- T)) +func ffboth[T any](func(chan T)) +func ffrecv[T any](func(<-chan T)) +func ffsend[T any](func(chan<- T)) func _() { var both func(chan int) @@ -169,9 +169,9 @@ func _() { // assignment is permitted, parameter passing is permitted as well, // so type inference should be able to handle these cases well. -func g1(type T)([]T) -func g2(type T)([]T, T) -func g3(type T)(*T, ...T) +func g1[T any]([]T) +func g2[T any]([]T, T) +func g3[T any](*T, ...T) func _() { type intSlize []int @@ -194,7 +194,7 @@ func _() { // Here's a realistic example. -func append(type T)(s []T, t ...T) []T +func append[T any](s []T, t ...T) []T func _() { var f func() diff --git a/src/go/types/examples/functionsB.go2 b/src/go/types/examples/functionsB.go2 deleted file mode 100644 index dd82a22712da2..0000000000000 --- a/src/go/types/examples/functionsB.go2 +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2019 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. - -// This file shows some examples of type-parameterized functions. - -package p - -// Reverse is a generic function that takes a []T argument and -// reverses that slice in place. -func Reverse[type T](list []T) { - i := 0 - j := len(list)-1 - for i < j { - list[i], list[j] = list[j], list[i] - i++ - j-- - } -} - -func _() { - // Reverse can be called with an explicit type argument. - Reverse[int](nil) - Reverse[string]([]string{"foo", "bar"}) - Reverse[struct{x, y int}]([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}}) - - // Since the type parameter is used for an incoming argument, - // it can be inferred from the provided argument's type. - Reverse([]string{"foo", "bar"}) - Reverse([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}}) - - // But the incoming argument must have a type, even if it's a - // default type. An untyped nil won't work. - // Reverse(nil) // this won't type-check - - // A typed nil will work, though. - Reverse[[]int(nil)] -} - -// Certain functions, such as the built-in `new` could be written using -// type parameters. -func new[type T]() *T { - var x T - return &x -} - -// When calling our own `new`, we need to pass the type parameter -// explicitly since there is no (value) argument from which the -// result type could be inferred. We don't try to infer the -// result type from the assignment to keep things simple and -// easy to understand. -var _ = new[int]() -var _ *float64 = new(float64)() // the result type is indeed *float64 - -// A function may have multiple type parameters, of course. -func foo[type A, B, C](a A, b []B, c *C) B { - // do something here - return b[0] -} - -// As before, we can pass type parameters explicitly. -var s = foo[int, string, float64](1, []string{"first"}, new(float64)()) - -// Or we can use type inference. -var _ float64 = foo(42, []float64{1.0}, &s) - -// Type inference works in a straight-forward manner even -// for variadic functions. -func variadic[type A, B](A, B, ...B) int - -// var _ = variadic(1) // ERROR not enough arguments -var _ = variadic(1, 2.3) -var _ = variadic(1, 2.3, 3.4, 4.5) -var _ = variadic[int, float64](1, 2.3, 3.4, 4) - -// Type inference also works in recursive function calls where -// the inferred type is the type parameter of the caller. -func f1[type T](x T) { - f1(x) -} - -func f2a[type T](x, y T) { - f2a(x, y) -} - -func f2b[type T](x, y T) { - f2b(y, x) -} - -func g2a[type P, Q](x P, y Q) { - g2a(x, y) -} - -func g2b[type P, Q](x P, y Q) { - g2b(y, x) -} - -// Here's an example of a recursive function call with variadic -// arguments and type inference inferring the type parameter of -// the caller (i.e., itself). -func max[type T interface{ type int }](x ...T) T { - var x0 T - if len(x) > 0 { - x0 = x[0] - } - if len(x) > 1 { - x1 := max(x[1:]...) - if x1 > x0 { - return x1 - } - } - return x0 -} - -// When inferring channel types, the channel direction is ignored -// for the purpose of type inference. Once the type has been in- -// fered, the usual parameter passing rules are applied. -// Thus even if a type can be inferred successfully, the function -// call may not be valid. - -func fboth[type T](chan T) -func frecv[type T](<-chan T) -func fsend[type T](chan<- T) - -func _() { - var both chan int - var recv <-chan int - var send chan<-int - - fboth(both) - fboth(recv /* ERROR cannot use */ ) - fboth(send /* ERROR cannot use */ ) - - frecv(both) - frecv(recv) - frecv(send /* ERROR cannot use */ ) - - fsend(both) - fsend(recv /* ERROR cannot use */) - fsend(send) -} - -func ffboth[type T](func(chan T)) -func ffrecv[type T](func(<-chan T)) -func ffsend[type T](func(chan<- T)) - -func _() { - var both func(chan int) - var recv func(<-chan int) - var send func(chan<- int) - - ffboth(both) - ffboth(recv /* ERROR cannot use */ ) - ffboth(send /* ERROR cannot use */ ) - - ffrecv(both /* ERROR cannot use */ ) - ffrecv(recv) - ffrecv(send /* ERROR cannot use */ ) - - ffsend(both /* ERROR cannot use */ ) - ffsend(recv /* ERROR cannot use */ ) - ffsend(send) -} - -// When inferring elements of unnamed composite parameter types, -// if the arguments are defined types, use their underlying types. -// Even though the matching types are not exactly structurally the -// same (one is a type literal, the other a named type), because -// assignment is permitted, parameter passing is permitted as well, -// so type inference should be able to handle these cases well. - -func g1[type T]([]T) -func g2[type T]([]T, T) -func g3[type T](*T, ...T) - -func _() { - type intSlize []int - g1([]int{}) - g1(intSlize{}) - g2(nil, 0) - - type myString string - var s1 string - g3(nil, "1", myString("2"), "3") - g3(&s1, "1", myString /* ERROR does not match */ ("2"), "3") - - type myStruct struct{x int} - var s2 myStruct - g3(nil, struct{x int}{}, myStruct{}) - g3(&s2, struct{x int}{}, myStruct{}) - g3(nil, myStruct{}, struct{x int}{}) - g3(&s2, myStruct{}, struct{x int}{}) -} - -// Here's a realistic example. - -func append[type T](s []T, t ...T) []T - -func _() { - var f func() - type Funcs []func() - var funcs Funcs - _ = append(funcs, f) -} diff --git a/src/go/types/examples/methods.go2 b/src/go/types/examples/methods.go2 index 1f0f74ad5bef2..95ff87291778b 100644 --- a/src/go/types/examples/methods.go2 +++ b/src/go/types/examples/methods.go2 @@ -7,20 +7,20 @@ package p // Parameterized types may have methods. -type T1(type A) struct{ a A } +type T1[A any] struct{ a A } // When declaring a method for a parameterized type, the "instantiated" // receiver type acts as an implicit declaration of the type parameters // for the receiver type. In the example below, method m1 on type T1 has -// the receiver type T1(A) which declares the type parameter A for use +// the receiver type T1[A] which declares the type parameter A for use // with this method. That is, within the method m1, A stands for the // actual type argument provided to an instantiated T1. -func (t T1(A)) m1() A { return t.a } +func (t T1[A]) m1() A { return t.a } // For instance, if T1 is instantiated with the type int, the type // parameter A in m1 assumes that type (int) as well and we can write // code like this: -var x T1(int) +var x T1[int] var _ int = x.m1() // Because the type parameter provided to a parameterized receiver type @@ -28,7 +28,7 @@ var _ int = x.m1() // It cannot possibly be some other type because the receiver type is not // instantiated with concrete types, it is standing for the parameterized // receiver type. -func (t T1([ /* ERROR must be an identifier */ ]int)) m2() {} +func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {} // Note that using what looks like a predeclared identifier, say int, // as type parameter in this situation is deceptive and considered bad @@ -39,7 +39,7 @@ func (t T1([ /* ERROR must be an identifier */ ]int)) m2() {} // and usually should be avoided. There are some notable exceptions; e.g., // sometimes it makes sense to use the identifier "copy" which happens to // also be the name of a predeclared built-in function. -func (t T1(int)) m3() { var _ int = 42 /* ERROR cannot convert 42 .* to int */ } +func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot convert 42 .* to int */ } // The names of the type parameters used in a parameterized receiver // type don't have to match the type parameter names in the the declaration @@ -49,7 +49,7 @@ func (t T1(int)) m3() { var _ int = 42 /* ERROR cannot convert 42 .* to int */ } // name of type parameters is always local to the declaration where they // are introduced. In our example we can write a method m2 and use the // name X instead of A for the type parameter w/o any difference. -func (t T1(X)) m4() X { return t.a } +func (t T1[X]) m4() X { return t.a } // If the receiver type is parameterized, type parameters must always be // provided: this simply follows from the general rule that a parameterized @@ -64,52 +64,33 @@ func (t T1 /* ERROR generic type .* without instantiation */ ) m5() {} // inconvenient to have to choose a name. Since the receiver type expression // serves as a declaration for its type parameters, we are free to choose the // blank identifier: -func (t T1(_)) m6() {} +func (t T1[_]) m6() {} // Naturally, these rules apply to any number of type parameters on the receiver // type. Here are some more complex examples. -type T2(type A, B, C) struct { +type T2[A, B, C any] struct { a A b B c C } // Naming of the type parameters is local and has no semantic impact: -func (t T2(A, B, C)) m1() (A, B, C) { return t.a, t.b, t.c } -func (t T2(C, B, A)) m2() (C, B, A) { return t.a, t.b, t.c } -func (t T2(X, Y, Z)) m3() (X, Y, Z) { return t.a, t.b, t.c } +func (t T2[A, B, C]) m1() (A, B, C) { return t.a, t.b, t.c } +func (t T2[C, B, A]) m2() (C, B, A) { return t.a, t.b, t.c } +func (t T2[X, Y, Z]) m3() (X, Y, Z) { return t.a, t.b, t.c } // Type parameters may be left blank if they are not needed: -func (t T2(A, _, C)) m4() (A, C) { return t.a, t.c } -func (t T2(_, _, X)) m5() X { return t.c } -func (t T2(_, _, _)) m6() {} +func (t T2[A, _, C]) m4() (A, C) { return t.a, t.c } +func (t T2[_, _, X]) m5() X { return t.c } +func (t T2[_, _, _]) m6() {} // As usual, blank names may be used for any object which we don't care about // using later. For instance, we may write an unnamed method with a receiver // that cannot be accessed: -func (_ T2(_, _, _)) _() int { return 42 } +func (_ T2[_, _, _]) _() int { return 42 } // Because a receiver parameter list is simply a parameter list, we can -// leave the receiver argument away for non-parameterized receiver types. +// leave the receiver argument away for receiver types. type T0 struct{} -func (T0) m() {} - -// This doesn't work for parameterized receiver types because there is -// a syntactic ambiguity: what looks like a parameterized receiver type -// T1(A) is parsed as a receiver argument named T1 followed by a -// parenthesized receiver type (A): (T1 (A)). -func (T1(A /* ERROR undeclared name: A */ )) _() {} - -// The work-around is to either use blank identifier for the receiver -// argument or to parenthesize the receiver type: -func (_ T1(A)) _(a A) {} -func ((T1(A))) _(a A) {} - -// Consequently, this problem appears in parameter lists in general: -func _(T1(A /* ERROR undeclared name: A */ )) {} - -// And the workaround is the same as for receivers: -func _(_ T1(int)) {} -func _((T1(int))) {} -func _(type A)(_ T1(A)) {} -func _(type A)((T1(A))) {} +func (T0) _() {} +func (T1[A]) _() {} diff --git a/src/go/types/examples/methodsB.go2 b/src/go/types/examples/methodsB.go2 deleted file mode 100644 index 58dd55a3671fe..0000000000000 --- a/src/go/types/examples/methodsB.go2 +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 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. - -// This file shows some examples of methods on type-parameterized types. - -package p - -// Parameterized types may have methods. -type T1[type A] struct{ a A } - -// When declaring a method for a parameterized type, the "instantiated" -// receiver type acts as an implicit declaration of the type parameters -// for the receiver type. In the example below, method m1 on type T1 has -// the receiver type T1[A] which declares the type parameter A for use -// with this method. That is, within the method m1, A stands for the -// actual type argument provided to an instantiated T1. -func (t T1[A]) m1() A { return t.a } - -// For instance, if T1 is instantiated with the type int, the type -// parameter A in m1 assumes that type (int) as well and we can write -// code like this: -var x T1[int] -var _ int = x.m1() - -// Because the type parameter provided to a parameterized receiver type -// is declared through that receiver declaration, it must be an identifier. -// It cannot possibly be some other type because the receiver type is not -// instantiated with concrete types, it is standing for the parameterized -// receiver type. -func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {} - -// Note that using what looks like a predeclared identifier, say int, -// as type parameter in this situation is deceptive and considered bad -// style. In m3 below, int is the name of the local receiver type parameter -// and it shadows the predeclared identifier int which then cannot be used -// anymore as expected. -// This is no different from locally redelaring a predeclared identifier -// and usually should be avoided. There are some notable exceptions; e.g., -// sometimes it makes sense to use the identifier "copy" which happens to -// also be the name of a predeclared built-in function. -func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot convert 42 .* to int */ } - -// The names of the type parameters used in a parameterized receiver -// type don't have to match the type parameter names in the the declaration -// of the type used for the receiver. In our example, even though T1 is -// declared with type parameter named A, methods using that receiver type -// are free to use their own name for that type parameter. That is, the -// name of type parameters is always local to the declaration where they -// are introduced. In our example we can write a method m2 and use the -// name X instead of A for the type parameter w/o any difference. -func (t T1[X]) m4() X { return t.a } - -// If the receiver type is parameterized, type parameters must always be -// provided: this simply follows from the general rule that a parameterized -// type must be instantiated before it can be used. A method receiver -// declaration using a parameterized receiver type is no exception. It is -// simply that such receiver type expressions perform two tasks simultaneously: -// they declare the (local) type parameters and then use them to instantiate -// the receiver type. Forgetting to provide a type parameter leads to an error. -func (t T1 /* ERROR generic type .* without instantiation */ ) m5() {} - -// However, sometimes we don't need the type parameter, and thus it is -// inconvenient to have to choose a name. Since the receiver type expression -// serves as a declaration for its type parameters, we are free to choose the -// blank identifier: -func (t T1[_]) m6() {} - -// Naturally, these rules apply to any number of type parameters on the receiver -// type. Here are some more complex examples. -type T2[type A, B, C] struct { - a A - b B - c C -} - -// Naming of the type parameters is local and has no semantic impact: -func (t T2[A, B, C]) m1() (A, B, C) { return t.a, t.b, t.c } -func (t T2[C, B, A]) m2() (C, B, A) { return t.a, t.b, t.c } -func (t T2[X, Y, Z]) m3() (X, Y, Z) { return t.a, t.b, t.c } - -// Type parameters may be left blank if they are not needed: -func (t T2[A, _, C]) m4() (A, C) { return t.a, t.c } -func (t T2[_, _, X]) m5() X { return t.c } -func (t T2[_, _, _]) m6() {} - -// As usual, blank names may be used for any object which we don't care about -// using later. For instance, we may write an unnamed method with a receiver -// that cannot be accessed: -func (_ T2[_, _, _]) _() int { return 42 } - -// Because a receiver parameter list is simply a parameter list, we can -// leave the receiver argument away for receiver types. -type T0 struct{} -func (T0) _() {} -func (T1[A]) _() {} diff --git a/src/go/types/examples/types.go2 b/src/go/types/examples/types.go2 index 5358835582c12..7bcd36b1e6324 100644 --- a/src/go/types/examples/types.go2 +++ b/src/go/types/examples/types.go2 @@ -7,49 +7,48 @@ package p // List is just what it says - a slice of E elements. -type List(type E) []E +type List[E any] []E // A generic (parameterized) type must always be instantiated // before it can be used to designate the type of a variable // (including a struct field, or function parameter); though // for the latter cases, the provided type may be another type // parameter. So: -var _ List(byte) = []byte{} +var _ List[byte] = []byte{} // A generic binary tree might be declared as follows. -type Tree(type E) struct { - left, right *Tree(E) +type Tree[E any] struct { + left, right *Tree[E] payload E } // A simple instantiation of Tree: -var root1 Tree(int) +var root1 Tree[int] // The actual type parameter provided may be a generic type itself: -var root2 Tree(List(int)) +var root2 Tree[List[int]] // A couple of more complex examples. -// Here, we need extra parentheses around the element type of the slices on the right -// to resolve the parsing ambiguity between the conversion []List(int) and the slice -// type with a parameterized elements type [](List(int)). -var _ List(List(int)) = [](List(int)){} -var _ List(List(List(Tree(int)))) = [](List(List(Tree(int)))){} +// We don't need extra parentheses around the element type of the slices on +// the right (unlike when we use ()'s rather than []'s for type parameters). +var _ List[List[int]] = []List[int]{} +var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{} // Type parameters act like type aliases when used in generic types // in the sense that we can "emulate" a specific type instantiation // with type aliases. -type T1(type P) struct { +type T1[P any] struct { f P } -type T2(type P) struct { +type T2[P any] struct { f struct { g P } } -var x1 T1(struct{ g int }) -var x2 T2(int) +var x1 T1[struct{ g int }] +var x2 T2[int] func _() { // This assignment is invalid because the types of x1, x2 are T1(...) @@ -85,10 +84,10 @@ func _() { // Another interesting corner case are generic types that don't use // their type arguments. For instance: -type T(type P) struct{} +type T[P any] struct{} -var xint T(int) -var xbool T(bool) +var xint T[int] +var xbool T[bool] // Are these two variables of the same type? After all, their underlying // types are identical. We consider them to be different because each type @@ -106,18 +105,17 @@ var _ T // ERROR cannot use generic type T // In type context, generic (parameterized) types cannot be parenthesized before // being instantiated. See also NOTES entry from 12/4/2019. -var _ (T /* ERROR cannot use generic type T */ )( /* ERROR expected ';' */ int) +var _ (T /* ERROR cannot use generic type T */ )[ /* ERROR expected ';' */ int] // All types may be parameterized, including interfaces. -type I1(type T) interface{ +type I1[T any] interface{ m1(T) } -// To differentiate an instantiated interface such as I1(int) from a method -// declaration when embedding it, we must use parentheses around it: +// Generic interfaces may be embedded as one would expect. type I2 interface { - I1(int) // method! - (I1(string)) // embedded I1 + I1(int) // method! + I1[string] // embedded I1 } func _() { @@ -126,19 +124,14 @@ func _() { x.m1("foo") } -// Generally, we now allow any embedded interfaces to be parenthesized. -// Because that removes the restriction that embedded interfaces must -// be named, we can even "inline" interface literals (though that's of -// little practial use - it's simply more complicated to disallow them). -// Here are some more examples: type I0 interface { m0() } type I3 interface { I0 - (I1(bool)) - ((interface{ m(string) })) + I1[bool] + m(string) } func _() { @@ -154,17 +147,19 @@ func _() { // They still need to be valid embedded types after the parentheses are stripped // (i.e., in contrast to interfaces, we cannot embed a struct literal). The name // of the embedded field is derived as before, after stripping parentheses. +// (7/14/2020: See comment above. We probably will revert this generalized ability +// if we go with [] for type parameters.) type _ struct { (int8) (*int16) *(int32) (*(int64)) (((*(int)))) - (*(List(int))) + (*(List[int])) int8 /* ERROR int8 redeclared */ int /* ERROR int redeclared */ - * /* ERROR List redeclared */ List(int) + * /* ERROR List redeclared */ List[int] ( /* ERROR invalid embedded field type */ [10]int) ( /* ERROR invalid embedded field type */ []int) @@ -179,7 +174,7 @@ type _ struct { // are type parameters. As with ordinary type definitions, the // types underlying properties are "inherited" but the methods // are not. -func _(type T interface{ m(); type int })() { +func _[T interface{ m(); type int }]() { type L T var x L @@ -206,13 +201,13 @@ func _(type T interface{ m(); type int })() { // one type argument. In that case, the type argument is the // respective type parameter to which the type bound applies. // Note: We may not permit this syntactic sugar at first. -type Adder(type T) interface { +type Adder[T any] interface { Add(T) T } // We don't need to explicitly instantiate the Adder bound // if we have exactly one type parameter. -func Sum(type T Adder)(list []T) T { +func Sum[T Adder](list []T) T { var sum T for _, x := range list { sum = sum.Add(x) @@ -222,29 +217,29 @@ func Sum(type T Adder)(list []T) T { // Valid and invalid variations. type B0 interface {} -type B1(type _) interface{} -type B2(type _, _) interface{} +type B1[_ any] interface{} +type B2[_, _ any] interface{} -func _(type T1 B0)() -func _(type T1 B1)() -func _(type T1 B2 /* ERROR cannot use generic type .* without instantiation */ )() +func _[T1 B0]() +func _[T1 B1]() +func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]() -func _(type T1, T2 B0)() -func _(type T1, T2 B1)() -func _(type T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ )() +func _[T1, T2 B0]() +func _[T1, T2 B1]() +func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]() -func _(type T1 B0, T2 B1)() // here B1 applies to T2 +func _[T1 B0, T2 B1]() // here B1 applies to T2 // When the type argument is left away, the type bound is // instantiated for each type parameter with that type // parameter. // Note: We may not permit this syntactic sugar at first. -func _(type A, B Adder, C Adder(A))() { - var a A // A's type bound is Adder(A) +func _[A, B Adder, C Adder[A]]() { + var a A // A's type bound is Adder[A] a = a.Add(a) - var b B // B's type bound is Adder(B) + var b B // B's type bound is Adder[B] b = b.Add(b) - var c C // C's type bound is Adder(A) + var c C // C's type bound is Adder[A] a = c.Add(a) } diff --git a/src/go/types/examples/typesB.go2 b/src/go/types/examples/typesB.go2 deleted file mode 100644 index 972a13be0c07f..0000000000000 --- a/src/go/types/examples/typesB.go2 +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2019 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. - -// This file shows some examples of generic types. - -package p - -// List is just what it says - a slice of E elements. -type List[type E] []E - -// A generic (parameterized) type must always be instantiated -// before it can be used to designate the type of a variable -// (including a struct field, or function parameter); though -// for the latter cases, the provided type may be another type -// parameter. So: -var _ List[byte] = []byte{} - -// A generic binary tree might be declared as follows. -type Tree[type E] struct { - left, right *Tree[E] - payload E -} - -// A simple instantiation of Tree: -var root1 Tree[int] - -// The actual type parameter provided may be a generic type itself: -var root2 Tree[List[int]] - -// A couple of more complex examples. -// We don't need extra parentheses around the element type of the slices on -// the right (unlike when we use ()'s rather than []'s for type parameters). -var _ List[List[int]] = []List[int]{} -var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{} - -// Type parameters act like type aliases when used in generic types -// in the sense that we can "emulate" a specific type instantiation -// with type aliases. -type T1[type P] struct { - f P -} - -type T2[type P] struct { - f struct { - g P - } -} - -var x1 T1[struct{ g int }] -var x2 T2[int] - -func _() { - // This assignment is invalid because the types of x1, x2 are T1(...) - // and T2(...) respectively, which are two different defined types. - x1 = x2 // ERROR assignment - - // This assignment is valid because the types of x1.f and x2.f are - // both struct { g int }; the type parameters act like type aliases - // and their actual names don't come into play here. - x1.f = x2.f -} - -// We can verify this behavior using type aliases instead: -type T1a struct { - f A1 -} -type A1 = struct { g int } - -type T2a struct { - f struct { - g A2 - } -} -type A2 = int - -var x1a T1a -var x2a T2a - -func _() { - x1a = x2a // ERROR assignment - x1a.f = x2a.f -} - -// Another interesting corner case are generic types that don't use -// their type arguments. For instance: -type T[type P] struct{} - -var xint T[int] -var xbool T[bool] - -// Are these two variables of the same type? After all, their underlying -// types are identical. We consider them to be different because each type -// instantiation creates a new named type, in this case T and T -// even if their underlying types are identical. This is sensible because -// we might still have methods that have different signatures or behave -// differently depending on the type arguments, and thus we can't possibly -// consider such types identical. Consequently: -func _() { - xint = xbool // ERROR assignment -} - -// Generic types cannot be used without instantiation. -var _ T // ERROR cannot use generic type T - -// In type context, generic (parameterized) types cannot be parenthesized before -// being instantiated. See also NOTES entry from 12/4/2019. -var _ (T /* ERROR cannot use generic type T */ )[ /* ERROR expected ';' */ int] - -// All types may be parameterized, including interfaces. -type I1[type T] interface{ - m1(T) -} - -// Generic interfaces may be emnedded as one would expect. -type I2 interface { - I1(int) // method! - I1[string] // embedded I1 -} - -func _() { - var x I2 - x.I1(0) - x.m1("foo") -} - -// Generally, we now allow any embedded interfaces to be parenthesized. -// Because that removes the restriction that embedded interfaces must -// be named, we can even "inline" interface literals (though that's of -// little practial use - it's simply more complicated to disallow them). -// (7/14/2020: We will probably revert this ability again because we -// don't need it when using [] instead of ()'s for type parameters.) -// Here are some more examples: -type I0 interface { - m0() -} - -type I3 interface { - I0 - (I1[bool]) - ((interface{ m(string) })) -} - -func _() { - var x I3 - x.m0() - x.m1(true) - x.m("foo") -} - -// We accept parenthesized embedded struct fields so we can distinguish between -// a named field with a parenthesized type foo (T) and an embedded parameterized -// type (foo(T)), similarly to interace embedding. -// They still need to be valid embedded types after the parentheses are stripped -// (i.e., in contrast to interfaces, we cannot embed a struct literal). The name -// of the embedded field is derived as before, after stripping parentheses. -// (7/14/2020: See comment above. We probably will revert this generalized ability -// if we go with [] for type parameters.) -type _ struct { - (int8) - (*int16) - *(int32) - (*(int64)) - (((*(int)))) - (*(List[int])) - - int8 /* ERROR int8 redeclared */ - int /* ERROR int redeclared */ - * /* ERROR List redeclared */ List[int] - - ( /* ERROR invalid embedded field type */ [10]int) - ( /* ERROR invalid embedded field type */ []int) - ( /* ERROR invalid embedded field type */ struct{}) - ( /* ERROR invalid embedded field type */ map[int]string) - ( /* ERROR invalid embedded field type */ chan<- int) - ( /* ERROR invalid embedded field type */ interface{}) - ( /* ERROR invalid embedded field type */ func()) -} - -// 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 _[type T interface{ m(); type 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 -} - -// As a special case, an explicit type argument may be omitted -// from a type parameter bound if the type bound expects exactly -// one type argument. In that case, the type argument is the -// respective type parameter to which the type bound applies. -// Note: We may not permit this syntactic sugar at first. -type Adder[type T] interface { - Add(T) T -} - -// We don't need to explicitly instantiate the Adder bound -// if we have exactly one type parameter. -func Sum[type T Adder](list []T) T { - var sum T - for _, x := range list { - sum = sum.Add(x) - } - return sum -} - -// Valid and invalid variations. -type B0 interface {} -type B1[type _] interface{} -type B2[type _, _] interface{} - -func _[type T1 B0]() -func _[type T1 B1]() -func _[type T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]() - -func _[type T1, T2 B0]() -func _[type T1, T2 B1]() -func _[type T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]() - -func _[type T1 B0, T2 B1]() // here B1 applies to T2 - -// When the type argument is left away, the type bound is -// instantiated for each type parameter with that type -// parameter. -// Note: We may not permit this syntactic sugar at first. -func _[type A, B Adder, C Adder[A]]() { - var a A // A's type bound is Adder[A] - a = a.Add(a) - var b B // B's type bound is Adder[B] - b = b.Add(b) - var c C // C's type bound is Adder[A] - a = c.Add(a) -} - -// The type of variables (incl. parameters and return values) cannot -// be an interface with type constraints or be/embed comparable. -type I interface { - type int -} - -var ( - _ interface /* ERROR cannot contain type constraints */ {type int} - _ I /* ERROR cannot contain type constraints */ -) - -func _(I /* ERROR cannot contain type constraints */ ) -func _(x, y, z I /* ERROR cannot contain type constraints */ ) -func _() I /* ERROR cannot contain type constraints */ - -func _() { - var _ I /* ERROR cannot contain type constraints */ -} - -type C interface { - comparable -} - -var _ comparable /* ERROR comparable */ -var _ C /* ERROR comparable */ - -func _(_ comparable /* ERROR comparable */ , _ C /* ERROR comparable */ ) - -func _() { - var _ comparable /* ERROR comparable */ - var _ C /* ERROR comparable */ -} \ No newline at end of file diff --git a/src/go/types/fixedbugs/issue39634.go2 b/src/go/types/fixedbugs/issue39634.go2 index 0de085ee069fd..9983e480eb0bd 100644 --- a/src/go/types/fixedbugs/issue39634.go2 +++ b/src/go/types/fixedbugs/issue39634.go2 @@ -2,49 +2,51 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Examples adjusted to match new [T any] syntax for type parameters. + package p // crash 1 -type nt1(type )interface{g /* ERROR undeclared name */ } -type ph1(type e nt1,g(d /* ERROR undeclared name */ ))s /* ERROR undeclared name */ -func(*ph1(e,e /* ERROR redeclared */ ))h(d /* ERROR undeclared name */ ) +type nt1[_ any]interface{g /* ERROR undeclared name */ } +type ph1[e nt1,g(d /* ERROR undeclared name */ )]s /* ERROR undeclared name */ +func(*ph1[e,e /* ERROR redeclared */ ])h(d /* ERROR undeclared name */ ) // crash 2 type Numeric2 interface{t2 /* ERROR not a type */ } -func t2(type T Numeric2)(s[]T){0 /* ERROR not a type */ (){s /* ERROR cannot index */ [0][0]}} +func t2[T Numeric2](s[]T){0 /* ERROR not a type */ []{s /* ERROR cannot index */ [0][0]}} // crash 3 type t3 *interface{ t3.p /* ERROR no field or method p */ } // crash 4 type Numeric4 interface{t4 /* ERROR not a type */ } -func t4(type T Numeric4)(s[]T){if( /* ERROR non-boolean */ 0){*s /* ERROR cannot indirect */ [0]}} +func t4[T Numeric4](s[]T){if( /* ERROR non-boolean */ 0){*s /* ERROR cannot indirect */ [0]}} // crash 7 type foo7 interface { bar() } -type x7(type A) struct{ foo7 } -func main7() { var _ foo7 = x7(int){} } +type x7[A any] struct{ foo7 } +func main7() { var _ foo7 = x7[int]{} } // crash 8 -type foo8(type A) interface { type A } -func bar8(type A foo8(A))(a A) {} +type foo8[A any] interface { type A } +func bar8[A foo8[A]](a A) {} func main8() {} // crash 9 -type foo9(type A) interface { type foo9(A) } -func _() { var _ = new(foo9(int)) } +type foo9[A any] interface { type foo9[A] } +func _() { var _ = new(foo9[int]) } // crash 12 var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len)]c /* ERROR undeclared */ /* ERROR undeclared */ // crash 15 -func y15() { var a /* ERROR declared but not used */ interface{ p() } = G15(string){} } -type G15(type X) s /* ERROR undeclared name */ +func y15() { var a /* ERROR declared but not used */ interface{ p() } = G15[string]{} } +type G15[X any] s /* ERROR undeclared name */ func (G15 /* ERROR generic type .* without instantiation */ ) p() // crash 16 -type Foo16(type T) r16 /* ERROR not a type */ -func r16(type T)() Foo16((Foo16(T))) +type Foo16[T any] r16 /* ERROR not a type */ +func r16[T any]() Foo16[Foo16[T]] // crash 17 type Y17 interface{ c() } @@ -52,35 +54,35 @@ type Z17 interface { c() Y17 Y17 /* ERROR duplicate method */ } -func F17(type T Z17)(T) +func F17[T Z17](T) // crash 18 -type o18(type T) []func(_ o18([]_ /* ERROR cannot use _ */ )) +type o18[T any] []func(_ o18[[]_ /* ERROR cannot use _ */ ]) // crash 19 type Z19 [][[]Z19{}[0][0]]c19 /* ERROR undeclared */ // crash 20 type Z20 /* ERROR illegal cycle */ interface{ Z20 } -func F20(type t Z20)() { F20(t /* ERROR invalid composite literal type */ {}) } +func F20[t Z20]() { F20(t /* ERROR invalid composite literal type */ {}) } // crash 21 type Z21 /* ERROR illegal cycle */ interface{ Z21 } -func F21(type *T Z21)() { ( /* ERROR not used */ F21(Z21)) } +func F21[T Z21]() { ( /* ERROR not used */ F21[Z21]) } // crash 24 -type T24(type P) P -func (r T24(P)) m() { T24 /* ERROR without instantiation */ .m() } +type T24[P any] P +func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() } // crash 25 -type T25(type A) int -func (t T25(A)) m1() {} +type T25[A any] int +func (t T25[A]) m1() {} var x T25 /* ERROR without instantiation */ .m1 // crash 26 -type T26 = interface{ F26(type Z)() } -func F26(type Z)() T26 { return F26() /* ERROR cannot infer Z */ } +type T26 = interface{ F26[Z any]() } +func F26[Z any]() T26 { return F26[] /* ERROR cannot infer Z */ } // crash 27 -func e27(type T)() interface{ (x27 /* ERROR not a type */ ) } +func e27[T any]() interface{ x27 /* ERROR not a type */ } func x27() { e27() /* ERROR cannot infer T */ } \ No newline at end of file diff --git a/src/go/types/fixedbugs/issue39664.go2 b/src/go/types/fixedbugs/issue39664.go2 index 28be805e9640f..3b3ec56980edd 100644 --- a/src/go/types/fixedbugs/issue39664.go2 +++ b/src/go/types/fixedbugs/issue39664.go2 @@ -4,12 +4,12 @@ package p -type T(type _) struct {} +type T[_ any] struct {} func (T /* ERROR instantiation */ ) m() func _() { var x interface { m() } - x = T(int){} + x = T[int]{} _ = x } diff --git a/src/go/types/fixedbugs/issue39680.go2 b/src/go/types/fixedbugs/issue39680.go2 index b519908d485eb..9bc26f3546134 100644 --- a/src/go/types/fixedbugs/issue39680.go2 +++ b/src/go/types/fixedbugs/issue39680.go2 @@ -7,16 +7,16 @@ package p import "fmt" // Minimal test case. -func _(type T interface{type T})(x T) T{ +func _[T interface{type T}](x T) T{ return x } // Test case from issue. -type constr(type T) interface { +type constr[T any] interface { type T } -func Print(type T constr(T))(s []T) { +func Print[T constr[T]](s []T) { for _, v := range s { fmt.Print(v) } diff --git a/src/go/types/fixedbugs/issue39693.go2 b/src/go/types/fixedbugs/issue39693.go2 index e3edd94644b8f..316ab1982e89c 100644 --- a/src/go/types/fixedbugs/issue39693.go2 +++ b/src/go/types/fixedbugs/issue39693.go2 @@ -9,6 +9,6 @@ type Number interface { float64 /* ERROR float64 is not an interface */ } -func Add(type T Number)(a, b T) T { +func Add[T Number](a, b T) T { return a /* ERROR not defined */ + b } diff --git a/src/go/types/fixedbugs/issue39723.go2 b/src/go/types/fixedbugs/issue39723.go2 index c0ca89e8b9d47..55464e6b7759f 100644 --- a/src/go/types/fixedbugs/issue39723.go2 +++ b/src/go/types/fixedbugs/issue39723.go2 @@ -6,4 +6,4 @@ package p // A constraint must be an interface; it cannot // be a type parameter, for instance. -func _(type A interface{ type interface{} }, B A /* ERROR not an interface */ )() +func _[A interface{ type interface{} }, B A /* ERROR not an interface */ ]() diff --git a/src/go/types/fixedbugs/issue39725.go2 b/src/go/types/fixedbugs/issue39725.go2 index 320dcd3bd9398..e19b6770bfe4b 100644 --- a/src/go/types/fixedbugs/issue39725.go2 +++ b/src/go/types/fixedbugs/issue39725.go2 @@ -4,13 +4,13 @@ package p -func f1(type T1, T2)(T1, T2, struct{a T1; b T2}) +func f1[T1, T2 any](T1, T2, struct{a T1; b T2}) func _() { f1(42, string("foo"), struct /* ERROR does not match inferred type struct\{a int; b string\} */ {a, b int}{}) } // simplified test case from issue -func f2(type T)(_ []T, _ func(T)) +func f2[T any](_ []T, _ func(T)) func _() { f2([]string{}, func /* ERROR does not match inferred type func\(string\) */ (f []byte) {}) } diff --git a/src/go/types/fixedbugs/issue39754.go2 b/src/go/types/fixedbugs/issue39754.go2 index ad3dd1fa6e8ce..0de777a18c701 100644 --- a/src/go/types/fixedbugs/issue39754.go2 +++ b/src/go/types/fixedbugs/issue39754.go2 @@ -4,17 +4,17 @@ package p -type Optional(type T) struct {} +type Optional[T any] struct {} -func (_ Optional(T)) Val() (T, bool) +func (_ Optional[T]) Val() (T, bool) -type Box(type T) interface { +type Box[T any] interface { Val() (T, bool) } -func f(type V interface{}, A, B Box(V))() {} +func f[V interface{}, A, B Box[V]]() {} func _() { - f(int, Optional(int), Optional(int))() - f(int, Optional(int), Optional /* ERROR does not satisfy Box */ (string))() + f[int, Optional[int], Optional[int]]() + f[int, Optional[int], Optional /* ERROR does not satisfy Box */ [string]]() } diff --git a/src/go/types/fixedbugs/issue39755.go2 b/src/go/types/fixedbugs/issue39755.go2 index 6fd898a07ab83..b7ab68818e958 100644 --- a/src/go/types/fixedbugs/issue39755.go2 +++ b/src/go/types/fixedbugs/issue39755.go2 @@ -4,7 +4,7 @@ package p -func _(type T interface{type map[string]int})(x T) { +func _[T interface{type map[string]int}](x T) { _ = x == nil } @@ -14,10 +14,10 @@ type PathParamsConstraint interface { type map[string]string, []struct{key, value string} } -type PathParams(type T PathParamsConstraint) struct { +type PathParams[T PathParamsConstraint] struct { t T } -func (pp *PathParams(T)) IsNil() bool { +func (pp *PathParams[T]) IsNil() bool { return pp.t == nil // this must succeed } diff --git a/src/go/types/fixedbugs/issue39768.go2 b/src/go/types/fixedbugs/issue39768.go2 index dd28cbcbd2a61..abac141d7f08d 100644 --- a/src/go/types/fixedbugs/issue39768.go2 +++ b/src/go/types/fixedbugs/issue39768.go2 @@ -4,17 +4,17 @@ package p -type T(type P) P +type T[P any] P type A = T -var x A(int) +var x A[int] var _ A /* ERROR cannot use generic type */ -type B = T(int) +type B = T[int] var y B = x -var _ B /* ERROR not a generic type */ (int) +var _ B /* ERROR not a generic type */ [int] // test case from issue -type Vector(type T) []T +type Vector[T any] []T type VectorAlias = Vector -var v Vector(int) +var v Vector[int] diff --git a/src/go/types/fixedbugs/issue39938.go2 b/src/go/types/fixedbugs/issue39938.go2 index c6035ddbccb3f..76e7e369ca12b 100644 --- a/src/go/types/fixedbugs/issue39938.go2 +++ b/src/go/types/fixedbugs/issue39938.go2 @@ -6,45 +6,45 @@ package p -type E0(type P) P -type E1(type P) *P -type E2(type P) struct{ P } -type E3(type P) struct{ *P } +type E0[P any] P +type E1[P any] *P +type E2[P any] struct{ P } +type E3[P any] struct{ *P } type T0 /* ERROR illegal cycle */ struct { - _ E0(T0) + _ E0[T0] } type T0_ /* ERROR illegal cycle */ struct { - (E0(T0_)) + E0[T0_] } type T1 struct { - _ E1(T1) + _ E1[T1] } type T2 /* ERROR illegal cycle */ struct { - _ E2(T2) + _ E2[T2] } type T3 struct { - _ E3(T3) + _ E3[T3] } // some more complex cases type T4 /* ERROR illegal cycle */ struct { - _ E0(E2(T4)) + _ E0[E2[T4]] } type T5 struct { - _ E0(E2(E0(E1(E2([10]T5))))) + _ E0[E2[E0[E1[E2[[10]T5]]]]] } type T6 /* ERROR illegal cycle */ struct { - _ E0([10]E2(E0(E2(E2(T6))))) + _ E0[[10]E2[E0[E2[E2[T6]]]]] } type T7 struct { - _ E0([]E2(E0(E2(E2(T6))))) + _ E0[[]E2[E0[E2[E2[T6]]]]] } diff --git a/src/go/types/fixedbugs/issue39948.go2 b/src/go/types/fixedbugs/issue39948.go2 index 73f7e88592ad5..c2b460902cc64 100644 --- a/src/go/types/fixedbugs/issue39948.go2 +++ b/src/go/types/fixedbugs/issue39948.go2 @@ -4,6 +4,6 @@ package p -type T(type P) interface{ +type T[P any] interface{ P // ERROR P is a type parameter, not an interface } diff --git a/src/go/types/fixedbugs/issue39976.go2 b/src/go/types/fixedbugs/issue39976.go2 index 2413ebfbae3bc..3db4eae012393 100644 --- a/src/go/types/fixedbugs/issue39976.go2 +++ b/src/go/types/fixedbugs/issue39976.go2 @@ -4,13 +4,13 @@ package p -type policy(type K, V) interface{} -type LRU(type K, V) struct{} +type policy[K, V any] interface{} +type LRU[K, V any] struct{} -func NewCache(type K, V)(p policy(K, V)) +func NewCache[K, V any](p policy[K, V]) func _() { - var lru LRU(int, string) - NewCache(int, string)(&lru) - NewCache(& /* ERROR does not match policy\(K, V\) \(cannot infer K and V\) */ lru) + var lru LRU[int, string] + NewCache[int, string](&lru) + NewCache(& /* ERROR does not match policy\[K, V\] \(cannot infer K and V\) */ lru) } diff --git a/src/go/types/fixedbugs/issue39982.go2 b/src/go/types/fixedbugs/issue39982.go2 index 934a6780ed133..9810b6386a9a9 100644 --- a/src/go/types/fixedbugs/issue39982.go2 +++ b/src/go/types/fixedbugs/issue39982.go2 @@ -5,32 +5,32 @@ package p type ( - T(type _) struct{} - S(type _) struct { - data T(*T(int)) + T[_ any] struct{} + S[_ any] struct { + data T[*T[int]] } ) func _() { - _ = S(int){ - data: T(*T(int)){}, + _ = S[int]{ + data: T[*T[int]]{}, } } // full test case from issue type ( - Element(type TElem) struct{} + Element[TElem any] struct{} - entry(type K comparable) struct{} + entry[K comparable] struct{} - Cache(type K comparable) struct { - data map[K]*Element(*entry(K)) + Cache[K comparable] struct { + data map[K]*Element[*entry[K]] } ) func _() { - _ = Cache(int){ - data: make(map[int](*Element(*entry(int)))), + _ = Cache[int]{ + data: make(map[int](*Element[*entry[int]])), } } diff --git a/src/go/types/fixedbugs/issue40038.go2 b/src/go/types/fixedbugs/issue40038.go2 index 731018712d322..c31440851b15e 100644 --- a/src/go/types/fixedbugs/issue40038.go2 +++ b/src/go/types/fixedbugs/issue40038.go2 @@ -4,11 +4,11 @@ package p -type A[type T] int +type A[T any] int func (A[T]) m(A[T]) -func f[type P interface{m(P)}]() +func f[P interface{m(P)}]() func _() { _ = f[A] diff --git a/src/go/types/fixedbugs/issue40056.go2 b/src/go/types/fixedbugs/issue40056.go2 index 7ef3895579450..71074be67e20d 100644 --- a/src/go/types/fixedbugs/issue40056.go2 +++ b/src/go/types/fixedbugs/issue40056.go2 @@ -10,6 +10,6 @@ func _() { type S struct {} -func NewS(type T)() *S +func NewS[T any]() *S -func (_ *S /* ERROR S is not a generic type */ (T)) M() \ No newline at end of file +func (_ *S /* ERROR S is not a generic type */ [T]) M() \ No newline at end of file diff --git a/src/go/types/fixedbugs/issue40057.go2 b/src/go/types/fixedbugs/issue40057.go2 index abedddca1ab86..fdc8fb1c00ace 100644 --- a/src/go/types/fixedbugs/issue40057.go2 +++ b/src/go/types/fixedbugs/issue40057.go2 @@ -12,6 +12,6 @@ func _() { } } -type S(type T) struct {} +type S[T any] struct {} -func (_ S(T)) m() +func (_ S[T]) m() diff --git a/src/go/types/fixedbugs/issue40301.go2 b/src/go/types/fixedbugs/issue40301.go2 index e43df84d6e2f0..5d97855f8a172 100644 --- a/src/go/types/fixedbugs/issue40301.go2 +++ b/src/go/types/fixedbugs/issue40301.go2 @@ -6,7 +6,7 @@ package p import "unsafe" -func _[type T](x T) { +func _[T any](x T) { _ = unsafe /* ERROR undefined */ .Alignof(x) _ = unsafe /* ERROR undefined */ .Sizeof(x) } diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 7f99e7aed51a5..678bb8fe16588 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -62,7 +62,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist var under Type if res != nil { // Calling Under() here may lead to endless instantiations. - // Test case: type T(type P) T(P) + // Test case: type T[P any] T[P] // TODO(gri) investigate if that's a bug or to be expected. under = res.Underlying() } @@ -451,7 +451,7 @@ func typeListString(list []Type) string { } // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid]. -// A nil type may appear in pathological cases such as type T(type P) []func(_ T([]_)) +// A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_)) // where an array/slice element is accessed before it is set up. func (subst *subster) typOrNil(typ Type) Type { if typ == nil { diff --git a/src/go/types/testdata/builtins.go2 b/src/go/types/testdata/builtins.go2 index e05a3460ab7bd..3918d836b5277 100644 --- a/src/go/types/testdata/builtins.go2 +++ b/src/go/types/testdata/builtins.go2 @@ -22,31 +22,31 @@ type Bss interface { type []int, []string } -func _(type T) () { +func _[T any] () { _ = make(T /* ERROR invalid argument */ ) _ = make(T /* ERROR invalid argument */ , 10) _ = make(T /* ERROR invalid argument */ , 10, 20) } -func _(type T Bmc) () { +func _[T Bmc] () { _ = make(T) _ = make(T, 10) _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20) } -func _(type T Bms) () { +func _[T Bms] () { _ = make /* ERROR expects 2 arguments */ (T) _ = make(T, 10) _ = make /* ERROR expects 2 arguments */ (T, 10, 20) } -func _(type T Bcs) () { +func _[T Bcs] () { _ = make /* ERROR expects 2 arguments */ (T) _ = make(T, 10) _ = make /* ERROR expects 2 arguments */ (T, 10, 20) } -func _(type T Bss) () { +func _[T Bss] () { _ = make /* ERROR expects 2 or 3 arguments */ (T) _ = make(T, 10) _ = make(T, 10, 20) diff --git a/src/go/types/testdata/chans.go2 b/src/go/types/testdata/chans.go2 index d6ca4df447424..fad2bcec9d083 100644 --- a/src/go/types/testdata/chans.go2 +++ b/src/go/types/testdata/chans.go2 @@ -10,24 +10,24 @@ import "runtime" // // This is a convenient way to exit a goroutine sending values when // the receiver stops reading them. -func Ranger(type T)() (*Sender(T), *Receiver(T)) { +func Ranger[T any]() (*Sender[T], *Receiver[T]) { c := make(chan T) d := make(chan bool) - s := &Sender(T){values: c, done: d} - r := &Receiver(T){values: c, done: d} + s := &Sender[T]{values: c, done: d} + r := &Receiver[T]{values: c, done: d} runtime.SetFinalizer(r, r.finalize) return s, r } // A sender is used to send values to a Receiver. -type Sender(type T) struct { +type Sender[T any] struct { values chan<- T done <-chan bool } // Send sends a value to the receiver. It returns whether any more // values may be sent; if it returns false the value was not sent. -func (s *Sender(T)) Send(v T) bool { +func (s *Sender[T]) Send(v T) bool { select { case s.values <- v: return true @@ -38,12 +38,12 @@ func (s *Sender(T)) Send(v T) bool { // Close tells the receiver that no more values will arrive. // After Close is called, the Sender may no longer be used. -func (s *Sender(T)) Close() { +func (s *Sender[T]) Close() { close(s.values) } // A Receiver receives values from a Sender. -type Receiver(type T) struct { +type Receiver[T any] struct { values <-chan T done chan<- bool } @@ -51,12 +51,12 @@ type Receiver(type T) struct { // Next returns the next value from the channel. The bool result // indicates whether the value is valid, or whether the Sender has // been closed and no more values will be received. -func (r *Receiver(T)) Next() (T, bool) { +func (r *Receiver[T]) Next() (T, bool) { v, ok := <-r.values return v, ok } // finalize is a finalizer for the receiver. -func (r *Receiver(T)) finalize() { +func (r *Receiver[T]) finalize() { close(r.done) } diff --git a/src/go/types/testdata/chansB.go2 b/src/go/types/testdata/chansB.go2 deleted file mode 100644 index d2ee3a3599280..0000000000000 --- a/src/go/types/testdata/chansB.go2 +++ /dev/null @@ -1,62 +0,0 @@ -package chans - -import "runtime" - -// Ranger returns a Sender and a Receiver. The Receiver provides a -// Next method to retrieve values. The Sender provides a Send method -// to send values and a Close method to stop sending values. The Next -// method indicates when the Sender has been closed, and the Send -// method indicates when the Receiver has been freed. -// -// This is a convenient way to exit a goroutine sending values when -// the receiver stops reading them. -func Ranger[type T]() (*Sender[T], *Receiver[T]) { - c := make(chan T) - d := make(chan bool) - s := &Sender[T]{values: c, done: d} - r := &Receiver[T]{values: c, done: d} - runtime.SetFinalizer(r, r.finalize) - return s, r -} - -// A sender is used to send values to a Receiver. -type Sender[type T] struct { - values chan<- T - done <-chan bool -} - -// Send sends a value to the receiver. It returns whether any more -// values may be sent; if it returns false the value was not sent. -func (s *Sender[T]) Send(v T) bool { - select { - case s.values <- v: - return true - case <-s.done: - return false - } -} - -// Close tells the receiver that no more values will arrive. -// After Close is called, the Sender may no longer be used. -func (s *Sender[T]) Close() { - close(s.values) -} - -// A Receiver receives values from a Sender. -type Receiver[type T] struct { - values <-chan T - done chan<- bool -} - -// Next returns the next value from the channel. The bool result -// indicates whether the value is valid, or whether the Sender has -// been closed and no more values will be received. -func (r *Receiver[T]) Next() (T, bool) { - v, ok := <-r.values - return v, ok -} - -// finalize is a finalizer for the receiver. -func (r *Receiver[T]) finalize() { - close(r.done) -} diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src index e42af0ba019ac..b2ccd3690d809 100644 --- a/src/go/types/testdata/expr3.src +++ b/src/go/types/testdata/expr3.src @@ -7,8 +7,9 @@ package expr3 import "time" func indexes() { + var x int _ = 1 /* ERROR "cannot index" */ [0] - _ = indexes /* ERROR "cannot index" */ [0] + _ = x /* ERROR "cannot index" */ [0] _ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2] var a [10]int diff --git a/src/go/types/testdata/issues.go2 b/src/go/types/testdata/issues.go2 index ad5d2100db616..bd12288852d38 100644 --- a/src/go/types/testdata/issues.go2 +++ b/src/go/types/testdata/issues.go2 @@ -10,7 +10,7 @@ import "io" import "context" // Interfaces are always comparable (though the comparison may panic at runtime). -func eql(type T comparable)(x, y T) bool { +func eql[T comparable](x, y T) bool { return x == y } @@ -28,17 +28,17 @@ func _() { // the pointer in the implementation of the method lookup because // the type bound of T is an interface an pointer to interface types // have no methods and then the lookup would fail. -type C(type T) interface { +type C[T any] interface { m() } // using type bound C -func _(type T C)(x *T) { +func _[T C](x *T) { x.m() } // using an interface literal as bound -func _(type T interface{ m() })(x *T) { +func _[T interface{ m() }](x *T) { x.m() } @@ -48,7 +48,7 @@ func _(type T interface{ m() })(x *T) { // Thus, assume an argument type for a generic function to be the type of addressable // values in the generic function when checking if the argument type satisfies the // generic function's type bound. -func f2(type _ interface{ m1(); m2() })() +func f2[_ interface{ m1(); m2() }]() type T struct{} func (T) m1() @@ -63,10 +63,10 @@ func _() { // type with a type list constraint, all of the type argument's types in its // bound, but at least one (!), must be in the type list of the bound of the // corresponding parameterized type's type parameter. -type T1(type P interface{type uint}) struct{} +type T1[P interface{type uint}] struct{} -func _(type P)() { - _ = T1(P /* ERROR P has no type constraints */ ){} +func _[P any]() { + _ = T1[P /* ERROR P has no type constraints */ ]{} } // This is the original (simplified) program causing the same issue. @@ -74,52 +74,52 @@ type Unsigned interface { type uint } -type T2(type U Unsigned) struct { +type T2[U Unsigned] struct { s U } -func (u T2(U)) Add1() U { +func (u T2[U]) Add1() U { return u.s + 1 } -func NewT2(type U)() T2(U /* ERROR U has no type constraints */ ) { - return T2(U /* ERROR U has no type constraints */ ){} +func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] { + return T2[U /* ERROR U has no type constraints */ ]{} } func _() { - u := NewT2(string)() + u := NewT2[string]() _ = u.Add1() } -// When we encounter an instantiated type such as Elem(T) we must +// When we encounter an instantiated type such as Elem[T] we must // not "expand" the instantiation when the type to be instantiated // (Elem in this case) is not yet fully set up. -type Elem(type T) struct { - next *Elem(T) - list *List(T) +type Elem[T any] struct { + next *Elem[T] + list *List[T] } -type List(type T) struct { - root Elem(T) +type List[T any] struct { + root Elem[T] } -func (l *List(T)) Init() { +func (l *List[T]) Init() { l.root.next = &l.root } // This is the original program causing the same issue. -type Element2(type TElem) struct { - next, prev *Element2(TElem) - list *List2(TElem) +type Element2[TElem any] struct { + next, prev *Element2[TElem] + list *List2[TElem] Value TElem } -type List2(type TElem) struct { - root Element2(TElem) +type List2[TElem any] struct { + root Element2[TElem] len int } -func (l *List2(TElem)) Init() *List2(TElem) { +func (l *List2[TElem]) Init() *List2[TElem] { l.root.next = &l.root l.root.prev = &l.root l.len = 0 @@ -127,34 +127,34 @@ func (l *List2(TElem)) Init() *List2(TElem) { } // Self-recursive instantiations must work correctly. -type A(type P) struct { _ *A(P) } +type A[P any] struct { _ *A[P] } -type AB(type P) struct { _ *BA(P) } -type BA(type P) struct { _ *AB(P) } +type AB[P any] struct { _ *BA[P] } +type BA[P any] struct { _ *AB[P] } // And a variation that also caused a problem with an // unresolved underlying type. -type Element3(type TElem) struct { - next, prev *Element3(TElem) - list *List3(TElem) +type Element3[TElem any] struct { + next, prev *Element3[TElem] + list *List3[TElem] Value TElem } -func (e *Element3(TElem)) Next() *Element3(TElem) { +func (e *Element3[TElem]) Next() *Element3[TElem] { if p := e.next; e.list != nil && p != &e.list.root { return p } return nil } -type List3(type TElem) struct { - root Element3(TElem) +type List3[TElem any] struct { + root Element3[TElem] len int } // Infinite generic type declarations must lead to an error. -type inf1(type T) struct{ _ inf1 /* ERROR illegal cycle */ (T) } -type inf2(type T) struct{ (inf2 /* ERROR illegal cycle */ (T)) } +type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] } +type inf2[T any] struct{ (inf2 /* ERROR illegal cycle */ [T]) } // The implementation of conversions T(x) between integers and floating-point // numbers checks that both T and x have either integer or floating-point @@ -162,24 +162,24 @@ type inf2(type T) struct{ (inf2 /* ERROR illegal cycle */ (T)) } // predicate disjunction in the implementation was wrong because if a type list // contains both an integer and a floating-point type, the type parameter is // neither an integer or a floating-point number. -func convert(type T1, T2 interface{type int, uint, float32})(v T1) T2 { +func convert[T1, T2 interface{type int, uint, float32}](v T1) T2 { return T2(v) } func _() { - convert(int, uint)(5) + convert[int, uint](5) } // When testing binary operators, for +, the operand types must either be // both numeric, or both strings. The implementation had the same problem // with this check as the conversion issue above (issue #39623). -func issue39623(type T interface{type int, string})(x, y T) T { +func issue39623[T interface{type int, string}](x, y T) T { return x + y } // Simplified, from https://go2goplay.golang.org/p/efS6x6s-9NI: -func Sum(type T interface{type int, string})(s []T) (sum T) { +func Sum[T interface{type int, string}](s []T) (sum T) { for _, v := range s { sum += v } @@ -188,19 +188,19 @@ func Sum(type T interface{type int, string})(s []T) (sum T) { // Assignability of an unnamed pointer type to a type parameter that // has a matching underlying type. -func _(type T interface{}, PT interface{type *T}) (x T) PT { +func _[T interface{}, PT interface{type *T}] (x T) PT { return &x } // Indexing of generic types containing type parameters in their type list: -func at(type T interface{ type []E }, E interface{})(x T, i int) E { +func at[T interface{ type []E }, E interface{}](x T, i int) E { return x[i] } // A generic type inside a function acts like a named type. Its underlying // type is itself, its "operational type" is defined by the type list in // the tybe bound, if any. -func _(type T interface{type int})(x T) { +func _[T interface{type int}](x T) { type myint int var _ int = int(x) var _ T = 42 @@ -209,24 +209,24 @@ func _(type T interface{type int})(x T) { // Indexing a generic type with an array type bound checks length. // (Example by mdempsky@.) -func _(type T interface { type [10]int })(x T) { +func _[T interface { type [10]int }](x T) { _ = x[9] // ok _ = x[20 /* ERROR out of bounds */ ] } // Pointer indirection of a generic type. -func _(type T interface{ type *int })(p T) int { +func _[T interface{ type *int }](p T) int { return *p } // Channel sends and receives on generic types. -func _(type T interface{ type chan int })(ch T) int { +func _[T interface{ type chan int }](ch T) int { ch <- 0 return <- ch } // Calling of a generic variable. -func _(type T interface{ type func() })(f T) { +func _[T interface{ type func() }](f T) { f() go f() } @@ -238,9 +238,9 @@ func _(type T interface{ type func() })(f T) { // type parameter that was substituted with a defined type. // Test case from an (originally) failing example. -type sliceOf(type E) interface{ type []E } +type sliceOf[E any] interface{ type []E } -func append(type T interface{}, S sliceOf(T), T2 interface{ type T })(s S, t ...T2) S +func append[T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S var f func() var cancelSlice []context.CancelFunc diff --git a/src/go/types/testdata/issuesB.go2 b/src/go/types/testdata/issuesB.go2 deleted file mode 100644 index bb60b5b7e4d91..0000000000000 --- a/src/go/types/testdata/issuesB.go2 +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2020 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. - -// This file contains regression tests for bugs found. - -package p - -import "io" -import "context" - -// Interfaces are always comparable (though the comparison may panic at runtime). -func eql[type T comparable](x, y T) bool { - return x == y -} - -func _() { - var x interface{} - var y interface{ m() } - eql(x, y /* ERROR does not match */ ) // interfaces of different types - eql(x, x) - eql(y, y) - eql(y, nil) - eql(io.Reader)(nil, nil) -} - -// If we have a receiver of pointer type (below: *T) we must ignore -// the pointer in the implementation of the method lookup because -// the type bound of T is an interface an pointer to interface types -// have no methods and then the lookup would fail. -type C[type T] interface { - m() -} - -// using type bound C -func _[type T C](x *T) { - x.m() -} - -// using an interface literal as bound -func _[type T interface{ m() }](x *T) { - x.m() -} - -// In a generic function body all method calls will be pointer method calls. -// If necessary, the function body will insert temporary variables, not seen -// by the user, in order to get an addressable variable to use to call the method. -// Thus, assume an argument type for a generic function to be the type of addressable -// values in the generic function when checking if the argument type satisfies the -// generic function's type bound. -func f2[type _ interface{ m1(); m2() }]() - -type T struct{} -func (T) m1() -func (*T) m2() - -func _() { - f2(T /* ERROR missing method m2 */ )() - f2(*T)() -} - -// When a type parameter is used as an argument to instantiate a parameterized -// type with a type list constraint, all of the type argument's types in its -// bound, but at least one (!), must be in the type list of the bound of the -// corresponding parameterized type's type parameter. -type T1[type P interface{type uint}] struct{} - -func _[type P]() { - _ = T1[P /* ERROR P has no type constraints */ ]{} -} - -// This is the original (simplified) program causing the same issue. -type Unsigned interface { - type uint -} - -type T2[type U Unsigned] struct { - s U -} - -func (u T2[U]) Add1() U { - return u.s + 1 -} - -func NewT2[type U]() T2[U /* ERROR U has no type constraints */ ] { - return T2[U /* ERROR U has no type constraints */ ]{} -} - -func _() { - u := NewT2[string]() - _ = u.Add1() -} - -// When we encounter an instantiated type such as Elem[T] we must -// not "expand" the instantiation when the type to be instantiated -// (Elem in this case) is not yet fully set up. -type Elem[type T] struct { - next *Elem[T] - list *List[T] -} - -type List[type T] struct { - root Elem[T] -} - -func (l *List[T]) Init() { - l.root.next = &l.root -} - -// This is the original program causing the same issue. -type Element2[type TElem] struct { - next, prev *Element2[TElem] - list *List2[TElem] - Value TElem -} - -type List2[type TElem] struct { - root Element2[TElem] - len int -} - -func (l *List2[TElem]) Init() *List2[TElem] { - l.root.next = &l.root - l.root.prev = &l.root - l.len = 0 - return l -} - -// Self-recursive instantiations must work correctly. -type A[type P] struct { _ *A[P] } - -type AB[type P] struct { _ *BA[P] } -type BA[type P] struct { _ *AB[P] } - -// And a variation that also caused a problem with an -// unresolved underlying type. -type Element3[type TElem] struct { - next, prev *Element3[TElem] - list *List3[TElem] - Value TElem -} - -func (e *Element3[TElem]) Next() *Element3[TElem] { - if p := e.next; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -type List3[type TElem] struct { - root Element3[TElem] - len int -} - -// Infinite generic type declarations must lead to an error. -type inf1[type T] struct{ _ inf1 /* ERROR illegal cycle */ [T] } -type inf2[type T] struct{ (inf2 /* ERROR illegal cycle */ [T]) } - -// The implementation of conversions T(x) between integers and floating-point -// numbers checks that both T and x have either integer or floating-point -// type. When the type of T or x is a type parameter, the respective simple -// predicate disjunction in the implementation was wrong because if a type list -// contains both an integer and a floating-point type, the type parameter is -// neither an integer or a floating-point number. -func convert[type T1, T2 interface{type int, uint, float32}](v T1) T2 { - return T2(v) -} - -func _() { - convert[int, uint](5) -} - -// When testing binary operators, for +, the operand types must either be -// both numeric, or both strings. The implementation had the same problem -// with this check as the conversion issue above (issue #39623). - -func issue39623[type T interface{type int, string}](x, y T) T { - return x + y -} - -// Simplified, from https://go2goplay.golang.org/p/efS6x6s-9NI: -func Sum[type T interface{type int, string}](s []T) (sum T) { - for _, v := range s { - sum += v - } - return -} - -// Assignability of an unnamed pointer type to a type parameter that -// has a matching underlying type. -func _[type T interface{}, PT interface{type *T}] (x T) PT { - return &x -} - -// Indexing of generic types containing type parameters in their type list: -func at[type T interface{ type []E }, E interface{}](x T, i int) E { - return x[i] -} - -// A generic type inside a function acts like a named type. Its underlying -// type is itself, its "operational type" is defined by the type list in -// the tybe bound, if any. -func _[type T interface{type int}](x T) { - type myint int - var _ int = int(x) - var _ T = 42 - var _ T = T(myint(42)) -} - -// Indexing a generic type with an array type bound checks length. -// (Example by mdempsky@.) -func _[type T interface { type [10]int }](x T) { - _ = x[9] // ok - _ = x[20 /* ERROR out of bounds */ ] -} - -// Pointer indirection of a generic type. -func _[type T interface{ type *int }](p T) int { - return *p -} - -// Channel sends and receives on generic types. -func _[type T interface{ type chan int }](ch T) int { - ch <- 0 - return <- ch -} - -// Calling of a generic variable. -func _[type T interface{ type func() }](f T) { - f() - go f() -} - -// We must compare against the underlying type of type list entries -// when checking if a constraint is satisfied by a type. The under- -// lying type of each type list entry must be computed after the -// interface has been instantiated as its typelist may contain a -// type parameter that was substituted with a defined type. -// Test case from an (originally) failing example. - -type sliceOf[type E] interface{ type []E } - -func append[type T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S - -var f func() -var cancelSlice []context.CancelFunc -var _ = append(context.CancelFunc, []context.CancelFunc, context.CancelFunc)(cancelSlice, f) diff --git a/src/go/types/testdata/linalg.go2 b/src/go/types/testdata/linalg.go2 index 595a4ee97f862..fba0d02eb2fe0 100644 --- a/src/go/types/testdata/linalg.go2 +++ b/src/go/types/testdata/linalg.go2 @@ -15,7 +15,7 @@ type Numeric interface { complex64, complex128 } -func DotProduct(type T Numeric)(s1, s2 []T) T { +func DotProduct[T Numeric](s1, s2 []T) T { if len(s1) != len(s2) { panic("DotProduct: slices of unequal length") } @@ -27,7 +27,7 @@ func DotProduct(type T Numeric)(s1, s2 []T) T { } // NumericAbs matches numeric types with an Abs method. -type NumericAbs(type T) interface { +type NumericAbs[T any] interface { Numeric Abs() T @@ -35,7 +35,7 @@ type NumericAbs(type T) interface { // AbsDifference computes the absolute value of the difference of // a and b, where the absolute value is determined by the Abs method. -func AbsDifference(type T NumericAbs)(a, b T) T { +func AbsDifference[T NumericAbs](a, b T) T { d := a - b return d.Abs() } @@ -54,9 +54,9 @@ type Complex interface { // OrderedAbs is a helper type that defines an Abs method for // ordered numeric types. -type OrderedAbs(type T OrderedNumeric) T +type OrderedAbs[T OrderedNumeric] T -func (a OrderedAbs(T)) Abs() OrderedAbs(T) { +func (a OrderedAbs[T]) Abs() OrderedAbs[T] { if a < 0 { return -a } @@ -65,19 +65,19 @@ func (a OrderedAbs(T)) Abs() OrderedAbs(T) { // ComplexAbs is a helper type that defines an Abs method for // complex types. -type ComplexAbs(type T Complex) T +type ComplexAbs[T Complex] T -func (a ComplexAbs(T)) Abs() ComplexAbs(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)) + return ComplexAbs[T](complex(d, 0)) } -func OrderedAbsDifference(type T OrderedNumeric)(a, b T) T { - return T(AbsDifference(OrderedAbs(T)(a), OrderedAbs(T)(b))) +func OrderedAbsDifference[T OrderedNumeric](a, b T) T { + return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b))) } -func ComplexAbsDifference(type T Complex)(a, b T) T { - return T(AbsDifference(ComplexAbs(T)(a), ComplexAbs(T)(b))) +func ComplexAbsDifference[T Complex](a, b T) T { + return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b))) } diff --git a/src/go/types/testdata/linalgB.go2 b/src/go/types/testdata/linalgB.go2 deleted file mode 100644 index a72f7be8b9bdb..0000000000000 --- a/src/go/types/testdata/linalgB.go2 +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2019 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 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 { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64, - complex64, complex128 -} - -func DotProduct[type T Numeric](s1, s2 []T) T { - if len(s1) != len(s2) { - panic("DotProduct: slices of unequal length") - } - var r T - for i := range s1 { - r += s1[i] * s2[i] - } - return r -} - -// NumericAbs matches numeric types with an Abs method. -type NumericAbs[type T] interface { - Numeric - - Abs() T -} - -// AbsDifference computes the absolute value of the difference of -// a and b, where the absolute value is determined by the Abs method. -func AbsDifference[type T NumericAbs](a, b T) T { - d := a - b - return d.Abs() -} - -// OrderedNumeric is a type bound that matches numeric types that support the < operator. -type OrderedNumeric interface { - type int, int8, int16, int32, int64, - uint, uint8, uint16, uint32, uint64, uintptr, - float32, float64 -} - -// Complex is a type bound that matches the two complex types, which do not have a < operator. -type Complex interface { - type complex64, complex128 -} - -// OrderedAbs is a helper type that defines an Abs method for -// ordered numeric types. -type OrderedAbs[type 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[type 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[type T OrderedNumeric](a, b T) T { - return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b))) -} - -func ComplexAbsDifference[type T Complex](a, b T) T { - return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b))) -} diff --git a/src/go/types/testdata/map.go2 b/src/go/types/testdata/map.go2 index 6d5e39a4ddf19..814d9539fdc94 100644 --- a/src/go/types/testdata/map.go2 +++ b/src/go/types/testdata/map.go2 @@ -9,27 +9,27 @@ package orderedmap import "chans" // ERROR could not import // Map is an ordered map. -type Map(type K, V) struct { - root *node(K, V) +type Map[K, V any] struct { + root *node[K, V] compare func(K, K) int } // node is the type of a node in the binary tree. -type node(type K, V) struct { +type node[K, V any] struct { key K val V - left, right *node(K, V) + left, right *node[K, V] } // New returns a new map. -func New(type K, V)(compare func(K, K) int) *Map(K, V) { - return &Map(K, V){compare: compare} +func New[K, V any](compare func(K, K) int) *Map[K, V] { + return &Map[K, V]{compare: compare} } // find looks up key in the map, and returns either a pointer // to the node holding key, or a pointer to the location where // such a node would go. -func (m *Map(K, V)) find(key K) **node(K, V) { +func (m *Map[K, V]) find(key K) **node[K, V] { pn := &m.root for *pn != nil { switch cmp := m.compare(key, (*pn).key); { @@ -47,19 +47,19 @@ func (m *Map(K, V)) find(key K) **node(K, V) { // Insert inserts a new key/value into the map. // If the key is already present, the value is replaced. // Returns true if this is a new key, false if already present. -func (m *Map(K, V)) Insert(key K, val V) bool { +func (m *Map[K, V]) Insert(key K, val V) bool { pn := m.find(key) if *pn != nil { (*pn).val = val return false } - *pn = &node(K, V){key: key, val: val} + *pn = &node[K, V]{key: key, val: val} return true } // Find returns the value associated with a key, or zero if not present. // The found result reports whether the key was found. -func (m *Map(K, V)) Find(key K) (V, bool) { +func (m *Map[K, V]) Find(key K) (V, bool) { pn := m.find(key) if *pn == nil { var zero V // see the discussion of zero values, above @@ -69,40 +69,40 @@ func (m *Map(K, V)) Find(key K) (V, bool) { } // keyValue is a pair of key and value used when iterating. -type keyValue(type K, V) struct { +type keyValue[K, V any] struct { key K val V } // InOrder returns an iterator that does an in-order traversal of the map. -func (m *Map(K, V)) InOrder() *Iterator(K, V) { - sender, receiver := chans.Ranger(keyValue(K, V))() - var f func(*node(K, V)) bool - f = func(n *node(K, V)) bool { +func (m *Map[K, V]) InOrder() *Iterator[K, V] { + sender, receiver := chans.Ranger[keyValue[K, V]]() + var f func(*node[K, V]) bool + f = func(n *node[K, V]) bool { if n == nil { return true } // Stop sending values if sender.Send returns false, // meaning that nothing is listening at the receiver end. return f(n.left) && - sender.Send(keyValue(K, V){n.key, n.val}) && + sender.Send(keyValue[K, V]{n.key, n.val}) && f(n.right) } go func() { f(m.root) sender.Close() }() - return &Iterator(K, V){receiver} + return &Iterator[K, V]{receiver} } // Iterator is used to iterate over the map. -type Iterator(type K, V) struct { - r *chans.Receiver(keyValue(K, V)) +type Iterator[K, V any] struct { + r *chans.Receiver[keyValue[K, V]] } // Next returns the next key and value pair, and a boolean indicating // whether they are valid or whether we have reached the end. -func (it *Iterator(K, V)) Next() (K, V, bool) { +func (it *Iterator[K, V]) Next() (K, V, bool) { keyval, ok := it.r.Next() if !ok { var zerok K diff --git a/src/go/types/testdata/map2.go2 b/src/go/types/testdata/map2.go2 index b88521427a167..2833445662de8 100644 --- a/src/go/types/testdata/map2.go2 +++ b/src/go/types/testdata/map2.go2 @@ -9,27 +9,27 @@ package orderedmap // Map is an ordered map. -type Map(type K, V) struct { - root *node(K, V) +type Map[K, V any] struct { + root *node[K, V] compare func(K, K) int } // node is the type of a node in the binary tree. -type node(type K, V) struct { +type node[K, V any] struct { key K val V - left, right *node(K, V) + left, right *node[K, V] } // New returns a new map. -func New(type K, V)(compare func(K, K) int) *Map(K, V) { - return &Map(K, V){compare: compare} +func New[K, V any](compare func(K, K) int) *Map[K, V] { + return &Map[K, V]{compare: compare} } // find looks up key in the map, and returns either a pointer // to the node holding key, or a pointer to the location where // such a node would go. -func (m *Map(K, V)) find(key K) **node(K, V) { +func (m *Map[K, V]) find(key K) **node[K, V] { pn := &m.root for *pn != nil { switch cmp := m.compare(key, (*pn).key); { @@ -47,19 +47,19 @@ func (m *Map(K, V)) find(key K) **node(K, V) { // Insert inserts a new key/value into the map. // If the key is already present, the value is replaced. // Returns true if this is a new key, false if already present. -func (m *Map(K, V)) Insert(key K, val V) bool { +func (m *Map[K, V]) Insert(key K, val V) bool { pn := m.find(key) if *pn != nil { (*pn).val = val return false } - *pn = &node(K, V){key: key, val: val} + *pn = &node[K, V]{key: key, val: val} return true } // Find returns the value associated with a key, or zero if not present. // The found result reports whether the key was found. -func (m *Map(K, V)) Find(key K) (V, bool) { +func (m *Map[K, V]) Find(key K) (V, bool) { pn := m.find(key) if *pn == nil { var zero V // see the discussion of zero values, above @@ -69,43 +69,40 @@ func (m *Map(K, V)) Find(key K) (V, bool) { } // keyValue is a pair of key and value used when iterating. -type keyValue(type K, V) struct { +type keyValue[K, V any] struct { key K val V } // InOrder returns an iterator that does an in-order traversal of the map. -func (m *Map(K, V)) InOrder() *Iterator(K, V) { - sender, receiver := chans_Ranger(keyValue(K, V))() - var f func(*node(K, V)) bool - f = func(n *node(K, V)) bool { +func (m *Map[K, V]) InOrder() *Iterator[K, V] { + sender, receiver := chans_Ranger[keyValue[K, V]]() + var f func(*node[K, V]) bool + f = func(n *node[K, V]) bool { if n == nil { return true } // Stop sending values if sender.Send returns false, // meaning that nothing is listening at the receiver end. return f(n.left) && - sender.Send(keyValue(K, V){n.key, n.val}) && + sender.Send(keyValue[K, V]{n.key, n.val}) && f(n.right) } go func() { f(m.root) sender.Close() }() - // TODO(gri) The design draft doesn't require that we repeat - // the type parameters here. Fix the implementation. - return &Iterator(K, V){receiver} - // return &Iterator{receiver} + return &Iterator[K, V]{receiver} } // Iterator is used to iterate over the map. -type Iterator(type K, V) struct { - r *chans_Receiver(keyValue(K, V)) +type Iterator[K, V any] struct { + r *chans_Receiver[keyValue[K, V]] } // Next returns the next key and value pair, and a boolean indicating // whether they are valid or whether we have reached the end. -func (it *Iterator(K, V)) Next() (K, V, bool) { +func (it *Iterator[K, V]) Next() (K, V, bool) { keyval, ok := it.r.Next() if !ok { var zerok K @@ -117,15 +114,15 @@ func (it *Iterator(K, V)) Next() (K, V, bool) { // chans -func chans_Ranger(type T)() (*chans_Sender(T), *chans_Receiver(T)) +func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T]) // A sender is used to send values to a Receiver. -type chans_Sender(type T) struct { +type chans_Sender[T any] struct { values chan<- T done <-chan bool } -func (s *chans_Sender(T)) Send(v T) bool { +func (s *chans_Sender[T]) Send(v T) bool { select { case s.values <- v: return true @@ -134,16 +131,16 @@ func (s *chans_Sender(T)) Send(v T) bool { } } -func (s *chans_Sender(T)) Close() { +func (s *chans_Sender[T]) Close() { close(s.values) } -type chans_Receiver(type T) struct { +type chans_Receiver[T any] struct { values <-chan T done chan<- bool } -func (r *chans_Receiver(T)) Next() (T, bool) { +func (r *chans_Receiver[T]) Next() (T, bool) { v, ok := <-r.values return v, ok } \ No newline at end of file diff --git a/src/go/types/testdata/map2B.go2 b/src/go/types/testdata/map2B.go2 deleted file mode 100644 index 257702b7a5858..0000000000000 --- a/src/go/types/testdata/map2B.go2 +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2019 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. - -// This file is like map.go2, but instead if importing chans, it contains -// the necessary functionality at the end of the file. - -// Package orderedmap provides an ordered map, implemented as a binary tree. -package orderedmap - -// Map is an ordered map. -type Map[type K, V] struct { - root *node[K, V] - compare func(K, K) int -} - -// node is the type of a node in the binary tree. -type node[type K, V] struct { - key K - val V - left, right *node[K, V] -} - -// New returns a new map. -func New[type K, V](compare func(K, K) int) *Map[K, V] { - return &Map[K, V]{compare: compare} -} - -// find looks up key in the map, and returns either a pointer -// to the node holding key, or a pointer to the location where -// such a node would go. -func (m *Map[K, V]) find(key K) **node[K, V] { - pn := &m.root - for *pn != nil { - switch cmp := m.compare(key, (*pn).key); { - case cmp < 0: - pn = &(*pn).left - case cmp > 0: - pn = &(*pn).right - default: - return pn - } - } - return pn -} - -// Insert inserts a new key/value into the map. -// If the key is already present, the value is replaced. -// Returns true if this is a new key, false if already present. -func (m *Map[K, V]) Insert(key K, val V) bool { - pn := m.find(key) - if *pn != nil { - (*pn).val = val - return false - } - *pn = &node[K, V]{key: key, val: val} - return true -} - -// Find returns the value associated with a key, or zero if not present. -// The found result reports whether the key was found. -func (m *Map[K, V]) Find(key K) (V, bool) { - pn := m.find(key) - if *pn == nil { - var zero V // see the discussion of zero values, above - return zero, false - } - return (*pn).val, true -} - -// keyValue is a pair of key and value used when iterating. -type keyValue[type K, V] struct { - key K - val V -} - -// InOrder returns an iterator that does an in-order traversal of the map. -func (m *Map[K, V]) InOrder() *Iterator[K, V] { - sender, receiver := chans_Ranger[keyValue[K, V]]() - var f func(*node[K, V]) bool - f = func(n *node[K, V]) bool { - if n == nil { - return true - } - // Stop sending values if sender.Send returns false, - // meaning that nothing is listening at the receiver end. - return f(n.left) && - sender.Send(keyValue[K, V]{n.key, n.val}) && - f(n.right) - } - go func() { - f(m.root) - sender.Close() - }() - return &Iterator[K, V]{receiver} -} - -// Iterator is used to iterate over the map. -type Iterator[type K, V] struct { - r *chans_Receiver[keyValue[K, V]] -} - -// Next returns the next key and value pair, and a boolean indicating -// whether they are valid or whether we have reached the end. -func (it *Iterator[K, V]) Next() (K, V, bool) { - keyval, ok := it.r.Next() - if !ok { - var zerok K - var zerov V - return zerok, zerov, false - } - return keyval.key, keyval.val, true -} - -// chans - -func chans_Ranger[type T]() (*chans_Sender[T], *chans_Receiver[T]) - -// A sender is used to send values to a Receiver. -type chans_Sender[type T] struct { - values chan<- T - done <-chan bool -} - -func (s *chans_Sender[T]) Send(v T) bool { - select { - case s.values <- v: - return true - case <-s.done: - return false - } -} - -func (s *chans_Sender[T]) Close() { - close(s.values) -} - -type chans_Receiver[type T] struct { - values <-chan T - done chan<- bool -} - -func (r *chans_Receiver[T]) Next() (T, bool) { - v, ok := <-r.values - return v, ok -} \ No newline at end of file diff --git a/src/go/types/testdata/mapB.go2 b/src/go/types/testdata/mapB.go2 deleted file mode 100644 index d0623775e22d6..0000000000000 --- a/src/go/types/testdata/mapB.go2 +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2019 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 orderedmap provides an ordered map, implemented as a binary tree. -package orderedmap - -// TODO(gri) fix imports for tests -import "chans" // ERROR could not import - -// Map is an ordered map. -type Map[type K, V] struct { - root *node[K, V] - compare func(K, K) int -} - -// node is the type of a node in the binary tree. -type node[type K, V] struct { - key K - val V - left, right *node[K, V] -} - -// New returns a new map. -func New[type K, V](compare func(K, K) int) *Map[K, V] { - return &Map[K, V]{compare: compare} -} - -// find looks up key in the map, and returns either a pointer -// to the node holding key, or a pointer to the location where -// such a node would go. -func (m *Map[K, V]) find(key K) **node[K, V] { - pn := &m.root - for *pn != nil { - switch cmp := m.compare(key, (*pn).key); { - case cmp < 0: - pn = &(*pn).left - case cmp > 0: - pn = &(*pn).right - default: - return pn - } - } - return pn -} - -// Insert inserts a new key/value into the map. -// If the key is already present, the value is replaced. -// Returns true if this is a new key, false if already present. -func (m *Map[K, V]) Insert(key K, val V) bool { - pn := m.find(key) - if *pn != nil { - (*pn).val = val - return false - } - *pn = &node[K, V]{key: key, val: val} - return true -} - -// Find returns the value associated with a key, or zero if not present. -// The found result reports whether the key was found. -func (m *Map[K, V]) Find(key K) (V, bool) { - pn := m.find(key) - if *pn == nil { - var zero V // see the discussion of zero values, above - return zero, false - } - return (*pn).val, true -} - -// keyValue is a pair of key and value used when iterating. -type keyValue[type K, V] struct { - key K - val V -} - -// InOrder returns an iterator that does an in-order traversal of the map. -func (m *Map[K, V]) InOrder() *Iterator[K, V] { - sender, receiver := chans.Ranger[keyValue[K, V]]() - var f func(*node[K, V]) bool - f = func(n *node[K, V]) bool { - if n == nil { - return true - } - // Stop sending values if sender.Send returns false, - // meaning that nothing is listening at the receiver end. - return f(n.left) && - sender.Send(keyValue[K, V]{n.key, n.val}) && - f(n.right) - } - go func() { - f(m.root) - sender.Close() - }() - // TODO(gri) The design draft doesn't require that we repeat - // the type parameters here. Fix the implementation. - return &Iterator[K, V]{receiver} - // return &Iterator{receiver} -} - -// Iterator is used to iterate over the map. -type Iterator[type K, V] struct { - r *chans.Receiver[keyValue[K, V]] -} - -// Next returns the next key and value pair, and a boolean indicating -// whether they are valid or whether we have reached the end. -func (it *Iterator[K, V]) Next() (K, V, bool) { - keyval, ok := it.r.Next() - if !ok { - var zerok K - var zerov V - return zerok, zerov, false - } - return keyval.key, keyval.val, true -} diff --git a/src/go/types/testdata/mtypeparams.go2 b/src/go/types/testdata/mtypeparams.go2 index 6623b2f317bb2..1d1240646239e 100644 --- a/src/go/types/testdata/mtypeparams.go2 +++ b/src/go/types/testdata/mtypeparams.go2 @@ -10,14 +10,14 @@ package p type S struct{} -func (S) m(type T)(v T) +func (S) m[T any](v T) type I interface { - m(type T)(v T) + m[T any](v T) } type J interface { - m(type T)(v T) + m[T any](v T) } var _ I = S{} @@ -27,14 +27,14 @@ type C interface{ n() } type Sc struct{} -func (Sc) m(type T C)(v T) +func (Sc) m[T C](v T) type Ic interface { - m(type T C)(v T) + m[T C](v T) } type Jc interface { - m(type T C)(v T) + m[T C](v T) } var _ Ic = Sc{} diff --git a/src/go/types/testdata/mtypeparamsB.go2 b/src/go/types/testdata/mtypeparamsB.go2 deleted file mode 100644 index 658559d71cd99..0000000000000 --- a/src/go/types/testdata/mtypeparamsB.go2 +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2020 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. - -// If types.Config.AcceptMethodTypeParams is set, -// the type checker accepts methods that have their -// own type parameter list. - -package p - -type S struct{} - -func (S) m[type T](v T) - -type I interface { - m[type T](v T) -} - -type J interface { - m[type T](v T) -} - -var _ I = S{} -var _ I = J(nil) - -type C interface{ n() } - -type Sc struct{} - -func (Sc) m[type T C](v T) - -type Ic interface { - m[type T C](v T) -} - -type Jc interface { - m[type T C](v T) -} - -var _ Ic = Sc{} -var _ Ic = Jc(nil) - -// TODO(gri) These should fail because the constraints don't match. -var _ I = Sc{} -var _ I = Jc(nil) - -var _ Ic = S{} -var _ Ic = J(nil) diff --git a/src/go/types/testdata/slices.go2 b/src/go/types/testdata/slices.go2 index 9cb92f65a79d4..2bacd1c2aa8aa 100644 --- a/src/go/types/testdata/slices.go2 +++ b/src/go/types/testdata/slices.go2 @@ -6,7 +6,7 @@ package slices // Map turns a []T1 to a []T2 using a mapping function. -func Map(type T1, T2)(s []T1, f func(T1) T2) []T2 { +func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 { r := make([]T2, len(s)) for i, v := range s { r[i] = f(v) @@ -15,7 +15,7 @@ func Map(type T1, T2)(s []T1, f func(T1) T2) []T2 { } // Reduce reduces a []T1 to a single value using a reduction function. -func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 { +func Reduce[T1, T2 any](s []T1, initializer T2, f func(T2, T1) T2) T2 { r := initializer for _, v := range s { r = f(r, v) @@ -24,7 +24,7 @@ func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 { } // Filter filters values from a slice using a filter function. -func Filter(type T)(s []T, f func(T) bool) []T { +func Filter[T any](s []T, f func(T) bool) []T { var r []T for _, v := range s { if f(v) { @@ -48,14 +48,14 @@ func limiter(x int) byte { } var input = []int{-4, 68954, 7, 44, 0, -555, 6945} -var limited1 = Map(int, byte)(input, limiter) +var limited1 = Map[int, byte](input, limiter) var limited2 = Map(input, limiter) // using type inference func reducer(x float64, y int) float64 { return x + float64(y) } -var reduced1 = Reduce(int, float64)(input, 0, reducer) +var reduced1 = Reduce[int, float64](input, 0, reducer) var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference var reduced3 = Reduce(input, 1, reducer) // using type inference @@ -63,6 +63,6 @@ func filter(x int) bool { return x&1 != 0 } -var filtered1 = Filter(int)(input, filter) +var filtered1 = Filter[int](input, filter) var filtered2 = Filter(input, filter) // using type inference diff --git a/src/go/types/testdata/slicesB.go2 b/src/go/types/testdata/slicesB.go2 deleted file mode 100644 index 23b38353b16b8..0000000000000 --- a/src/go/types/testdata/slicesB.go2 +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 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 slices implements various slice algorithms. -package slices - -// Map turns a []T1 to a []T2 using a mapping function. -func Map[type T1, T2](s []T1, f func(T1) T2) []T2 { - r := make([]T2, len(s)) - for i, v := range s { - r[i] = f(v) - } - return r -} - -// Reduce reduces a []T1 to a single value using a reduction function. -func Reduce[type T1, T2](s []T1, initializer T2, f func(T2, T1) T2) T2 { - r := initializer - for _, v := range s { - r = f(r, v) - } - return r -} - -// Filter filters values from a slice using a filter function. -func Filter[type T](s []T, f func(T) bool) []T { - var r []T - for _, v := range s { - if f(v) { - r = append(r, v) - } - } - return r -} - -// Example uses - -func limiter(x int) byte { - switch { - case x < 0: - return 0 - default: - return byte(x) - case x > 255: - return 255 - } -} - -var input = []int{-4, 68954, 7, 44, 0, -555, 6945} -var limited1 = Map[int, byte](input, limiter) -var limited2 = Map(input, limiter) // using type inference - -func reducer(x float64, y int) float64 { - return x + float64(y) -} - -var reduced1 = Reduce[int, float64](input, 0, reducer) -var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference -var reduced3 = Reduce(input, 1, reducer) // using type inference - -func filter(x int) bool { - return x&1 != 0 -} - -var filtered1 = Filter[int](input, filter) -var filtered2 = Filter(input, filter) // using type inference - diff --git a/src/go/types/testdata/syntaxB.go2 b/src/go/types/testdata/syntaxB.go2 deleted file mode 100644 index 3d4069f8a1f74..0000000000000 --- a/src/go/types/testdata/syntaxB.go2 +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2020 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 - -// any is the empty interface -func _(x any) { - x = 0 - x = true - x = "foo" - x = &x - x = func(){} - // etc. - print(0, true, "foo", &x, func(){}) -} - -func print(args... any) - -// Various options for type parameter syntax so we can play with it. - -type _[type P] int -type _[P interface{}] int -type _[P any] int -type _[P,] int -type _[P, Q] int - -func _[P](P) diff --git a/src/go/types/testdata/tinferenceB.go2 b/src/go/types/testdata/tinference.go2 similarity index 66% rename from src/go/types/testdata/tinferenceB.go2 rename to src/go/types/testdata/tinference.go2 index 14d677922b783..a53fde0a2a944 100644 --- a/src/go/types/testdata/tinferenceB.go2 +++ b/src/go/types/testdata/tinference.go2 @@ -8,28 +8,28 @@ import "strconv" type any interface{} -func f0[type A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) +func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) func _() { f := f0[string] f("a", "b", "c", "d") f0("a", "b", "c", "d") } -func f1[type A any, B interface{type A}](A, B) +func f1[A any, B interface{type A}](A, B) func _() { f := f1[int] f(int(0), int(0)) f1(int(0), int(0)) } -func f2[type A any, B interface{type []A}](A, B) +func f2[A any, B interface{type []A}](A, B) func _() { f := f2[byte] f(byte(0), []byte{}) f2(byte(0), []byte{}) } -func f3[type A any, B interface{type C}, C interface{type *A}](A, B, C) +func f3[A any, B interface{type C}, C interface{type *A}](A, B, C) func _() { f := f3[int] var x int @@ -37,7 +37,7 @@ func _() { f3(x, &x, &x) } -func f4[type A any, B interface{type []C}, C interface{type *A}](A, B, C) +func f4[A any, B interface{type []C}, C interface{type *A}](A, B, C) func _() { f := f4[int] var x int @@ -45,14 +45,14 @@ func _() { f4(x, []*int{}, &x) } -func f5[type A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A +func f5[A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A func _() { x := f5(1.2) var _ float64 = x.b var _ float64 = *x.c } -func f6[type A any, B interface{type struct{f []A}}](B) A +func f6[A any, B interface{type struct{f []A}}](B) A func _() { x := f6(struct{f []string}{}) var _ string = x @@ -60,11 +60,11 @@ func _() { // TODO(gri) Need to flag invalid recursive constraints. At the // moment these cause infinite recursions and stack overflow. -// func f7[type A interface{type B}, B interface{type A}]() +// func f7[A interface{type B}, B interface{type A}]() // More realistic examples -func Double[type S interface{ type []E }, E interface{ type int, int8, int16, int32, int64 }](s S) S { +func Double[S interface{ type []E }, E interface{ type int, int8, int16, int32, int64 }](s S) S { r := make(S, len(s)) for i, v := range s { r[i] = v + v @@ -78,12 +78,12 @@ var _ = Double(MySlice{1}) // From the draft design. -type Setter[type B] interface { +type Setter[B any] interface { Set(string) type *B } -func FromStrings[type T interface{}, PT Setter[T]](s []string) []T { +func FromStrings[T interface{}, PT Setter[T]](s []string) []T { result := make([]T, len(s)) for i, v := range s { // The type of &result[i] is *T which is in the type list diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index c10b3c2ec973e..dae78caff8191 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -7,11 +7,11 @@ package p // fun test case -type C(type P interface{m()}) P +type C[P interface{m()}] P -func (r C(P)) m() { r.m() } +func (r C[P]) m() { r.m() } -func f(type T interface{m(); n()})(x T) { - y := C(T)(x) +func f[T interface{m(); n()}](x T) { + y := C[T](x) y.m() } diff --git a/src/go/types/testdata/tmpB.go2 b/src/go/types/testdata/tmpB.go2 deleted file mode 100644 index cf07c7bd13e22..0000000000000 --- a/src/go/types/testdata/tmpB.go2 +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2020 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. - -// This file is meant as "dumping ground" for debugging code. - -package p - -// fun test case -type C[type P interface{m()}] P - -func (r C[P]) m() { r.m() } - -func f[type T interface{m(); n()}](x T) { - y := C[T](x) - y.m() -} diff --git a/src/go/types/testdata/todos.go2 b/src/go/types/testdata/todos.go2 index e617eaec96b14..09e9b4c48a918 100644 --- a/src/go/types/testdata/todos.go2 +++ b/src/go/types/testdata/todos.go2 @@ -8,14 +8,15 @@ package p -// Composite literals that require parentheses around their types. -// Should investigate if it makes sense to be smarter when parsing -// at the cost of more complex rules. -type T1(type P) struct{} -type T2(type P, Q) struct{} +// When using []'s instead of ()'s for type parameters +// we don't need extra parentheses for some composite +// literal types. +type T1[P any] struct{} +type T2[P, Q any] struct{} func _() { - _ = []T1 /* ERROR instantiation */ (int){} // this doesn't work - _ = [](T1(int)){} // this works - _ = [](T2(int, string)){} // T2(int, float) cannot be a conversion - should not need ()'s + _ = []T1[int]{} // ok if we use []'s + _ = [](T1[int]){} + _ = []T2[int, string]{} // ok if we use []'s + _ = [](T2[int, string]){} } diff --git a/src/go/types/testdata/todosB.go2 b/src/go/types/testdata/todosB.go2 deleted file mode 100644 index 9c53116e48b40..0000000000000 --- a/src/go/types/testdata/todosB.go2 +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2020 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. - -// This file is meant as "dumping ground" for tests -// of not yet implemented features. It will grow and -// shrink over time. - -package p - -// When using []'s instead of ()'s for type parameters -// we don't need extra parentheses for some composite -// literal types. -type T1[type P] struct{} -type T2[type P, Q] struct{} - -func _() { - _ = []T1[int]{} // ok if we use []'s - _ = [](T1[int]){} - _ = []T2[int, string]{} // ok if we use []'s - _ = [](T2[int, string]){} -} diff --git a/src/go/types/testdata/typeargs.go2 b/src/go/types/testdata/typeargs.go2 deleted file mode 100644 index 0f63f552b6ede..0000000000000 --- a/src/go/types/testdata/typeargs.go2 +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2020 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. - -// Test instantiations of type parameters with pointer designation. -// -// When we have a type parameter with a pointer designation -// -// (type *T Constraint) -// -// we are saying that *T must satisfy Constraint. One way of emulating -// this without pointer designation is to translate the above type -// parameter list to -// -// (type PT interface{ Constraint; type *T }, T interface{}) -// -// with two type parameters, where PT has the additional constraint -// that it must be a *T. - -package p - -func e(type T)() { - e(T)() - e(*T)() - ep(T)() - ep(*T)() -} - -func ep(type *T)() { - e(T)() - e(*T)() - ep(T)() - ep(*T)() -} - -func et(type T interface{type int})() { - et(T)() - et(* /* ERROR \*T not found in int */ T)() - // etp(T /* ERROR \*T not found in int */ )() // TODO(gri) fix this - etp(* /* ERROR \*T not found in int */ T)() -} - -func etp(type *T interface{type int})() { - // et(T /* ERROR T not found in int */ )() // TODO(gri) Fix this - et(* /* ERROR \*T not found in int */ T)() - etp(T)() - etp(* /* ERROR \*T not found in int */ T)() -} - -func f(type T interface { m() })() { - // Use functions to produce non-addressable values of the respective types. - func() (_ T) { return }().m() // method set of T is { m } (per declaration) - func() (_ *T) { return }().m() // method set of *T is { m } (implicit deref *T to get T value) - - var x T - x.m() // method set of T is { m } (per declaration) - var xp *T - xp.m() // method set of *T is { m } (implicit deref *T to get T value) - - f(T)() // method set of T is { m } (per declaration) - f(* /* ERROR \*T has no methods */ T)() // method set of *T is {} - fp(T /* ERROR pointer designation mismatch */ )() - fp(* /* ERROR \*T has no methods */ T)() // method set of *T is {} -} - -func fp(type *T interface { m() })() { - // Use functions to produce non-addressable values of the respective types. - func() (_ T) { return }().m /* ERROR cannot call pointer method m */ () // method set of T is {}, receiver is not addressable - func() (_ *T) { return }().m() // method set of *T is { m } - - var x T - x.m() // method set of *T is { m } (x is addressable) - var xp *T - xp.m() // method set of *T is { m } (per declaration) - - f(T /* ERROR pointer designation mismatch */ )() - f(* /* ERROR \*T has no methods */ T)() // method set of **T is {} - fp(T)() // method set of *T is { m } - fp(* /* ERROR \*T has no methods */ T)() // method set of **T is {} -} - -type S struct{} -func (S) m() - -type Sp struct{} -func (*Sp) m() - -func _() { - S{}.m() // method set of S is { m } (per declaration) - Sp{}.m /* ERROR cannot call pointer method m */ () // method set of Sp is {} - (&S{}).m() // method set of *S is { m } (deref *S value to get S value) - (&Sp{}).m() // method set of *Sp is { m } (per declaration) - - var s S - s.m() // method set of S is { m } (per declaration) - var sp Sp - sp.m() // method set of &Sp is { m } (sp is addressable) - var ps *S - ps.m() // method set of *S is { m } (deref *S value to get S value) - var psp *Sp - psp.m() // method set of *Sp is { m } (per declaration) - - f(S)() // method set of S is { m } - f(Sp /* ERROR missing method m */ )() // method set of Sp is {} - f(*S)() // method set of *S is { m } - f(*Sp)() // method set of *Sp is { m } - - fp(S)() // method set of *S is { m } - fp(Sp)() // method set of *Sp is { m } - fp(* /* ERROR missing method m */ S)() // method set of **S is {} - fp(* /* ERROR missing method m */ Sp)() // method set of **Sp is {} -} - -// Example from design doc - -type Setter interface { - Set(string) -} - -func Strings(type T Setter)(s []string) []T { - result := make([]T, len(s)) - for i, v := range s { - result[i].Set(v) - } - return result -} - -type Settable int - -func (p *Settable) Set(s string) { - *p = 0 -} - -func F() { - Strings(Settable /* ERROR missing method Set */ )([]string{"1"}) -} diff --git a/src/go/types/testdata/typeargsB.go2 b/src/go/types/testdata/typeargsB.go2 deleted file mode 100644 index d966aed1eee08..0000000000000 --- a/src/go/types/testdata/typeargsB.go2 +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2020 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. - -// Test instantiations of type parameters with pointer designation. -// -// When we have a type parameter with a pointer designation -// -// [type *T Constraint] -// -// we are saying that *T must satisfy Constraint. One way of emulating -// this without pointer designation is to translate the above type -// parameter list to -// -// [type PT interface{ Constraint; type *T }, T interface{}] -// -// with two type parameters, where PT has the additional constraint -// that it must be a *T. - -package p - -func e[type T]() { - e[T]() - e[*T]() - ep[T]() - ep[*T]() -} - -func ep[type *T]() { - e[T]() - e[*T]() - ep[T]() - ep[*T]() -} - -func et[type T interface{type int}]() { - et(T)() - et(* /* ERROR \*T not found in int */ T)() - // etp(T /* ERROR \*T not found in int */ )() // TODO(gri) fix this - etp(* /* ERROR \*T not found in int */ T)() -} - -func etp[type *T interface{type int}]() { - // et(T /* ERROR T not found in int */ )() // TODO(gri) Fix this - et(* /* ERROR \*T not found in int */ T)() - etp(T)() - etp(* /* ERROR \*T not found in int */ T)() -} - -func f[type T interface { m() }]() { - // Use functions to produce non-addressable values of the respective types. - func() (_ T) { return }().m() // method set of T is { m } (per declaration) - func() (_ *T) { return }().m() // method set of *T is { m } (implicit deref *T to get T value) - - var x T - x.m() // method set of T is { m } (per declaration) - var xp *T - xp.m() // method set of *T is { m } (implicit deref *T to get T value) - - f(T)() // method set of T is { m } (per declaration) - f(* /* ERROR \*T has no methods */ T)() // method set of *T is {} - fp(T /* ERROR pointer designation mismatch */ )() - fp(* /* ERROR \*T has no methods */ T)() // method set of *T is {} -} - -func fp[type *T interface { m() }]() { - // Use functions to produce non-addressable values of the respective types. - func() (_ T) { return }().m /* ERROR cannot call pointer method m */ () // method set of T is {}, receiver is not addressable - func() (_ *T) { return }().m() // method set of *T is { m } - - var x T - x.m() // method set of *T is { m } (x is addressable) - var xp *T - xp.m() // method set of *T is { m } (per declaration) - - f(T /* ERROR pointer designation mismatch */ )() - f(* /* ERROR \*T has no methods */ T)() // method set of **T is {} - fp(T)() // method set of *T is { m } - fp(* /* ERROR \*T has no methods */ T)() // method set of **T is {} -} - -type S struct{} -func (S) m() - -type Sp struct{} -func (*Sp) m() - -func _() { - S{}.m() // method set of S is { m } (per declaration) - Sp{}.m /* ERROR cannot call pointer method m */ () // method set of Sp is {} - (&S{}).m() // method set of *S is { m } (deref *S value to get S value) - (&Sp{}).m() // method set of *Sp is { m } (per declaration) - - var s S - s.m() // method set of S is { m } (per declaration) - var sp Sp - sp.m() // method set of &Sp is { m } (sp is addressable) - var ps *S - ps.m() // method set of *S is { m } (deref *S value to get S value) - var psp *Sp - psp.m() // method set of *Sp is { m } (per declaration) - - f(S)() // method set of S is { m } - f(Sp /* ERROR missing method m */ )() // method set of Sp is {} - f(*S)() // method set of *S is { m } - f(*Sp)() // method set of *Sp is { m } - - fp(S)() // method set of *S is { m } - fp(Sp)() // method set of *Sp is { m } - fp(* /* ERROR missing method m */ S)() // method set of **S is {} - fp(* /* ERROR missing method m */ Sp)() // method set of **Sp is {} -} - -// Example from design doc - -type Setter interface { - Set(string) -} - -func Strings[type T Setter](s []string) []T { - result := make([]T, len(s)) - for i, v := range s { - result[i].Set(v) - } - return result -} - -type Settable int - -func (p *Settable) Set(s string) { - *p = 0 -} - -func F() { - Strings[Settable /* ERROR missing method Set */ ]([]string{"1"}) -} diff --git a/src/go/types/testdata/typeinst.go2 b/src/go/types/testdata/typeinst.go2 index 6ef51929c3584..1bf4a636cbfe5 100644 --- a/src/go/types/testdata/typeinst.go2 +++ b/src/go/types/testdata/typeinst.go2 @@ -8,44 +8,44 @@ type myInt int // Parameterized type declarations -type T1(type P) P +type T1[P any] P -type T2(type P) struct { +type T2[P any] struct { f P g int // int should still be in scope chain } -type List(type P) []P +type List[P any] []P // Alias type declarations cannot have type parameters. -type A1( /* ERROR cannot be parameterized */ type P) = P /* ERROR undeclared */ +type A1[ /* ERROR cannot be parameterized */ P any] = P /* ERROR undeclared */ // Parameterized type instantiations var x int -type _ x /* ERROR not a type */ (int) +type _ x /* ERROR not a type */ [int] -type _ int /* ERROR not a generic type */ () -type _ myInt /* ERROR not a generic type */ () +type _ int /* ERROR not a generic type */ [] +type _ myInt /* ERROR not a generic type */ [] // TODO(gri) better error messages -type _ T1 /* ERROR got 0 arguments but 1 type parameters */ () -type _ T1(x /* ERROR not a type */ ) -type _ T1 /* ERROR got 2 arguments but 1 type parameters */ (int, float32) +type _ T1 /* ERROR got 0 arguments but 1 type parameters */ [] +type _ T1[x /* ERROR not a type */ ] +type _ T1 /* ERROR got 2 arguments but 1 type parameters */ [int, float32] -var _ T2(int) = T2(int){} +var _ T2[int] = T2[int]{} -var _ List(int) = []int{1, 2, 3} -var _ List([]int) = [][]int{{1, 2, 3}} -var _ List(List(List(int))) +var _ List[int] = []int{1, 2, 3} +var _ List[[]int] = [][]int{{1, 2, 3}} +var _ List[List[List[int]]] // Parameterized types containing parameterized types -type T3(type P) List(P) +type T3[P any] List[P] -var _ T3(int) = T3(int)(List(int){1, 2, 3}) +var _ T3[int] = T3[int](List[int]{1, 2, 3}) // Self-recursive generic types are not permitted -type self1(type P) self1 /* ERROR illegal cycle */ (P) -type self2(type P) *self2(P) // this is ok +type self1[P any] self1 /* ERROR illegal cycle */ [P] +type self2[P any] *self2[P] // this is ok diff --git a/src/go/types/testdata/typeinst2.go2 b/src/go/types/testdata/typeinst2.go2 index 204a18cdc426f..e8ee3db012189 100644 --- a/src/go/types/testdata/typeinst2.go2 +++ b/src/go/types/testdata/typeinst2.go2 @@ -4,53 +4,53 @@ package p -type List(type E) []E -var _ List(List(List(int))) -var _ List(List(List(int))) = [](List(List(int))){} +type List[E any] []E +var _ List[List[List[int]]] +var _ List[List[List[int]]] = []List[List[int]]{} type ( - T1(type P1) struct { - f1 T2(P1, float32) + T1[P1 any] struct { + f1 T2[P1, float32] } - T2(type P2, P3) struct { + T2[P2, P3 any] struct { f2 P2 f3 P3 } ) func _() { - var x1 T1(int) - var x2 T2(int, float32) + var x1 T1[int] + var x2 T2[int, float32] x1.f1.f2 = 0 x1.f1 = x2 } -type T3(type P) T1(T2(P, P)) +type T3[P any] T1[T2[P, P]] func _() { - var x1 T3(int) - var x2 T2(int, int) + var x1 T3[int] + var x2 T2[int, int] x1.f1.f2 = x2 } -func f(type P) (x P) List(P) { - return List(P){x} +func f[P any] (x P) List[P] { + return List[P]{x} } var ( _ []int = f(0) - _ []float32 = f(float32)(10) - _ List(complex128) = f(1i) - _ [](List(int)) = f(List(int){}) - _ List(List(int)) = [](List(int)){} - _ = [](List(int)){} + _ []float32 = f[float32](10) + _ List[complex128] = f(1i) + _ []List[int] = f(List[int]{}) + _ List[List[int]] = []List[int]{} + _ = []List[int]{} ) // Parameterized types with methods -func (l List(E)) Head() (_ E, _ bool) { +func (l List[E]) Head() (_ E, _ bool) { if len(l) > 0 { return l[0], true } @@ -59,63 +59,63 @@ func (l List(E)) Head() (_ E, _ bool) { // A test case for instantiating types with other types (extracted from map.go2) -type Pair(type K) struct { +type Pair[K any] struct { key K } -type Receiver(type T) struct { +type Receiver[T any] struct { values T } -type Iterator(type K) struct { - r Receiver(Pair(K)) +type Iterator[K any] struct { + r Receiver[Pair[K]] } -func Values (type T) (r Receiver(T)) T { +func Values [T any] (r Receiver[T]) T { return r.values } -func (it Iterator(K)) Next() K { - return Values(Pair(K))(it.r).key +func (it Iterator[K]) Next() K { + return Values[Pair[K]](it.r).key } // A more complex test case testing type bounds (extracted from linalg.go2 and reduced to essence) -type NumericAbs(type T) interface { +type NumericAbs[T any] interface { Abs() T } -func AbsDifference(type T NumericAbs)(x T) +func AbsDifference[T NumericAbs](x T) -type OrderedAbs(type T) T +type OrderedAbs[T any] T -func (a OrderedAbs(T)) Abs() OrderedAbs(T) +func (a OrderedAbs[T]) Abs() OrderedAbs[T] -func OrderedAbsDifference(type T)(x T) { - AbsDifference(OrderedAbs(T)(x)) +func OrderedAbsDifference[T any](x T) { + AbsDifference(OrderedAbs[T](x)) } // same code, reduced to essence -func g(type P interface{ m() P })(x P) +func g[P interface{ m() P }](x P) -type T4(type P) P +type T4[P any] P -func (_ T4(P)) m() T4(P) +func (_ T4[P]) m() T4[P] -func _(type Q)(x Q) { - g(T4(Q)(x)) +func _[Q any](x Q) { + g(T4[Q](x)) } // Another test case that caused problems in the past -type T5(type _ interface { a() }, _ interface{}) struct{} +type T5[_ interface { a() }, _ interface{}] struct{} -type A(type P) struct{ x P } +type A[P any] struct{ x P } -func (_ A(P)) a() {} +func (_ A[P]) a() {} -var _ T5(A(int), int) +var _ T5[A[int], int] // Invoking methods with parameterized receiver types uses // type inference to determine the actual type arguments matching @@ -126,22 +126,22 @@ var _ T5(A(int), int) // of the actual receiver and the method's receiver type. // The following code tests this mechanism. -type R1(type A) struct{} -func (_ R1(A)) vm() -func (_ *R1(A)) pm() +type R1[A any] struct{} +func (_ R1[A]) vm() +func (_ *R1[A]) pm() -func _(type T)(r R1(T), p *R1(T)) { +func _[T any](r R1[T], p *R1[T]) { r.vm() r.pm() p.vm() p.pm() } -type R2(type A, B) struct{} -func (_ R2(A, B)) vm() -func (_ *R2(A, B)) pm() +type R2[A, B any] struct{} +func (_ R2[A, B]) vm() +func (_ *R2[A, B]) pm() -func _(type T)(r R2(T, int), p *R2(string, T)) { +func _[T any](r R2[T, int], p *R2[string, T]) { r.vm() r.pm() p.vm() @@ -175,12 +175,12 @@ type _ interface { // Interface type lists can contain any type, incl. *Named types. // Verify that we use the underlying type to compute the operational type. type MyInt int -func add1(type T interface{type MyInt})(x T) T { +func add1[T interface{type MyInt}](x T) T { return x + 1 } type MyString string -func double(type T interface{type MyInt, MyString})(x T) T { +func double[T interface{type MyInt, MyString}](x T) T { return x + x } @@ -204,22 +204,22 @@ type I0 interface { E0 } -func f0(type T I0)() -var _ = f0(int) -var _ = f0(bool) -var _ = f0(string) -var _ = f0(float64 /* ERROR does not satisfy I0 */ ) +func f0[T I0]() +var _ = f0[int] +var _ = f0[bool] +var _ = f0[string] +var _ = f0[float64 /* ERROR does not satisfy I0 */ ] type I01 interface { E0 E1 } -func f01(type T I01)() -var _ = f01(int) -var _ = f01(bool /* ERROR does not satisfy I0 */ ) -var _ = f01(string) -var _ = f01(float64 /* ERROR does not satisfy I0 */ ) +func f01[T I01]() +var _ = f01[int] +var _ = f01[bool /* ERROR does not satisfy I0 */ ] +var _ = f01[string] +var _ = f01[float64 /* ERROR does not satisfy I0 */ ] type I012 interface { E0 @@ -227,30 +227,30 @@ type I012 interface { E2 } -func f012(type T I012)() -var _ = f012(int /* ERROR does not satisfy I012 */ ) -var _ = f012(bool /* ERROR does not satisfy I012 */ ) -var _ = f012(string /* ERROR does not satisfy I012 */ ) -var _ = f012(float64 /* ERROR does not satisfy I012 */ ) +func f012[T I012]() +var _ = f012[int /* ERROR does not satisfy I012 */ ] +var _ = f012[bool /* ERROR does not satisfy I012 */ ] +var _ = f012[string /* ERROR does not satisfy I012 */ ] +var _ = f012[float64 /* ERROR does not satisfy I012 */ ] type I12 interface { E1 E2 } -func f12(type T I12)() -var _ = f12(int /* ERROR does not satisfy I12 */ ) -var _ = f12(bool /* ERROR does not satisfy I12 */ ) -var _ = f12(string /* ERROR does not satisfy I12 */ ) -var _ = f12(float64) +func f12[T I12]() +var _ = f12[int /* ERROR does not satisfy I12 */ ] +var _ = f12[bool /* ERROR does not satisfy I12 */ ] +var _ = f12[string /* ERROR does not satisfy I12 */ ] +var _ = f12[float64] type I0_ interface { E0 type int } -func f0_(type T I0_)() -var _ = f0_(int) -var _ = f0_(bool /* ERROR does not satisfy I0_ */ ) -var _ = f0_(string /* ERROR does not satisfy I0_ */ ) -var _ = f0_(float64 /* ERROR does not satisfy I0_ */ ) +func f0_[T I0_]() +var _ = f0_[int] +var _ = f0_[bool /* ERROR does not satisfy I0_ */ ] +var _ = f0_[string /* ERROR does not satisfy I0_ */ ] +var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ] diff --git a/src/go/types/testdata/typeinst2B.go2 b/src/go/types/testdata/typeinst2B.go2 deleted file mode 100644 index ba4b33bd2a828..0000000000000 --- a/src/go/types/testdata/typeinst2B.go2 +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2019 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 List[type E] []E -var _ List[List[List[int]]] -var _ List[List[List[int]]] = []List[List[int]]{} - -type ( - T1[type P1] struct { - f1 T2[P1, float32] - } - - T2[type P2, P3] struct { - f2 P2 - f3 P3 - } -) - -func _() { - var x1 T1[int] - var x2 T2[int, float32] - - x1.f1.f2 = 0 - x1.f1 = x2 -} - -type T3[type P] T1[T2[P, P]] - -func _() { - var x1 T3[int] - var x2 T2[int, int] - x1.f1.f2 = x2 -} - -func f[type P] (x P) List[P] { - return List[P]{x} -} - -var ( - _ []int = f(0) - _ []float32 = f[float32](10) - _ List[complex128] = f(1i) - _ []List[int] = f(List[int]{}) - _ List[List[int]] = []List[int]{} - _ = []List[int]{} -) - -// Parameterized types with methods - -func (l List[E]) Head() (_ E, _ bool) { - if len(l) > 0 { - return l[0], true - } - return -} - -// A test case for instantiating types with other types (extracted from map.go2) - -type Pair[type K] struct { - key K -} - -type Receiver[type T] struct { - values T -} - -type Iterator[type K] struct { - r Receiver[Pair[K]] -} - -func Values [type T] (r Receiver[T]) T { - return r.values -} - -func (it Iterator[K]) Next() K { - return Values[Pair[K]](it.r).key -} - -// A more complex test case testing type bounds (extracted from linalg.go2 and reduced to essence) - -type NumericAbs[type T] interface { - Abs() T -} - -func AbsDifference[type T NumericAbs](x T) - -type OrderedAbs[type T] T - -func (a OrderedAbs[T]) Abs() OrderedAbs[T] - -func OrderedAbsDifference[type T](x T) { - AbsDifference(OrderedAbs[T](x)) -} - -// same code, reduced to essence - -func g[type P interface{ m() P }](x P) - -type T4[type P] P - -func (_ T4[P]) m() T4[P] - -func _[type Q](x Q) { - g(T4[Q](x)) -} - -// Another test case that caused problems in the past - -type T5[type _ interface { a() }, _ interface{}] struct{} - -type A[type P] struct{ x P } - -func (_ A[P]) a() {} - -var _ T5[A[int], int] - -// Invoking methods with parameterized receiver types uses -// type inference to determine the actual type arguments matching -// the receiver type parameters from the actual receiver argument. -// Go does implicit address-taking and dereferenciation depending -// on the actual receiver and the method's receiver type. To make -// type inference work, the type-checker matches "pointer-ness" -// of the actual receiver and the method's receiver type. -// The following code tests this mechanism. - -type R1[type A] struct{} -func (_ R1[A]) vm() -func (_ *R1[A]) pm() - -func _[type T](r R1[T], p *R1[T]) { - r.vm() - r.pm() - p.vm() - p.pm() -} - -type R2[type A, B] struct{} -func (_ R2[A, B]) vm() -func (_ *R2[A, B]) pm() - -func _[type T](r R2[T, int], p *R2[string, T]) { - r.vm() - r.pm() - p.vm() - p.pm() -} - -// An interface can (explicitly) declare at most one type list. -type _ interface { - m0() - type int, string, bool - type /* ERROR multiple type lists */ float32, float64 - m1() - m2() - type /* ERROR multiple type lists */ complex64, complex128 - type /* ERROR multiple type lists */ rune -} - -// Interface type lists may contain each type at most once. -// (If there are multiple lists, we assume the author intended -// for them to be all in a single list, and we report the error -// as well.) -type _ interface { - type int, int /* ERROR duplicate type int */ - type /* ERROR multiple type lists */ int /* ERROR duplicate type int */ -} - -type _ interface { - type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int} -} - -// Interface type lists can contain any type, incl. *Named types. -// Verify that we use the underlying type to compute the operational type. -type MyInt int -func add1[type T interface{type MyInt}](x T) T { - return x + 1 -} - -type MyString string -func double[type T interface{type MyInt, MyString}](x T) T { - return x + x -} - -// Embedding of interfaces with type lists leads to interfaces -// with type lists that are the intersection of the embedded -// type lists. - -type E0 interface { - type int, bool, string -} - -type E1 interface { - type int, float64, string -} - -type E2 interface { - type float64 -} - -type I0 interface { - E0 -} - -func f0[type T I0]() -var _ = f0[int] -var _ = f0[bool] -var _ = f0[string] -var _ = f0[float64 /* ERROR does not satisfy I0 */ ] - -type I01 interface { - E0 - E1 -} - -func f01[type T I01]() -var _ = f01[int] -var _ = f01[bool /* ERROR does not satisfy I0 */ ] -var _ = f01[string] -var _ = f01[float64 /* ERROR does not satisfy I0 */ ] - -type I012 interface { - E0 - E1 - E2 -} - -func f012[type T I012]() -var _ = f012[int /* ERROR does not satisfy I012 */ ] -var _ = f012[bool /* ERROR does not satisfy I012 */ ] -var _ = f012[string /* ERROR does not satisfy I012 */ ] -var _ = f012[float64 /* ERROR does not satisfy I012 */ ] - -type I12 interface { - E1 - E2 -} - -func f12[type T I12]() -var _ = f12[int /* ERROR does not satisfy I12 */ ] -var _ = f12[bool /* ERROR does not satisfy I12 */ ] -var _ = f12[string /* ERROR does not satisfy I12 */ ] -var _ = f12[float64] - -type I0_ interface { - E0 - type int -} - -func f0_[type T I0_]() -var _ = f0_[int] -var _ = f0_[bool /* ERROR does not satisfy I0_ */ ] -var _ = f0_[string /* ERROR does not satisfy I0_ */ ] -var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ] diff --git a/src/go/types/testdata/typeinstB.go2 b/src/go/types/testdata/typeinstB.go2 deleted file mode 100644 index 7245250af0b8a..0000000000000 --- a/src/go/types/testdata/typeinstB.go2 +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 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 myInt int - -// Parameterized type declarations - -type T1[type P] P - -type T2[type P] struct { - f P - g int // int should still be in scope chain -} - -type List[type P] []P - -// Alias type declarations cannot have type parameters. -type A1[ /* ERROR cannot be parameterized */ type P] = P /* ERROR undeclared */ - -// Parameterized type instantiations - -var x int -type _ x /* ERROR not a type */ [int] - -type _ int /* ERROR not a generic type */ [] -type _ myInt /* ERROR not a generic type */ [] - -// TODO(gri) better error messages -type _ T1 /* ERROR got 0 arguments but 1 type parameters */ [] -type _ T1[x /* ERROR not a type */ ] -type _ T1 /* ERROR got 2 arguments but 1 type parameters */ [int, float32] - -var _ T2[int] = T2[int]{} - -var _ List[int] = []int{1, 2, 3} -var _ List[[]int] = [][]int{{1, 2, 3}} -var _ List[List[List[int]]] - -// Parameterized types containing parameterized types - -type T3[type P] List[P] - -var _ T3[int] = T3[int](List[int]{1, 2, 3}) - -// Self-recursive generic types are not permitted - -type self1[type P] self1 /* ERROR illegal cycle */ [P] -type self2[type P] *self2[P] // this is ok diff --git a/src/go/types/testdata/typeparams.go2 b/src/go/types/testdata/typeparams.go2 index b3df910d156e7..4b35b71527234 100644 --- a/src/go/types/testdata/typeparams.go2 +++ b/src/go/types/testdata/typeparams.go2 @@ -6,13 +6,13 @@ package p // import "io" // for type assertion tests -func identity(type T)(x T) T { return x } +func identity[T any](x T) T { return x } -func _(type)(x int) int -func _(type T)(T /* ERROR redeclared */ T)() -func _(type T, T /* ERROR redeclared */ )() +func _[any](x int) int +func _[T any](T /* ERROR redeclared */ T)() +func _[T, T /* ERROR redeclared */ any]() -func reverse(type T)(list []T) []T { +func reverse[T any](list []T) []T { rlist := make([]T, len(list)) i := len(list) for _, x := range list { @@ -23,113 +23,109 @@ func reverse(type T)(list []T) []T { } var _ = reverse /* ERROR cannot use generic function reverse */ -var _ = reverse(int, float32 /* ERROR got 2 type arguments */ ) ([]int{1, 2, 3}) -var _ = reverse(int)([ /* ERROR cannot use */ ]float32{1, 2, 3}) -var f = reverse(chan int) +var _ = reverse[int, float32 /* ERROR got 2 type arguments */ ] ([]int{1, 2, 3}) +var _ = reverse[int]([ /* ERROR cannot use */ ]float32{1, 2, 3}) +var f = reverse[chan int] var _ = f(0 /* ERROR cannot convert 0 .* to \[\]chan int */ ) -func swap(type A, B)(a A, b B) (B, A) { return b, a } +func swap[A, B any](a A, b B) (B, A) { return b, a } -var _ = swap /* ERROR single value is expected */ (int, float32)(1, 2) -var f32, i = swap(int, float32)(swap(float32, int)(1, 2)) +var _ = swap /* ERROR single value is expected */ [int, float32](1, 2) +var f32, i = swap[int, float32](swap(float32, int)(1, 2)) var _ float32 = f32 var _ int = i -func swapswap(type A, B)(a A, b B) (A, B) { - return swap(B, A)(b, a) +func swapswap[A, B any](a A, b B) (A, B) { + return swap[B, A](b, a) } -type F(type A, B) func(A, B) (B, A) +type F[A, B any] func(A, B) (B, A) -func min(type T interface{ type int })(x, y T) T { +func min[T interface{ type int }](x, y T) T { if x < y { return x } return y } -func _(type T interface{type int, float32})(x, y T) bool { return x < y } -func _(type T)(x, y T) bool { return x /* ERROR cannot compare */ < y } -func _(type T interface{type int, float32, bool})(x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T interface{type int, float32}](x, y T) bool { return x < y } +func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } -func _(type T C1)(x, y T) bool { return x /* ERROR cannot compare */ < y } -func _(type T C2)(x, y T) bool { return x < y } +func _[T C1](x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T C2](x, y T) bool { return x < y } -type C1(type T) interface{} -type C2(type T) interface{ type int, float32 } +type C1[T any] interface{} +type C2[T any] interface{ type int, float32 } -func new(type T)() *T { +func new[T any]() *T { var x T return &x } var _ = new /* ERROR cannot use generic function new */ -var _ *int = new(int)() +var _ *int = new[int]() -func _(type T)(map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable +func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable -func f1(type T1)(struct{T1}) int +func f1[T1 any](struct{T1}) int var _ = f1(int)(struct{T1}{}) type T1 = int -func f2(type t1)(struct{t1; x float32}) int +func f2[t1 any](struct{t1; x float32}) int var _ = f2(t1)(struct{t1; x float32}{}) type t1 = int -func f3(type A, B, C)(A, struct{x B}, func(A, struct{x B}, *C)) int +func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int -var _ = f3(int, rune, bool)(1, struct{x rune}{}, nil) - -// type parameters with pointer marking -func _(type *P, Q)() -func _(type *P)(x P) +var _ = f3[int, rune, bool](1, struct{x rune}{}, nil) // indexing -func _(type T) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _(type T interface{ type int }) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _(type T interface{ type string }) (x T, i int) { _ = x[i] } -func _(type T interface{ type []int }) (x T, i int) { _ = x[i] } -func _(type T interface{ type [10]int, *[20]int, map[string]int }) (x T, i int) { _ = x[i] } -func _(type T interface{ type string, []byte }) (x T, i int) { _ = x[i] } -func _(type T interface{ type []int, [1]rune }) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _(type T interface{ type string, []rune }) (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ type string }] (x T, i int) { _ = x[i] } +func _[T interface{ type []int }] (x T, i int) { _ = x[i] } +func _[T interface{ type [10]int, *[20]int, map[string]int }] (x T, i int) { _ = x[i] } +func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] } +func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } // slicing // TODO(gri) implement this -func _(type T interface{ type string }) (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } +func _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } // len/cap built-ins -func _(type T)(x T) { _ = len(x /* ERROR invalid argument */ ) } -func _(type T interface{ type int })(x T) { _ = len(x /* ERROR invalid argument */ ) } -func _(type T interface{ type string, []byte, int })(x T) { _ = len(x /* ERROR invalid argument */ ) } -func _(type T interface{ type string })(x T) { _ = len(x) } -func _(type T interface{ type [10]int })(x T) { _ = len(x) } -func _(type T interface{ type []byte })(x T) { _ = len(x) } -func _(type T interface{ type map[int]int })(x T) { _ = len(x) } -func _(type T interface{ type chan int })(x T) { _ = len(x) } -func _(type T interface{ type string, []byte, chan int })(x T) { _ = len(x) } - -func _(type T)(x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _(type T interface{ type int })(x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _(type T interface{ type string, []byte, int })(x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _(type T interface{ type string })(x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _(type T interface{ type [10]int })(x T) { _ = cap(x) } -func _(type T interface{ type []byte })(x T) { _ = cap(x) } -func _(type T interface{ type map[int]int })(x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _(type T interface{ type chan int })(x T) { _ = cap(x) } -func _(type T interface{ type []byte, chan int })(x T) { _ = cap(x) } +func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ type string }](x T) { _ = len(x) } +func _[T interface{ type [10]int }](x T) { _ = len(x) } +func _[T interface{ type []byte }](x T) { _ = len(x) } +func _[T interface{ type map[int]int }](x T) { _ = len(x) } +func _[T interface{ type chan int }](x T) { _ = len(x) } +func _[T interface{ type string, []byte, chan int }](x T) { _ = len(x) } + +func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type [10]int }](x T) { _ = cap(x) } +func _[T interface{ type []byte }](x T) { _ = cap(x) } +func _[T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type chan int }](x T) { _ = cap(x) } +func _[T interface{ type []byte, chan int }](x T) { _ = cap(x) } // range iteration -func _(type T interface{})(x T) { +func _[T interface{}](x T) { for range x /* ERROR cannot range */ {} } -func _(type T interface{ type string, []string })(x T) { +func _[T interface{ type string, []string }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } @@ -141,23 +137,23 @@ func _(type T interface{ type string, []string })(x T) { } -func _(type T interface{ type string, []rune, map[int]rune })(x T) { +func _[T interface{ type string, []rune, map[int]rune }](x T) { for _, e := range x { _ = e } for i, e := range x { _ = i; _ = e } } -func _(type T interface{ type string, []rune, map[string]rune })(x T) { +func _[T interface{ type string, []rune, map[string]rune }](x T) { for _, e := range x { _ = e } for i, e := range x /* ERROR must have the same key type */ { _ = e } } -func _(type T interface{ type string, chan int })(x T) { +func _[T interface{ type string, chan int }](x T) { for range x {} for i := range x { _ = i } for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value } -func _(type T interface{ type string, chan<-int })(x T) { +func _[T interface{ type string, chan<-int }](x T) { for i := range x /* ERROR send-only channel */ { _ = i } } @@ -165,28 +161,28 @@ func _(type T interface{ type string, chan<-int })(x T) { var _ = new() /* ERROR cannot infer T */ -func f4(type A, B, C)(A, B) C +func f4[A, B, C any](A, B) C var _ = f4(1, 2) /* ERROR cannot infer C */ -var _ = f4(int, float32, complex128)(1, 2) +var _ = f4[int, float32, complex128](1, 2) -func f5(type A, B, C)(A, []*B, struct{f []C}) int +func f5[A, B, C any](A, []*B, struct{f []C}) int -var _ = f5(int, float32, complex128)(0, nil, struct{f []complex128}{}) +var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{}) var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer -var _ = f5(0, []*float32{new(float32)()}, struct{f []complex128}{}) +var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{}) -func f6(type A)(A, []A) int +func f6[A any](A, []A) int var _ = f6(0, nil) -func f6nil(type A)(A) int +func f6nil[A any](A) int var _ = f6nil(nil) // ERROR cannot infer // type inference with variadic functions -func f7(type T)(...T) T +func f7[T any](...T) T var _ int = f7() /* ERROR cannot infer T */ var _ int = f7(1) @@ -194,12 +190,12 @@ var _ int = f7(1, 2) var _ int = f7([]int{}...) var _ int = f7 /* ERROR cannot use */ ([]float64{}...) var _ float64 = f7([]float64{}...) -var _ = f7(float64)(1, 2.3) +var _ = f7[float64](1, 2.3) var _ = f7(float64(1), 2.3) var _ = f7(1, 2.3 /* ERROR does not match */ ) var _ = f7(1.2, 3 /* ERROR does not match */ ) -func f8(type A, B)(A, B, ...B) int +func f8[A, B any](A, B, ...B) int var _ = f8(1) /* ERROR not enough arguments */ var _ = f8(1, 2.3) @@ -212,115 +208,115 @@ var _ = f8(int, float64)(0, 0, nil...) // test case for #18268 // init functions cannot have type parameters func init() {} -func init(/* ERROR func init must have no type parameters */ type)() {} -func init(/* ERROR func init must have no type parameters */ type P)() {} +func init[/* ERROR func init must have no type parameters */ any]() {} +func init[/* ERROR func init must have no type parameters */ P any]() {} type T struct {} func (T) m1() {} // The type checker accepts method type parameters if configured accordingly. -func (T) m2(type)() {} -func (T) m3(type P)() {} +func (T) m2[any]() {} +func (T) m3[P any]() {} // type inference across parameterized types -type S1(type P) struct { f P } +type S1[P any] struct { f P } -func f9(type P)(x S1(P)) +func f9[P any](x S1[P]) func _() { - f9(int)(S1(int){42}) - f9(S1(int){42}) + f9[int](S1[int]{42}) + f9(S1[int]{42}) } -type S2(type A, B, C) struct{} +type S2[A, B, C any] struct{} -func f10(type X, Y, Z)(a S2(X, int, Z), b S2(X, Y, bool)) +func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool]) -func _(type P)() { - f10(int, float32, string)(S2(int, int, string){}, S2(int, float32, bool){}) - f10(S2(int, int, string){}, S2(int, float32, bool){}) - f10(S2(P, int, P){}, S2(P, float32, bool){}) +func _[P any]() { + f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{}) + f10(S2[int, int, string]{}, S2[int, float32, bool]{}) + f10(S2[P, int, P]{}, S2[P, float32, bool]{}) } // corner case for type inference // (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic) -func f11(type T)() +func f11[T any]() func _() { - f11(int)() + f11[int]() } // the previous example was extracted from -func f12(type T interface{m() T})() +func f12[T interface{m() T}]() -type A(type T) T +type A[T any] T -func (a A(T)) m() A(T) +func (a A[T]) m() A[T] -func _(type T)() { - f12(A(T))() +func _[T any]() { + f12(A[T])() } // method expressions -func (_ S1(P)) m() +func (_ S1[P]) m() func _() { - m := S1(int).m + m := S1[int].m m(struct { f int }{42}) } -func _(type T) (x T) { - m := S1(T).m - m(S1(T){x}) +func _[T any] (x T) { + m := S1[T].m + m(S1[T]{x}) } // type parameters in methods (generalization) type R0 struct{} -func (R0) _(type T)(x T) -func (R0 /* ERROR invalid receiver */ ) _(type R0)() // scope of type parameters starts at "func" +func (R0) _[T any](x T) +func (R0 /* ERROR invalid receiver */ ) _[R0 any]() // scope of type parameters starts at "func" -type R1(type A, B) struct{} +type R1[A, B any] struct{} -func (_ R1(A, B)) m0(A, B) -func (_ R1(A, B)) m1(type T)(A, B, T) T -func (_ R1 /* ERROR not a generic type */ (R1, _)) _() -func (_ R1(A, B)) _(type A /* ERROR redeclared */ )(B) +func (_ R1[A, B]) m0(A, B) +func (_ R1[A, B]) m1[T any](A, B, T) T +func (_ R1 /* ERROR not a generic type */ [R1, _]) _() +func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B) func _() { - var r R1(int, string) - r.m1(rune)(42, "foo", 'a') - r.m1(rune)(42, "foo", 1.2 /* ERROR truncated to rune */) + var r R1[int, string] + r.m1[rune](42, "foo", 'a') + r.m1[rune](42, "foo", 1.2 /* ERROR truncated to rune */) r.m1(42, "foo", 1.2) // using type inference var _ float64 = r.m1(42, "foo", 1.2) } -type I1(type A) interface { +type I1[A any] interface { m1(A) } -var _ I1(int) = r1(int){} +var _ I1[int] = r1[int]{} -type r1(type T) struct{} +type r1[T any] struct{} -func (_ r1(T)) m1(T) +func (_ r1[T]) m1(T) -type I2(type A, B) interface { +type I2[A, B any] interface { m1(A) m2(A) B } -var _ I2(int, float32) = R2(int, float32){} +var _ I2[int, float32] = R2[int, float32]{} -type R2(type P, Q) struct{} +type R2[P, Q any] struct{} -func (_ R2(X, Y)) m1(X) -func (_ R2(X, Y)) m2(X) Y +func (_ R2[X, Y]) m1(X) +func (_ R2[X, Y]) m2(X) Y // type assertions and type switches over generic types // NOTE: These are currently disabled because it's unclear what the correct @@ -328,7 +324,7 @@ func (_ R2(X, Y)) m2(X) Y // an interface first. // // ReadByte1 corresponds to the ReadByte example in the draft design. -// func ReadByte1(type T io.Reader)(r T) (byte, error) { +// func ReadByte1[T io.Reader](r T) (byte, error) { // if br, ok := r.(io.ByteReader); ok { // return br.ReadByte() // } @@ -336,9 +332,9 @@ func (_ R2(X, Y)) m2(X) Y // _, err := r.Read(b[:]) // return b[0], err // } -// +// // // ReadBytes2 is like ReadByte1 but uses a type switch instead. -// func ReadByte2(type T io.Reader)(r T) (byte, error) { +// func ReadByte2[T io.Reader](r T) (byte, error) { // switch br := r.(type) { // case io.ByteReader: // return br.ReadByte() @@ -347,17 +343,17 @@ func (_ R2(X, Y)) m2(X) Y // _, err := r.Read(b[:]) // return b[0], err // } -// +// // // type assertions and type switches over generic types are strict // type I3 interface { // m(int) // } -// +// // type I4 interface { // m() int // different signature from I3.m // } -// -// func _(type T I3)(x I3, p T) { +// +// func _[T I3](x I3, p T) { // // type assertions and type switches over interfaces are not strict // _ = x.(I4) // switch x.(type) { @@ -373,7 +369,7 @@ func (_ R2(X, Y)) m2(X) Y // type assertions and type switches over generic types lead to errors for now -func _(type T)(x T) { +func _[T any](x T) { _ = x /* ERROR not an interface */ .(int) switch x /* ERROR not an interface */ .(type) { } @@ -385,7 +381,7 @@ func _(type T)(x T) { } } -func _(type T interface{type int})(x T) { +func _[T interface{type int}](x T) { _ = x /* ERROR not an interface */ .(int) switch x /* ERROR not an interface */ .(type) { } @@ -398,22 +394,51 @@ func _(type T interface{type int})(x T) { } // error messages related to type bounds mention those bounds -type C(type P) interface{} +type C[P any] interface{} -func _(type P C) (x P) { +func _[P C] (x P) { x.m /* ERROR x.m undefined */ () } type I interface {} -func _(type P I) (x P) { +func _[P I] (x P) { x.m /* ERROR interface I has no method m */ () } -func _(type P interface{}) (x P) { +func _[P interface{}] (x P) { x.m /* ERROR type bound for P has no method m */ () } -func _(type P) (x P) { +func _[P any] (x P) { x.m /* ERROR type bound for P has no method m */ () } + +// automatic distinguishing between array and generic types +// NOTE: Disabled when using unified parameter list syntax. +/* +const P = 10 +type A1 [P]byte +func _(a A1) { + assert(len(a) == 10) +} + +type A2 [P]struct{ + f [P]byte +} +func _(a A2) { + assert(len(a) == 10) + assert(len(a[0].f) == 10) +} + +type A3 [P]func(x [P]A3) +func _(a A3) { + assert(len(a) == 10) +} + +type T2[P] struct{ P } +var _ T2[int] + +type T3[P] func(P) +var _ T3[int] +*/ \ No newline at end of file diff --git a/src/go/types/testdata/typeparamsB.go2 b/src/go/types/testdata/typeparamsB.go2 deleted file mode 100644 index 10b13244aeb30..0000000000000 --- a/src/go/types/testdata/typeparamsB.go2 +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright 2018 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 - -// import "io" // for type assertion tests - -func identity[type T](x T) T { return x } - -func _[type](x int) int -func _[type T](T /* ERROR redeclared */ T)() -func _[type T, T /* ERROR redeclared */ ]() - -func reverse[type T](list []T) []T { - rlist := make([]T, len(list)) - i := len(list) - for _, x := range list { - i-- - rlist[i] = x - } - return rlist -} - -var _ = reverse /* ERROR cannot use generic function reverse */ -var _ = reverse[int, float32 /* ERROR got 2 type arguments */ ] ([]int{1, 2, 3}) -var _ = reverse[int]([ /* ERROR cannot use */ ]float32{1, 2, 3}) -var f = reverse[chan int] -var _ = f(0 /* ERROR cannot convert 0 .* to \[\]chan int */ ) - -func swap[type A, B](a A, b B) (B, A) { return b, a } - -var _ = swap /* ERROR single value is expected */ [int, float32](1, 2) -var f32, i = swap[int, float32](swap(float32, int)(1, 2)) -var _ float32 = f32 -var _ int = i - -func swapswap[type A, B](a A, b B) (A, B) { - return swap[B, A](b, a) -} - -type F[type A, B] func(A, B) (B, A) - -func min[type T interface{ type int }](x, y T) T { - if x < y { - return x - } - return y -} - -func _[type T interface{type int, float32}](x, y T) bool { return x < y } -func _[type T](x, y T) bool { return x /* ERROR cannot compare */ < y } -func _[type T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } - -func _[type T C1](x, y T) bool { return x /* ERROR cannot compare */ < y } -func _[type T C2](x, y T) bool { return x < y } - -type C1[type T] interface{} -type C2[type T] interface{ type int, float32 } - -func new[type T]() *T { - var x T - return &x -} - -var _ = new /* ERROR cannot use generic function new */ -var _ *int = new[int]() - -func _[type T](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable - -func f1[type T1](struct{T1}) int -var _ = f1(int)(struct{T1}{}) -type T1 = int - -func f2[type t1](struct{t1; x float32}) int -var _ = f2(t1)(struct{t1; x float32}{}) -type t1 = int - - -func f3[type A, B, C](A, struct{x B}, func(A, struct{x B}, *C)) int - -var _ = f3[int, rune, bool](1, struct{x rune}{}, nil) - -// type parameters with pointer marking -func _[type *P, Q]() -func _[type *P](x P) - -// indexing - -func _[type T] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[type T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[type T interface{ type string }] (x T, i int) { _ = x[i] } -func _[type T interface{ type []int }] (x T, i int) { _ = x[i] } -func _[type T interface{ type [10]int, *[20]int, map[string]int }] (x T, i int) { _ = x[i] } -func _[type T interface{ type string, []byte }] (x T, i int) { _ = x[i] } -func _[type T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } -func _[type T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } - -// slicing -// TODO(gri) implement this - -func _[type T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } - -// len/cap built-ins - -func _[type T](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[type T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[type T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) } -func _[type T interface{ type string }](x T) { _ = len(x) } -func _[type T interface{ type [10]int }](x T) { _ = len(x) } -func _[type T interface{ type []byte }](x T) { _ = len(x) } -func _[type T interface{ type map[int]int }](x T) { _ = len(x) } -func _[type T interface{ type chan int }](x T) { _ = len(x) } -func _[type T interface{ type string, []byte, chan int }](x T) { _ = len(x) } - -func _[type T](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[type T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[type T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[type T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[type T interface{ type [10]int }](x T) { _ = cap(x) } -func _[type T interface{ type []byte }](x T) { _ = cap(x) } -func _[type T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } -func _[type T interface{ type chan int }](x T) { _ = cap(x) } -func _[type T interface{ type []byte, chan int }](x T) { _ = cap(x) } - -// range iteration - -func _[type T interface{}](x T) { - for range x /* ERROR cannot range */ {} -} - -func _[type T interface{ type string, []string }](x T) { - for range x {} - for i := range x { _ = i } - for i, _ := range x { _ = i } - for i, e := range x /* ERROR must have the same element type */ { _ = i } - for _, e := range x /* ERROR must have the same element type */ {} - var e rune - _ = e - for _, (e) = range x /* ERROR must have the same element type */ {} -} - - -func _[type T interface{ type string, []rune, map[int]rune }](x T) { - for _, e := range x { _ = e } - for i, e := range x { _ = i; _ = e } -} - -func _[type T interface{ type string, []rune, map[string]rune }](x T) { - for _, e := range x { _ = e } - for i, e := range x /* ERROR must have the same key type */ { _ = e } -} - -func _[type T interface{ type string, chan int }](x T) { - for range x {} - for i := range x { _ = i } - for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value -} - -func _[type T interface{ type string, chan<-int }](x T) { - for i := range x /* ERROR send-only channel */ { _ = i } -} - -// type inference checks - -var _ = new() /* ERROR cannot infer T */ - -func f4[type A, B, C](A, B) C - -var _ = f4(1, 2) /* ERROR cannot infer C */ -var _ = f4[int, float32, complex128](1, 2) - -func f5[type A, B, C](A, []*B, struct{f []C}) int - -var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{}) -var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer -var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{}) - -func f6[type A](A, []A) int - -var _ = f6(0, nil) - -func f6nil[type A](A) int - -var _ = f6nil(nil) // ERROR cannot infer - -// type inference with variadic functions - -func f7[type T](...T) T - -var _ int = f7() /* ERROR cannot infer T */ -var _ int = f7(1) -var _ int = f7(1, 2) -var _ int = f7([]int{}...) -var _ int = f7 /* ERROR cannot use */ ([]float64{}...) -var _ float64 = f7([]float64{}...) -var _ = f7[float64](1, 2.3) -var _ = f7(float64(1), 2.3) -var _ = f7(1, 2.3 /* ERROR does not match */ ) -var _ = f7(1.2, 3 /* ERROR does not match */ ) - -func f8[type A, B](A, B, ...B) int - -var _ = f8(1) /* ERROR not enough arguments */ -var _ = f8(1, 2.3) -var _ = f8(1, 2.3, 3.4, 4.5) -var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ ) -var _ = f8(int, float64)(1, 2.3, 3.4, 4) - -var _ = f8(int, float64)(0, 0, nil...) // test case for #18268 - -// init functions cannot have type parameters - -func init() {} -func init[/* ERROR func init must have no type parameters */ type]() {} -func init[/* ERROR func init must have no type parameters */ type P]() {} - -type T struct {} - -func (T) m1() {} -// The type checker accepts method type parameters if configured accordingly. -func (T) m2[type]() {} -func (T) m3[type P]() {} - -// type inference across parameterized types - -type S1[type P] struct { f P } - -func f9[type P](x S1[P]) - -func _() { - f9[int](S1[int]{42}) - f9(S1[int]{42}) -} - -type S2[type A, B, C] struct{} - -func f10[type X, Y, Z](a S2[X, int, Z], b S2[X, Y, bool]) - -func _[type P]() { - f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{}) - f10(S2[int, int, string]{}, S2[int, float32, bool]{}) - f10(S2[P, int, P]{}, S2[P, float32, bool]{}) -} - -// corner case for type inference -// (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic) - -func f11[type T]() - -func _() { - f11[int]() -} - -// the previous example was extracted from - -func f12[type T interface{m() T}]() - -type A[type T] T - -func (a A[T]) m() A[T] - -func _[type T]() { - f12(A[T])() -} - -// method expressions - -func (_ S1[P]) m() - -func _() { - m := S1[int].m - m(struct { f int }{42}) -} - -func _[type T] (x T) { - m := S1[T].m - m(S1[T]{x}) -} - -// type parameters in methods (generalization) - -type R0 struct{} - -func (R0) _[type T](x T) -func (R0 /* ERROR invalid receiver */ ) _[type R0]() // scope of type parameters starts at "func" - -type R1[type A, B] struct{} - -func (_ R1[A, B]) m0(A, B) -func (_ R1[A, B]) m1[type T](A, B, T) T -func (_ R1 /* ERROR not a generic type */ [R1, _]) _() -func (_ R1[A, B]) _[type A /* ERROR redeclared */ ](B) - -func _() { - var r R1[int, string] - r.m1[rune](42, "foo", 'a') - r.m1[rune](42, "foo", 1.2 /* ERROR truncated to rune */) - r.m1(42, "foo", 1.2) // using type inference - var _ float64 = r.m1(42, "foo", 1.2) -} - -type I1[type A] interface { - m1(A) -} - -var _ I1[int] = r1[int]{} - -type r1[type T] struct{} - -func (_ r1[T]) m1(T) - -type I2[type A, B] interface { - m1(A) - m2(A) B -} - -var _ I2[int, float32] = R2[int, float32]{} - -type R2[type P, Q] struct{} - -func (_ R2[X, Y]) m1(X) -func (_ R2[X, Y]) m2(X) Y - -// type assertions and type switches over generic types -// NOTE: These are currently disabled because it's unclear what the correct -// approach is, and one can always work around by assigning the variable to -// an interface first. - -// // ReadByte1 corresponds to the ReadByte example in the draft design. -// func ReadByte1[type T io.Reader](r T) (byte, error) { -// if br, ok := r.(io.ByteReader); ok { -// return br.ReadByte() -// } -// var b [1]byte -// _, err := r.Read(b[:]) -// return b[0], err -// } -// -// // ReadBytes2 is like ReadByte1 but uses a type switch instead. -// func ReadByte2[type T io.Reader](r T) (byte, error) { -// switch br := r.(type) { -// case io.ByteReader: -// return br.ReadByte() -// } -// var b [1]byte -// _, err := r.Read(b[:]) -// return b[0], err -// } -// -// // type assertions and type switches over generic types are strict -// type I3 interface { -// m(int) -// } -// -// type I4 interface { -// m() int // different signature from I3.m -// } -// -// func _[type T I3](x I3, p T) { -// // type assertions and type switches over interfaces are not strict -// _ = x.(I4) -// switch x.(type) { -// case I4: -// } -// -// // type assertions and type switches over generic types are strict -// _ = p /* ERROR cannot have dynamic type I4 */.(I4) -// switch p.(type) { -// case I4 /* ERROR cannot have dynamic type I4 */ : -// } -// } - -// type assertions and type switches over generic types lead to errors for now - -func _[type T](x T) { - _ = x /* ERROR not an interface */ .(int) - switch x /* ERROR not an interface */ .(type) { - } - - // work-around - var t interface{} = x - _ = t.(int) - switch t.(type) { - } -} - -func _[type T interface{type int}](x T) { - _ = x /* ERROR not an interface */ .(int) - switch x /* ERROR not an interface */ .(type) { - } - - // work-around - var t interface{} = x - _ = t.(int) - switch t.(type) { - } -} - -// error messages related to type bounds mention those bounds -type C[type P] interface{} - -func _[type P C] (x P) { - x.m /* ERROR x.m undefined */ () -} - -type I interface {} - -func _[type P I] (x P) { - x.m /* ERROR interface I has no method m */ () -} - -func _[type P interface{}] (x P) { - x.m /* ERROR type bound for P has no method m */ () -} - -func _[type P] (x P) { - x.m /* ERROR type bound for P has no method m */ () -} - -// automatic distinguishing between array and generic types -const P = 10 -type A1 [P]byte -func _(a A1) { - assert(len(a) == 10) -} - -type A2 [P]struct{ - f [P]byte -} -func _(a A2) { - assert(len(a) == 10) - assert(len(a[0].f) == 10) -} - -type A3 [P]func(x [P]A3) -func _(a A3) { - assert(len(a) == 10) -} - -type T2[P] struct{ P } -var _ T2[int] - -type T3[P] func(P) -var _ T3[int] diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index d9bfb2b92c914..a60e76e6e4f55 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -269,9 +269,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeTypeName(buf, t.obj, qf) if t.targs != nil { // instantiated type - buf.WriteByte('(') + buf.WriteByte('[') writeTypeList(buf, t.targs, qf, visited) - buf.WriteByte(')') + buf.WriteByte(']') } else if t.tparams != nil { // parameterized type writeTParamList(buf, t.tparams, qf, visited) @@ -287,9 +287,9 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { case *instance: buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance writeTypeName(buf, t.base.obj, qf) - buf.WriteByte('(') + buf.WriteByte('[') writeTypeList(buf, t.targs, qf, visited) - buf.WriteByte(')') + buf.WriteByte(']') case *bottom: buf.WriteString("⊥") @@ -332,8 +332,9 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited break } } + writeBounds = true // always write the bounds for new type parameter list syntax - buf.WriteString("(type ") + buf.WriteString("[") var prev Type for i, p := range list { b := bound(p) @@ -360,7 +361,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited buf.WriteByte(' ') writeType(buf, prev, qf, visited) } - buf.WriteByte(')') + buf.WriteByte(']') } func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) { diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 4c93cbefa314b..bb82f5606445d 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -407,7 +407,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { var under Type if T != nil { // Calling Under() here may lead to endless instantiations. - // Test case: type T(type P) *T(P) + // Test case: type T[P any] *T[P] // TODO(gri) investigate if that's a bug or to be expected // (see also analogous comment in Checker.instantiate). under = T.Underlying() diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 4242ae91f1d9f..8417f2b6548da 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -19,7 +19,7 @@ import ( // (even if that also contains possibly the same type parameters). This // is crucial to infer the type parameters of self-recursive calls: // -// func f[type P](a P) { f(a) } +// func f[P any](a P) { f(a) } // // For the call f(a) we want to infer that the type argument for P is P. // During unification, the parameter type P must be resolved to the type @@ -258,7 +258,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { // For type unification, do not shortcut (x == y) for identical // types. Instead keep comparing them element-wise to unify the // matching (and equal type parameter types). A simple test case - // where this matters is: func f[type P](a P) { f(a) } . + // where this matters is: func f[P any](a P) { f(a) } . switch x := x.(type) { case *Basic: