aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/syntax
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2020-10-10 17:02:15 -0700
committerRobert Griesemer <gri@golang.org>2020-10-13 04:39:31 +0000
commit7668f02dec44690ee61722f08b2d80b5b0c5eccd (patch)
treea494c14ae85012046c7bc58634574bfa2b19c20c /src/cmd/compile/internal/syntax
parentb627988b0ca748a73867ba5fc4cfc70031c028d2 (diff)
downloadgo-7668f02dec44690ee61722f08b2d80b5b0c5eccd.tar.gz
go-7668f02dec44690ee61722f08b2d80b5b0c5eccd.zip
[dev.typeparams] cmd/compile/internal/syntax: add type parameter tests
The file endings are not .go so that gofmt leaves these files alone. They are also not .src to distinguish them from regular go source tests. Change-Id: I741f5c037bad1ea9d6f7fda3673487d0be631350 Reviewed-on: https://go-review.googlesource.com/c/go/+/261219 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/cmd/compile/internal/syntax')
-rw-r--r--src/cmd/compile/internal/syntax/parser_test.go21
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/chans.go262
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/linalg.go283
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/map.go2113
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/map2.go2146
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/slices.go268
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/smoketest.go283
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/typeinst.go260
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2256
-rw-r--r--src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2451
10 files changed, 1341 insertions, 2 deletions
diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go
index f1c5433b40..e270879739 100644
--- a/src/cmd/compile/internal/syntax/parser_test.go
+++ b/src/cmd/compile/internal/syntax/parser_test.go
@@ -29,7 +29,24 @@ func TestParse(t *testing.T) {
ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
}
-func TestStdLib(t *testing.T) {
+func TestParseGo2(t *testing.T) {
+ dir := filepath.Join(testdata, "go2")
+ list, err := ioutil.ReadDir(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, fi := range list {
+ name := fi.Name()
+ if !fi.IsDir() && !strings.HasPrefix(name, ".") {
+ ParseFile(filepath.Join(dir, name), func(err error) { t.Error(err) }, nil, AllowGenerics)
+ }
+ }
+}
+
+func TestStdLib(t *testing.T) { testStdLib(t, 0) }
+func TestStdLibGeneric(t *testing.T) { testStdLib(t, AllowGenerics) }
+
+func testStdLib(t *testing.T, mode Mode) {
if testing.Short() {
t.Skip("skipping test in short mode")
}
@@ -68,7 +85,7 @@ func TestStdLib(t *testing.T) {
if debug {
fmt.Printf("parsing %s\n", filename)
}
- ast, err := ParseFile(filename, nil, nil, 0)
+ ast, err := ParseFile(filename, nil, nil, mode)
if err != nil {
t.Error(err)
return
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/chans.go2 b/src/cmd/compile/internal/syntax/testdata/go2/chans.go2
new file mode 100644
index 0000000000..fad2bcec9d
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/chans.go2
@@ -0,0 +1,62 @@
+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[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}
+ runtime.SetFinalizer(r, r.finalize)
+ return s, r
+}
+
+// A sender is used to send values to a Receiver.
+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 {
+ 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[T any] 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/cmd/compile/internal/syntax/testdata/go2/linalg.go2 b/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2
new file mode 100644
index 0000000000..0d27603a58
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2
@@ -0,0 +1,83 @@
+// 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[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[T any] 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[T NumericAbs[T]](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[T OrderedNumeric] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
+ if a < 0 {
+ return -a
+ }
+ return a
+}
+
+// ComplexAbs is a helper type that defines an Abs method for
+// complex types.
+type ComplexAbs[T Complex] T
+
+func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
+ r := float64(real(a))
+ i := float64(imag(a))
+ d := math.Sqrt(r * r + i * i)
+ return ComplexAbs[T](complex(d, 0))
+}
+
+func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+ return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
+}
+
+func ComplexAbsDifference[T Complex](a, b T) T {
+ return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
+}
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/map.go2 b/src/cmd/compile/internal/syntax/testdata/go2/map.go2
new file mode 100644
index 0000000000..814d9539fd
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/map.go2
@@ -0,0 +1,113 @@
+// 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[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[K, V any] struct {
+ key K
+ val V
+ left, right *node[K, V]
+}
+
+// New returns a new map.
+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] {
+ 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[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 {
+ 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[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) {
+ 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/cmd/compile/internal/syntax/testdata/go2/map2.go2 b/src/cmd/compile/internal/syntax/testdata/go2/map2.go2
new file mode 100644
index 0000000000..2833445662
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/map2.go2
@@ -0,0 +1,146 @@
+// 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[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[K, V any] struct {
+ key K
+ val V
+ left, right *node[K, V]
+}
+
+// New returns a new map.
+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] {
+ 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[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 {
+ 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[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) {
+ 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[T any]() (*chans_Sender[T], *chans_Receiver[T])
+
+// A sender is used to send values to a Receiver.
+type chans_Sender[T any] 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[T any] 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/cmd/compile/internal/syntax/testdata/go2/slices.go2 b/src/cmd/compile/internal/syntax/testdata/go2/slices.go2
new file mode 100644
index 0000000000..2bacd1c2aa
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/slices.go2
@@ -0,0 +1,68 @@
+// 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[T1, T2 any](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[T1, T2 any](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[T any](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/cmd/compile/internal/syntax/testdata/go2/smoketest.go2 b/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2
new file mode 100644
index 0000000000..e5cfba0612
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2
@@ -0,0 +1,83 @@
+// 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 basic generic code snippets.
+
+package p
+
+// type parameter lists
+type B[P any] struct{}
+type _[P interface{}] struct{}
+type _[P B] struct{}
+type _[P B[P]] struct{}
+
+type _[A, B, C any] struct{}
+type _[A, B, C B] struct{}
+type _[A, B, C B[A, B, C]] struct{}
+type _[A1, A2 B1, A3 B2, A4, A5, A6 B3] struct{}
+
+type _[A interface{}] struct{}
+type _[A, B interface{ m() }] struct{}
+
+type _[A, B, C any] struct{}
+
+// in functions
+func _[P any]()
+func _[P interface{}]()
+func _[P B]()
+func _[P B[P]]()
+
+// in methods
+func (T) _[P any]()
+func (T) _[P interface{}]()
+func (T) _[P B]()
+func (T) _[P B[P]]()
+
+// type instantiations
+type _ T[int]
+
+// in expressions
+var _ = T[int]{}
+
+// in embedded types
+type _ struct{ T[int] }
+
+// interfaces
+type _ interface{
+ m()
+ type int
+}
+
+type _ interface{
+ type int, float, string
+ type complex128
+ underlying(underlying underlying) underlying
+}
+
+type _ interface{
+ T
+ T[int]
+}
+
+// tricky cases
+func _(T[P], T[P1, P2])
+func _(a [N]T)
+
+type _ struct{
+ T[P]
+ T[P1, P2]
+ f [N]
+}
+type _ interface{
+ m()
+
+ // generic methods - disabled for now
+ // m[] /* ERROR empty type parameter list */ ()
+ // m[ /* ERROR cannot have type parameters */ P any](P)
+
+ // instantiated types
+ // T[] /* ERROR empty type argument list */
+ T[P]
+ T[P1, P2]
+}
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/typeinst.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeinst.go2
new file mode 100644
index 0000000000..a422d5e568
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/typeinst.go2
@@ -0,0 +1,60 @@
+// 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[P any] P
+
+type T2[P any] struct {
+ f P
+ g int // int should still be in scope chain
+}
+
+type List[P any] []P
+
+// Alias type declarations cannot have type parameters. Syntax error.
+// TODO(gri) Disabled for now as we don't check syntax error here.
+// type A1[P any] = /* ERROR cannot be alias */ P
+
+// But an alias may refer to a generic, uninstantiated type.
+type A2 = List
+var _ A2[int]
+var _ A2 /* ERROR without instantiation */
+
+type A3 = List[int]
+var _ A3
+
+// Parameterized type instantiations
+
+var x int
+type _ x /* ERROR not a type */ [int]
+
+type _ int /* ERROR not a generic type */ [int]
+type _ myInt /* ERROR not a generic type */ [int]
+
+// TODO(gri) better error messages
+type _ T1[int]
+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[P any] List[P]
+
+var _ T3[int] = T3[int](List[int]{1, 2, 3})
+
+// Self-recursive generic types are not permitted
+
+type self1[P any] self1 /* ERROR illegal cycle */ [P]
+type self2[P any] *self2[P] // this is ok
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2
new file mode 100644
index 0000000000..6e2104a515
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2
@@ -0,0 +1,256 @@
+// 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[E any] []E
+var _ List[List[List[int]]]
+var _ List[List[List[int]]] = []List[List[int]]{}
+
+type (
+ T1[P1 any] struct {
+ f1 T2[P1, float32]
+ }
+
+ T2[P2, P3 any] struct {
+ f2 P2
+ f3 P3
+ }
+)
+
+func _() {
+ var x1 T1[int]
+ var x2 T2[int, float32]
+
+ x1.f1.f2 = 0
+ x1.f1 = x2
+}
+
+type T3[P any] T1[T2[P, P]]
+
+func _() {
+ var x1 T3[int]
+ var x2 T2[int, int]
+ x1.f1.f2 = x2
+}
+
+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]{}
+)
+
+// 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[K any] struct {
+ key K
+}
+
+type Receiver[T any] struct {
+ values T
+}
+
+type Iterator[K any] struct {
+ r Receiver[Pair[K]]
+}
+
+func Values [T any] (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[T any] interface {
+ Abs() T
+}
+
+func AbsDifference[T NumericAbs[T]](x T)
+
+type OrderedAbs[T any] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T]
+
+func OrderedAbsDifference[T any](x T) {
+ AbsDifference(OrderedAbs[T](x))
+}
+
+// same code, reduced to essence
+
+func g[P interface{ m() P }](x P)
+
+type T4[P any] P
+
+func (_ T4[P]) m() T4[P]
+
+func _[Q any](x Q) {
+ g(T4[Q](x))
+}
+
+// Another test case that caused problems in the past
+
+type T5[_ interface { a() }, _ interface{}] struct{}
+
+type A[P any] 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[A any] struct{}
+func (_ R1[A]) vm()
+func (_ *R1[A]) pm()
+
+func _[T any](r R1[T], p *R1[T]) {
+ r.vm()
+ r.pm()
+ p.vm()
+ p.pm()
+}
+
+type R2[A, B any] struct{}
+func (_ R2[A, B]) vm()
+func (_ *R2[A, B]) pm()
+
+func _[T any](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[T interface{type MyInt}](x T) T {
+ return x + 1
+}
+
+type MyString string
+func double[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[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[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[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[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_[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/cmd/compile/internal/syntax/testdata/go2/typeparams.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2
new file mode 100644
index 0000000000..f78037f0f5
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2
@@ -0,0 +1,451 @@
+// 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
+
+// The predeclared identifier "any" is only visible as a constraint
+// in a type parameter list.
+var _ any // ERROR undeclared
+func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) {
+ var _ any /* ERROR undeclared */
+}
+
+func identity[T any](x T) T { return x }
+
+func _[_ any](x int) int
+func _[T any](T /* ERROR redeclared */ T)()
+func _[T, T /* ERROR redeclared */ any]()
+
+func reverse[T any](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[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 _ float32 = f32
+var _ int = i
+
+func swapswap[A, B any](a A, b B) (A, B) {
+ return swap[B, A](b, a)
+}
+
+type F[A, B any] func(A, B) (B, A)
+
+func min[T interface{ type int }](x, y T) T {
+ if x < y {
+ return x
+ }
+ return 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 _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y }
+func _[T C2[T]](x, y T) bool { return x < y }
+
+type C1[T any] interface{}
+type C2[T any] interface{ type int, float32 }
+
+func new[T any]() *T {
+ var x T
+ return &x
+}
+
+var _ = new /* ERROR cannot use generic function new */
+var _ *int = new[int]()
+
+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[T1 any](struct{T1}) int
+var _ = f1(int)(struct{T1}{})
+type T1 = int
+
+func f2[t1 any](struct{t1; x float32}) int
+var _ = f2(t1)(struct{t1; x float32}{})
+type t1 = 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)
+
+// indexing
+
+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 _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] }
+
+// len/cap built-ins
+
+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 _[T interface{}](x T) {
+ for range x /* ERROR cannot range */ {}
+}
+
+func _[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 _[T interface{ type string, []rune, map[int]rune }](x T) {
+ for _, e := range x { _ = e }
+ for i, e := range x { _ = i; _ = e }
+}
+
+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 _[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 _[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[A, B, C any](A, B) C
+
+var _ = f4(1, 2) /* ERROR cannot infer C */
+var _ = f4[int, float32, complex128](1, 2)
+
+func f5[A, B, C any](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[A any](A, []A) int
+
+var _ = f6(0, nil)
+
+func f6nil[A any](A) int
+
+var _ = f6nil(nil) // ERROR cannot infer
+
+// type inference with variadic functions
+
+func f7[T any](...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[A, B any](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 */ _ 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[_ any]() {}
+func (T) m3[P any]() {}
+
+// type inference across parameterized types
+
+type S1[P any] struct { f P }
+
+func f9[P any](x S1[P])
+
+func _() {
+ f9[int](S1[int]{42})
+ f9(S1[int]{42})
+}
+
+type S2[A, B, C any] struct{}
+
+func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, 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[T any]()
+
+func _() {
+ f11[int]()
+}
+
+// the previous example was extracted from
+
+func f12[T interface{m() T}]()
+
+type A[T any] T
+
+func (a A[T]) m() A[T]
+
+func _[T any]() {
+ f12(A[T])()
+}
+
+// method expressions
+
+func (_ S1[P]) m()
+
+func _() {
+ m := S1[int].m
+ m(struct { f int }{42})
+}
+
+func _[T any] (x T) {
+ m := S1[T].m
+ m(S1[T]{x})
+}
+
+// type parameters in methods (generalization)
+
+type R0 struct{}
+
+func (R0) _[T any](x T)
+func (R0 /* ERROR invalid receiver */ ) _[R0 any]() // scope of type parameters starts at "func"
+
+type R1[A, B any] struct{}
+
+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 */)
+ r.m1(42, "foo", 1.2) // using type inference
+ var _ float64 = r.m1(42, "foo", 1.2)
+}
+
+type I1[A any] interface {
+ m1(A)
+}
+
+var _ I1[int] = r1[int]{}
+
+type r1[T any] struct{}
+
+func (_ r1[T]) m1(T)
+
+type I2[A, B any] interface {
+ m1(A)
+ m2(A) B
+}
+
+var _ I2[int, float32] = R2[int, float32]{}
+
+type R2[P, Q any] 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[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[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 _[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 _[T any](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 _[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[P any] interface{}
+
+func _[P C[P]] (x P) {
+ x.m /* ERROR x.m undefined */ ()
+}
+
+type I interface {}
+
+func _[P I] (x P) {
+ x.m /* ERROR interface I has no method m */ ()
+}
+
+func _[P interface{}] (x P) {
+ x.m /* ERROR type bound for P has no method m */ ()
+}
+
+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