diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
commit | 43a123c1ae6613b3efeed291fa552ecd909d3acf (patch) | |
tree | fd92518b7024bc74031f78a1cf9e454b65e73665 /test/typeparam | |
parent | Initial commit. (diff) | |
download | golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.tar.xz golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.zip |
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/typeparam')
478 files changed, 17530 insertions, 0 deletions
diff --git a/test/typeparam/absdiff.go b/test/typeparam/absdiff.go new file mode 100644 index 0000000..9c83eff --- /dev/null +++ b/test/typeparam/absdiff.go @@ -0,0 +1,94 @@ +// run + +// 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 main + +type Numeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 +} + +// 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 matches numeric types that support the < operator. +type orderedNumeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +// Complex matches the two complex types, which do not have a < operator. +type Complex interface { + ~complex64 | ~complex128 +} + +// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). +// // orderedAbs is a helper type that defines an Abs method for +// // ordered numeric types. +// type orderedAbs[T orderedNumeric] T +// +// func (a orderedAbs[T]) Abs() orderedAbs[T] { +// if a < 0 { +// return -a +// } +// return a +// } +// +// // complexAbs is a helper type that defines an Abs method for +// // complex types. +// type complexAbs[T Complex] T +// +// func (a complexAbs[T]) Abs() complexAbs[T] { +// r := float64(real(a)) +// i := float64(imag(a)) +// d := math.Sqrt(r*r + i*i) +// return complexAbs[T](complex(d, 0)) +// } +// +// // OrderedAbsDifference returns the absolute value of the difference +// // between a and b, where a and b are of an ordered type. +// func orderedAbsDifference[T orderedNumeric](a, b T) T { +// return T(absDifference(orderedAbs[T](a), orderedAbs[T](b))) +// } +// +// // ComplexAbsDifference returns the absolute value of the difference +// // between a and b, where a and b are of a complex type. +// func complexAbsDifference[T Complex](a, b T) T { +// return T(absDifference(complexAbs[T](a), complexAbs[T](b))) +// } + +func main() { + // // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). + // if got, want := orderedAbsDifference(1.0, -2.0), 3.0; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // if got, want := orderedAbsDifference(-1.0, 2.0), 3.0; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // if got, want := orderedAbsDifference(-20, 15), 35; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // + // if got, want := complexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // if got, want := complexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } +} diff --git a/test/typeparam/absdiff2.go b/test/typeparam/absdiff2.go new file mode 100644 index 0000000..87a1ec6 --- /dev/null +++ b/test/typeparam/absdiff2.go @@ -0,0 +1,135 @@ +// run + +// Copyright 2022 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. + +// absdiff example in which an Abs method is attached to a generic type, which is a +// structure with a single field that may be a list of possible basic types. + +package main + +import ( + "fmt" + "math" +) + +type Numeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 +} + +// numericAbs matches a struct containing a numeric type that has an Abs method. +type numericAbs[T Numeric] interface { + ~struct{ Value_ T } + Abs() T + Value() 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 Numeric, U numericAbs[T]](a, b U) T { + d := a.Value() - b.Value() + dt := U{Value_: d} + return dt.Abs() +} + +// orderedNumeric matches numeric types that support the < operator. +type orderedNumeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +// Complex matches the two complex types, which do not have a < operator. +type Complex interface { + ~complex64 | ~complex128 +} + +// orderedAbs is a helper type that defines an Abs method for +// a struct containing an ordered numeric type. +type orderedAbs[T orderedNumeric] struct { + Value_ T +} + +func (a orderedAbs[T]) Abs() T { + if a.Value_ < 0 { + return -a.Value_ + } + return a.Value_ +} + +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. +// Use accessor method instead. + +func (a orderedAbs[T]) Value() T { + return a.Value_ +} + +// complexAbs is a helper type that defines an Abs method for +// a struct containing a complex type. +type complexAbs[T Complex] struct { + Value_ T +} + +func realimag(x any) (re, im float64) { + switch z := x.(type) { + case complex64: + re = float64(real(z)) + im = float64(imag(z)) + case complex128: + re = real(z) + im = imag(z) + default: + panic("unknown complex type") + } + return +} + +func (a complexAbs[T]) Abs() T { + // TODO use direct conversion instead of realimag once #50937 is fixed + r, i := realimag(a.Value_) + // r := float64(real(a.Value)) + // i := float64(imag(a.Value)) + d := math.Sqrt(r*r + i*i) + return T(complex(d, 0)) +} + +func (a complexAbs[T]) Value() T { + return a.Value_ +} + +// OrderedAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of an ordered type. +func OrderedAbsDifference[T orderedNumeric](a, b T) T { + return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b}) +} + +// ComplexAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of a complex type. +func ComplexAbsDifference[T Complex](a, b T) T { + return absDifference(complexAbs[T]{a}, complexAbs[T]{b}) +} + +func main() { + if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := OrderedAbsDifference(-20, 15), 35; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + + if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } +} diff --git a/test/typeparam/absdiff3.go b/test/typeparam/absdiff3.go new file mode 100644 index 0000000..c85cd1d --- /dev/null +++ b/test/typeparam/absdiff3.go @@ -0,0 +1,98 @@ +// run + +// Copyright 2022 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. + +// absdiff example using a function argument rather than attaching an +// Abs method to a structure containing base types. + +package main + +import ( + "fmt" + "math" +) + +type Numeric interface { + OrderedNumeric | Complex +} + +// absDifference computes the absolute value of the difference of +// a and b, where the absolute value is determined by the abs function. +func absDifference[T Numeric](a, b T, abs func(a T) T) T { + return abs(a - b) +} + +// OrderedNumeric matches numeric types that support the < operator. +type OrderedNumeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +func Abs[T OrderedNumeric](a T) T { + if a < 0 { + return -a + } + return a +} + +// Complex matches the two complex types, which do not have a < operator. +type Complex interface { + ~complex64 | ~complex128 +} + +func realimag(x any) (re, im float64) { + switch z := x.(type) { + case complex64: + re = float64(real(z)) + im = float64(imag(z)) + case complex128: + re = real(z) + im = imag(z) + default: + panic("unknown complex type") + } + return +} + +func ComplexAbs[T Complex](a T) T { + // TODO use direct conversion instead of realimag once #50937 is fixed + r, i := realimag(a) + // r := float64(real(a)) + // i := float64(imag(a)) + d := math.Sqrt(r*r + i*i) + return T(complex(d, 0)) +} + +// OrderedAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of an ordered type. +func OrderedAbsDifference[T OrderedNumeric](a, b T) T { + return absDifference(a, b, Abs[T]) +} + +// ComplexAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of a complex type. +func ComplexAbsDifference[T Complex](a, b T) T { + return absDifference(a, b, ComplexAbs[T]) +} + +func main() { + if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := OrderedAbsDifference(-20, 15), 35; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + + if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } +} diff --git a/test/typeparam/absdiffimp.dir/a.go b/test/typeparam/absdiffimp.dir/a.go new file mode 100644 index 0000000..60822fd --- /dev/null +++ b/test/typeparam/absdiffimp.dir/a.go @@ -0,0 +1,72 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Numeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 +} + +// 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 matches numeric types that support the < operator. +type orderedNumeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +// Complex matches the two complex types, which do not have a < operator. +type Complex interface { + ~complex64 | ~complex128 +} + +// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). +// // orderedAbs is a helper type that defines an Abs method for +// // ordered numeric types. +// type orderedAbs[T orderedNumeric] T +// +// func (a orderedAbs[T]) Abs() orderedAbs[T] { +// if a < 0 { +// return -a +// } +// return a +// } +// +// // complexAbs is a helper type that defines an Abs method for +// // complex types. +// type complexAbs[T Complex] T +// +// func (a complexAbs[T]) Abs() complexAbs[T] { +// r := float64(real(a)) +// i := float64(imag(a)) +// d := math.Sqrt(r*r + i*i) +// return complexAbs[T](complex(d, 0)) +// } +// +// // OrderedAbsDifference returns the absolute value of the difference +// // between a and b, where a and b are of an ordered type. +// func OrderedAbsDifference[T orderedNumeric](a, b T) T { +// return T(absDifference(orderedAbs[T](a), orderedAbs[T](b))) +// } +// +// // ComplexAbsDifference returns the absolute value of the difference +// // between a and b, where a and b are of a complex type. +// func ComplexAbsDifference[T Complex](a, b T) T { +// return T(absDifference(complexAbs[T](a), complexAbs[T](b))) +// } diff --git a/test/typeparam/absdiffimp.dir/main.go b/test/typeparam/absdiffimp.dir/main.go new file mode 100644 index 0000000..c648013 --- /dev/null +++ b/test/typeparam/absdiffimp.dir/main.go @@ -0,0 +1,25 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). + // if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // + // if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } + // if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want)) + // } +} diff --git a/test/typeparam/absdiffimp.go b/test/typeparam/absdiffimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/absdiffimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/absdiffimp2.dir/a.go b/test/typeparam/absdiffimp2.dir/a.go new file mode 100644 index 0000000..dc64f2d --- /dev/null +++ b/test/typeparam/absdiffimp2.dir/a.go @@ -0,0 +1,110 @@ +// Copyright 2022 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 a + +import ( + "math" +) + +type Numeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~complex64 | ~complex128 +} + +// numericAbs matches a struct containing a numeric type that has an Abs method. +type numericAbs[T Numeric] interface { + ~struct{ Value_ T } + Abs() T + Value() 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 Numeric, U numericAbs[T]](a, b U) T { + d := a.Value() - b.Value() + dt := U{Value_: d} + return dt.Abs() +} + +// orderedNumeric matches numeric types that support the < operator. +type orderedNumeric interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +// Complex matches the two complex types, which do not have a < operator. +type Complex interface { + ~complex64 | ~complex128 +} + +// orderedAbs is a helper type that defines an Abs method for +// a struct containing an ordered numeric type. +type orderedAbs[T orderedNumeric] struct { + Value_ T +} + +func (a orderedAbs[T]) Abs() T { + if a.Value_ < 0 { + return -a.Value_ + } + return a.Value_ +} + +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. +// Use accessor method instead. + +func (a orderedAbs[T]) Value() T { + return a.Value_ +} + +// complexAbs is a helper type that defines an Abs method for +// a struct containing a complex type. +type complexAbs[T Complex] struct { + Value_ T +} + +func realimag(x any) (re, im float64) { + switch z := x.(type) { + case complex64: + re = float64(real(z)) + im = float64(imag(z)) + case complex128: + re = real(z) + im = imag(z) + default: + panic("unknown complex type") + } + return +} + +func (a complexAbs[T]) Abs() T { + // TODO use direct conversion instead of realimag once #50937 is fixed + r, i := realimag(a.Value_) + // r := float64(real(a.Value)) + // i := float64(imag(a.Value)) + d := math.Sqrt(r*r + i*i) + return T(complex(d, 0)) +} + +func (a complexAbs[T]) Value() T { + return a.Value_ +} + +// OrderedAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of an ordered type. +func OrderedAbsDifference[T orderedNumeric](a, b T) T { + return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b}) +} + +// ComplexAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of a complex type. +func ComplexAbsDifference[T Complex](a, b T) T { + return absDifference(complexAbs[T]{a}, complexAbs[T]{b}) +} diff --git a/test/typeparam/absdiffimp2.dir/main.go b/test/typeparam/absdiffimp2.dir/main.go new file mode 100644 index 0000000..1519da0 --- /dev/null +++ b/test/typeparam/absdiffimp2.dir/main.go @@ -0,0 +1,29 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + + if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } +} diff --git a/test/typeparam/absdiffimp2.go b/test/typeparam/absdiffimp2.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/absdiffimp2.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/adder.go b/test/typeparam/adder.go new file mode 100644 index 0000000..fbb4925 --- /dev/null +++ b/test/typeparam/adder.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type AddType interface { + int | int64 | string +} + +// Add can add numbers or strings +func Add[T AddType](a, b T) T { + return a + b +} + +func main() { + if got, want := Add(5, 3), 8; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := Add("ab", "cd"), "abcd"; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/aliasimp.dir/a.go b/test/typeparam/aliasimp.dir/a.go new file mode 100644 index 0000000..c64e87c --- /dev/null +++ b/test/typeparam/aliasimp.dir/a.go @@ -0,0 +1,9 @@ +// 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 a + +type Rimp[T any] struct { + F T +} diff --git a/test/typeparam/aliasimp.dir/main.go b/test/typeparam/aliasimp.dir/main.go new file mode 100644 index 0000000..39c29fc --- /dev/null +++ b/test/typeparam/aliasimp.dir/main.go @@ -0,0 +1,41 @@ +// 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 main + +import "./a" + +type R[T any] struct { + F T +} + +// type S = R // disallowed for now + +type Sint = R[int] + +// type Simp = a.Rimp // disallowed for now + +// type SimpString Simp[string] // disallowed for now +type SimpString a.Rimp[string] + +func main() { + // var s S[int] // disallowed for now + var s R[int] + if s.F != 0 { + panic(s.F) + } + var s2 Sint + if s2.F != 0 { + panic(s2.F) + } + // var s3 Simp[string] // disallowed for now + var s3 a.Rimp[string] + if s3.F != "" { + panic(s3.F) + } + var s4 SimpString + if s4.F != "" { + panic(s4.F) + } +} diff --git a/test/typeparam/aliasimp.go b/test/typeparam/aliasimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/aliasimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/append.go b/test/typeparam/append.go new file mode 100644 index 0000000..6168262 --- /dev/null +++ b/test/typeparam/append.go @@ -0,0 +1,31 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Recv <-chan int + +type sliceOf[E any] interface { + ~[]E +} + +func _Append[S sliceOf[T], T any](s S, t ...T) S { + return append(s, t...) +} + +func main() { + recv := make(Recv) + a := _Append([]Recv{recv}, recv) + if len(a) != 2 || a[0] != recv || a[1] != recv { + panic(a) + } + + recv2 := make(chan<- int) + a2 := _Append([]chan<- int{recv2}, recv2) + if len(a2) != 2 || a2[0] != recv2 || a2[1] != recv2 { + panic(a) + } +} diff --git a/test/typeparam/boundmethod.go b/test/typeparam/boundmethod.go new file mode 100644 index 0000000..510519a --- /dev/null +++ b/test/typeparam/boundmethod.go @@ -0,0 +1,108 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This test illustrates how a type bound method (String below) can be implemented +// either by a concrete type (myint below) or a instantiated generic type +// (StringInt[myint] below). + +package main + +import ( + "fmt" + "reflect" + "strconv" +) + +type myint int + +//go:noinline +func (m myint) String() string { + return strconv.Itoa(int(m)) +} + +type Stringer interface { + String() string +} + +func stringify[T Stringer](s []T) (ret []string) { + for _, v := range s { + // Test normal bounds method call on type param + x1 := v.String() + + // Test converting type param to its bound interface first + v1 := Stringer(v) + x2 := v1.String() + + // Test method expression with type param type + f1 := T.String + x3 := f1(v) + + // Test creating and calling closure equivalent to the method expression + f2 := func(v1 T) string { + return Stringer(v1).String() + } + x4 := f2(v) + + if x1 != x2 || x2 != x3 || x3 != x4 { + panic(fmt.Sprintf("Mismatched values %v, %v, %v, %v\n", x1, x2, x3, x4)) + } + + ret = append(ret, v.String()) + } + return ret +} + +type Ints interface { + ~int32 | ~int +} + +// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). +// type StringInt[T Ints] T +// +// //go:noinline +// func (m StringInt[T]) String() string { +// return strconv.Itoa(int(m)) +// } + +type StringStruct[T Ints] struct { + f T +} + +func (m StringStruct[T]) String() string { + return strconv.Itoa(int(m.f)) +} + +func main() { + x := []myint{myint(1), myint(2), myint(3)} + + // stringify on a normal type, whose bound method is associated with the base type. + got := stringify(x) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). + // x2 := []StringInt[myint]{StringInt[myint](5), StringInt[myint](7), StringInt[myint](6)} + // + // // stringify on an instantiated type, whose bound method is associated with + // // the generic type StringInt[T], which maps directly to T. + // got2 := stringify(x2) + // want2 := []string{"5", "7", "6"} + // if !reflect.DeepEqual(got2, want2) { + // panic(fmt.Sprintf("got %s, want %s", got2, want2)) + // } + + // stringify on an instantiated type, whose bound method is associated with + // the generic type StringStruct[T], which maps to a struct containing T. + x3 := []StringStruct[myint]{StringStruct[myint]{f: 11}, StringStruct[myint]{f: 10}, StringStruct[myint]{f: 9}} + + got3 := stringify(x3) + want3 := []string{"11", "10", "9"} + if !reflect.DeepEqual(got3, want3) { + panic(fmt.Sprintf("got %s, want %s", got3, want3)) + } +} diff --git a/test/typeparam/builtins.go b/test/typeparam/builtins.go new file mode 100644 index 0000000..763d720 --- /dev/null +++ b/test/typeparam/builtins.go @@ -0,0 +1,112 @@ +// compile + +// 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 tests built-in calls on generic types. + +// derived and expanded from cmd/compile/internal/types2/testdata/check/builtins.go2 + +package builtins + +// close + +type C0 interface{ int } +type C1 interface{ chan int } +type C2 interface{ chan int | <-chan int } +type C3 interface{ chan int | chan float32 } +type C4 interface{ chan int | chan<- int } +type C5[T any] interface{ ~chan T | chan<- T } + +func f1[T C1](ch T) { + close(ch) +} + +func f2[T C3](ch T) { + close(ch) +} + +func f3[T C4](ch T) { + close(ch) +} + +func f4[T C5[X], X any](ch T) { + close(ch) +} + +// delete + +type M0 interface{ int } +type M1 interface{ map[string]int } +type M2 interface { + map[string]int | map[string]float64 +} +type M3 interface{ map[string]int | map[rune]int } +type M4[K comparable, V any] interface{ map[K]V | map[rune]V } + +func g1[T M1](m T) { + delete(m, "foo") +} + +func g2[T M2](m T) { + delete(m, "foo") +} + +func g3[T M4[rune, V], V any](m T) { + delete(m, 'k') +} + +// make + +func m1[ + S1 interface{ []int }, + S2 interface{ []int | chan int }, + + M1 interface{ map[string]int }, + M2 interface{ map[string]int | chan int }, + + C1 interface{ chan int }, + C2 interface{ chan int | chan string }, +]() { + _ = make([]int, 10) + _ = make(m1S0, 10) + _ = make(S1, 10) + _ = make(S1, 10, 20) + + _ = make(map[string]int) + _ = make(m1M0) + _ = make(M1) + _ = make(M1, 10) + + _ = make(chan int) + _ = make(m1C0) + _ = make(C1) + _ = make(C1, 10) +} +// TODO: put these type declarations back inside m1 when issue 47631 is fixed. +type m1S0 []int +type m1M0 map[string]int +type m1C0 chan int + +// len/cap + +type Slice[T any] interface { + []T +} + +func c1[T any, S Slice[T]]() { + x := make(S, 5, 10) + _ = len(x) + _ = cap(x) +} + +// append + +func a1[T any, S Slice[T]]() { + x := make(S, 5) + y := make(S, 2) + var z T + _ = append(x, y...) + _ = append(x, z) +} diff --git a/test/typeparam/chans.go b/test/typeparam/chans.go new file mode 100644 index 0000000..d73ce6e --- /dev/null +++ b/test/typeparam/chans.go @@ -0,0 +1,413 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package chans provides utility functions for working with channels. +package main + +import ( + "context" + "fmt" + "runtime" + "sort" + "sync" + "time" +) + +// _Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func _SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// _ReadAll reads from c until the channel is closed or the context is +// canceled, returning all the values read. +func _ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem { + var r []Elem + for { + select { + case <-ctx.Done(): + return r + case v, ok := <-c: + if !ok { + return r + } + r = append(r, v) + } + } +} + +// _Merge merges two channels into a single channel. +// This will leave a goroutine running until either both channels are closed +// or the context is canceled, at which point the returned channel is closed. +func _Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) { + defer close(r) + for c1 != nil || c2 != nil { + select { + case <-ctx.Done(): + return + case v1, ok := <-c1: + if ok { + r <- v1 + } else { + c1 = nil + } + case v2, ok := <-c2: + if ok { + r <- v2 + } else { + c2 = nil + } + } + } + }(ctx, c1, c2, r) + return r +} + +// _Filter calls f on each value read from c. If f returns true the value +// is sent on the returned channel. This will leave a goroutine running +// until c is closed or the context is canceled, at which point the +// returned channel is closed. +func _Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) { + defer close(r) + for { + select { + case <-ctx.Done(): + return + case v, ok := <-c: + if !ok { + return + } + if f(v) { + r <- v + } + } + } + }(ctx, c, f, r) + return r +} + +// _Sink returns a channel that discards all values sent to it. +// This will leave a goroutine running until the context is canceled +// or the returned channel is closed. +func _Sink[Elem any](ctx context.Context) chan<- Elem { + r := make(chan Elem) + go func(ctx context.Context, r <-chan Elem) { + for { + select { + case <-ctx.Done(): + return + case _, ok := <-r: + if !ok { + return + } + } + } + }(ctx, r) + return r +} + +// An Exclusive is a value that may only be used by a single goroutine +// at a time. This is implemented using channels rather than a mutex. +type _Exclusive[Val any] struct { + c chan Val +} + +// _MakeExclusive makes an initialized exclusive value. +func _MakeExclusive[Val any](initial Val) *_Exclusive[Val] { + r := &_Exclusive[Val]{ + c: make(chan Val, 1), + } + r.c <- initial + return r +} + +// _Acquire acquires the exclusive value for private use. +// It must be released using the Release method. +func (e *_Exclusive[Val]) Acquire() Val { + return <-e.c +} + +// TryAcquire attempts to acquire the value. The ok result reports whether +// the value was acquired. If the value is acquired, it must be released +// using the Release method. +func (e *_Exclusive[Val]) TryAcquire() (v Val, ok bool) { + select { + case r := <-e.c: + return r, true + default: + return v, false + } +} + +// Release updates and releases the value. +// This method panics if the value has not been acquired. +func (e *_Exclusive[Val]) Release(v Val) { + select { + case e.c <- v: + default: + panic("_Exclusive Release without Acquire") + } +} + +// 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[Elem any]() (*_Sender[Elem], *_Receiver[Elem]) { + c := make(chan Elem) + d := make(chan struct{}) + s := &_Sender[Elem]{ + values: c, + done: d, + } + r := &_Receiver[Elem]{ + values: c, + done: d, + } + runtime.SetFinalizer(r, (*_Receiver[Elem]).finalize) + return s, r +} + +// A _Sender is used to send values to a Receiver. +type _Sender[Elem any] struct { + values chan<- Elem + done <-chan struct{} +} + +// Send sends a value to the receiver. It reports whether the value was sent. +// The value will not be sent if the context is closed or the receiver +// is freed. +func (s *_Sender[Elem]) Send(ctx context.Context, v Elem) bool { + select { + case <-ctx.Done(): + return false + 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[Elem]) Close() { + close(s.values) +} + +// A _Receiver receives values from a _Sender. +type _Receiver[Elem any] struct { + values <-chan Elem + done chan<- struct{} +} + +// Next returns the next value from the channel. The bool result indicates +// whether the value is valid. +func (r *_Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) { + select { + case <-ctx.Done(): + case v, ok = <-r.values: + } + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *_Receiver[Elem]) finalize() { + close(r.done) +} + +func TestReadAll() { + c := make(chan int) + go func() { + c <- 4 + c <- 2 + c <- 5 + close(c) + }() + got := _ReadAll(context.Background(), c) + want := []int{4, 2, 5} + if !_SliceEqual(got, want) { + panic(fmt.Sprintf("_ReadAll returned %v, want %v", got, want)) + } +} + +func TestMerge() { + c1 := make(chan int) + c2 := make(chan int) + go func() { + c1 <- 1 + c1 <- 3 + c1 <- 5 + close(c1) + }() + go func() { + c2 <- 2 + c2 <- 4 + c2 <- 6 + close(c2) + }() + ctx := context.Background() + got := _ReadAll(ctx, _Merge(ctx, c1, c2)) + sort.Ints(got) + want := []int{1, 2, 3, 4, 5, 6} + if !_SliceEqual(got, want) { + panic(fmt.Sprintf("_Merge returned %v, want %v", got, want)) + } +} + +func TestFilter() { + c := make(chan int) + go func() { + c <- 1 + c <- 2 + c <- 3 + close(c) + }() + even := func(i int) bool { return i%2 == 0 } + ctx := context.Background() + got := _ReadAll(ctx, _Filter(ctx, c, even)) + want := []int{2} + if !_SliceEqual(got, want) { + panic(fmt.Sprintf("_Filter returned %v, want %v", got, want)) + } +} + +func TestSink() { + c := _Sink[int](context.Background()) + after := time.NewTimer(time.Minute) + defer after.Stop() + send := func(v int) { + select { + case c <- v: + case <-after.C: + panic("timed out sending to _Sink") + } + } + send(1) + send(2) + send(3) + close(c) +} + +func TestExclusive() { + val := 0 + ex := _MakeExclusive(&val) + + var wg sync.WaitGroup + f := func() { + defer wg.Done() + for i := 0; i < 10; i++ { + p := ex.Acquire() + (*p)++ + ex.Release(p) + } + } + + wg.Add(2) + go f() + go f() + + wg.Wait() + if val != 20 { + panic(fmt.Sprintf("after Acquire/Release loop got %d, want 20", val)) + } +} + +func TestExclusiveTry() { + s := "" + ex := _MakeExclusive(&s) + p, ok := ex.TryAcquire() + if !ok { + panic("TryAcquire failed") + } + *p = "a" + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + _, ok := ex.TryAcquire() + if ok { + panic(fmt.Sprintf("TryAcquire succeeded unexpectedly")) + } + }() + wg.Wait() + + ex.Release(p) + + p, ok = ex.TryAcquire() + if !ok { + panic(fmt.Sprintf("TryAcquire failed")) + } +} + +func TestRanger() { + s, r := _Ranger[int]() + + ctx := context.Background() + go func() { + // Receive one value then exit. + v, ok := r.Next(ctx) + if !ok { + panic(fmt.Sprintf("did not receive any values")) + } else if v != 1 { + panic(fmt.Sprintf("received %d, want 1", v)) + } + }() + + c1 := make(chan bool) + c2 := make(chan bool) + go func() { + defer close(c2) + if !s.Send(ctx, 1) { + panic(fmt.Sprintf("Send failed unexpectedly")) + } + close(c1) + if s.Send(ctx, 2) { + panic(fmt.Sprintf("Send succeeded unexpectedly")) + } + }() + + <-c1 + + // Force a garbage collection to try to get the finalizers to run. + runtime.GC() + + select { + case <-c2: + case <-time.After(time.Minute): + panic("_Ranger Send should have failed, but timed out") + } +} + +func main() { + TestReadAll() + TestMerge() + TestFilter() + TestSink() + TestExclusive() + TestExclusiveTry() + TestRanger() +} diff --git a/test/typeparam/chansimp.dir/a.go b/test/typeparam/chansimp.dir/a.go new file mode 100644 index 0000000..7321992 --- /dev/null +++ b/test/typeparam/chansimp.dir/a.go @@ -0,0 +1,232 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import ( + "context" + "runtime" +) + +// Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// ReadAll reads from c until the channel is closed or the context is +// canceled, returning all the values read. +func ReadAll[Elem any](ctx context.Context, c <-chan Elem) []Elem { + var r []Elem + for { + select { + case <-ctx.Done(): + return r + case v, ok := <-c: + if !ok { + return r + } + r = append(r, v) + } + } +} + +// Merge merges two channels into a single channel. +// This will leave a goroutine running until either both channels are closed +// or the context is canceled, at which point the returned channel is closed. +func Merge[Elem any](ctx context.Context, c1, c2 <-chan Elem) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c1, c2 <-chan Elem, r chan<- Elem) { + defer close(r) + for c1 != nil || c2 != nil { + select { + case <-ctx.Done(): + return + case v1, ok := <-c1: + if ok { + r <- v1 + } else { + c1 = nil + } + case v2, ok := <-c2: + if ok { + r <- v2 + } else { + c2 = nil + } + } + } + }(ctx, c1, c2, r) + return r +} + +// Filter calls f on each value read from c. If f returns true the value +// is sent on the returned channel. This will leave a goroutine running +// until c is closed or the context is canceled, at which point the +// returned channel is closed. +func Filter[Elem any](ctx context.Context, c <-chan Elem, f func(Elem) bool) <-chan Elem { + r := make(chan Elem) + go func(ctx context.Context, c <-chan Elem, f func(Elem) bool, r chan<- Elem) { + defer close(r) + for { + select { + case <-ctx.Done(): + return + case v, ok := <-c: + if !ok { + return + } + if f(v) { + r <- v + } + } + } + }(ctx, c, f, r) + return r +} + +// Sink returns a channel that discards all values sent to it. +// This will leave a goroutine running until the context is canceled +// or the returned channel is closed. +func Sink[Elem any](ctx context.Context) chan<- Elem { + r := make(chan Elem) + go func(ctx context.Context, r <-chan Elem) { + for { + select { + case <-ctx.Done(): + return + case _, ok := <-r: + if !ok { + return + } + } + } + }(ctx, r) + return r +} + +// An Exclusive is a value that may only be used by a single goroutine +// at a time. This is implemented using channels rather than a mutex. +type Exclusive[Val any] struct { + c chan Val +} + +// MakeExclusive makes an initialized exclusive value. +func MakeExclusive[Val any](initial Val) *Exclusive[Val] { + r := &Exclusive[Val]{ + c: make(chan Val, 1), + } + r.c <- initial + return r +} + +// Acquire acquires the exclusive value for private use. +// It must be released using the Release method. +func (e *Exclusive[Val]) Acquire() Val { + return <-e.c +} + +// TryAcquire attempts to acquire the value. The ok result reports whether +// the value was acquired. If the value is acquired, it must be released +// using the Release method. +func (e *Exclusive[Val]) TryAcquire() (v Val, ok bool) { + select { + case r := <-e.c: + return r, true + default: + return v, false + } +} + +// Release updates and releases the value. +// This method panics if the value has not been acquired. +func (e *Exclusive[Val]) Release(v Val) { + select { + case e.c <- v: + default: + panic("Exclusive Release without Acquire") + } +} + +// 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[Elem any]() (*Sender[Elem], *Receiver[Elem]) { + c := make(chan Elem) + d := make(chan struct{}) + s := &Sender[Elem]{ + values: c, + done: d, + } + r := &Receiver[Elem]{ + values: c, + done: d, + } + runtime.SetFinalizer(r, (*Receiver[Elem]).finalize) + return s, r +} + +// A Sender is used to send values to a Receiver. +type Sender[Elem any] struct { + values chan<- Elem + done <-chan struct{} +} + +// Send sends a value to the receiver. It reports whether the value was sent. +// The value will not be sent if the context is closed or the receiver +// is freed. +func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool { + select { + case <-ctx.Done(): + return false + 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[Elem]) Close() { + close(s.values) +} + +// A Receiver receives values from a Sender. +type Receiver[Elem any] struct { + values <-chan Elem + done chan<- struct{} +} + +// Next returns the next value from the channel. The bool result indicates +// whether the value is valid. +func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) { + select { + case <-ctx.Done(): + case v, ok = <-r.values: + } + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *Receiver[Elem]) finalize() { + close(r.done) +} diff --git a/test/typeparam/chansimp.dir/main.go b/test/typeparam/chansimp.dir/main.go new file mode 100644 index 0000000..a380a3c --- /dev/null +++ b/test/typeparam/chansimp.dir/main.go @@ -0,0 +1,189 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "context" + "fmt" + "runtime" + "sort" + "sync" + "time" +) + +func TestReadAll() { + c := make(chan int) + go func() { + c <- 4 + c <- 2 + c <- 5 + close(c) + }() + got := a.ReadAll(context.Background(), c) + want := []int{4, 2, 5} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("ReadAll returned %v, want %v", got, want)) + } +} + +func TestMerge() { + c1 := make(chan int) + c2 := make(chan int) + go func() { + c1 <- 1 + c1 <- 3 + c1 <- 5 + close(c1) + }() + go func() { + c2 <- 2 + c2 <- 4 + c2 <- 6 + close(c2) + }() + ctx := context.Background() + got := a.ReadAll(ctx, a.Merge(ctx, c1, c2)) + sort.Ints(got) + want := []int{1, 2, 3, 4, 5, 6} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("Merge returned %v, want %v", got, want)) + } +} + +func TestFilter() { + c := make(chan int) + go func() { + c <- 1 + c <- 2 + c <- 3 + close(c) + }() + even := func(i int) bool { return i%2 == 0 } + ctx := context.Background() + got := a.ReadAll(ctx, a.Filter(ctx, c, even)) + want := []int{2} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("Filter returned %v, want %v", got, want)) + } +} + +func TestSink() { + c := a.Sink[int](context.Background()) + after := time.NewTimer(time.Minute) + defer after.Stop() + send := func(v int) { + select { + case c <- v: + case <-after.C: + panic("timed out sending to Sink") + } + } + send(1) + send(2) + send(3) + close(c) +} + +func TestExclusive() { + val := 0 + ex := a.MakeExclusive(&val) + + var wg sync.WaitGroup + f := func() { + defer wg.Done() + for i := 0; i < 10; i++ { + p := ex.Acquire() + (*p)++ + ex.Release(p) + } + } + + wg.Add(2) + go f() + go f() + + wg.Wait() + if val != 20 { + panic(fmt.Sprintf("after Acquire/Release loop got %d, want 20", val)) + } +} + +func TestExclusiveTry() { + s := "" + ex := a.MakeExclusive(&s) + p, ok := ex.TryAcquire() + if !ok { + panic("TryAcquire failed") + } + *p = "a" + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + _, ok := ex.TryAcquire() + if ok { + panic(fmt.Sprintf("TryAcquire succeeded unexpectedly")) + } + }() + wg.Wait() + + ex.Release(p) + + p, ok = ex.TryAcquire() + if !ok { + panic(fmt.Sprintf("TryAcquire failed")) + } +} + +func TestRanger() { + s, r := a.Ranger[int]() + + ctx := context.Background() + go func() { + // Receive one value then exit. + v, ok := r.Next(ctx) + if !ok { + panic(fmt.Sprintf("did not receive any values")) + } else if v != 1 { + panic(fmt.Sprintf("received %d, want 1", v)) + } + }() + + c1 := make(chan bool) + c2 := make(chan bool) + go func() { + defer close(c2) + if !s.Send(ctx, 1) { + panic(fmt.Sprintf("Send failed unexpectedly")) + } + close(c1) + if s.Send(ctx, 2) { + panic(fmt.Sprintf("Send succeeded unexpectedly")) + } + }() + + <-c1 + + // Force a garbage collection to try to get the finalizers to run. + runtime.GC() + + select { + case <-c2: + case <-time.After(time.Minute): + panic("Ranger Send should have failed, but timed out") + } +} + +func main() { + TestReadAll() + TestMerge() + TestFilter() + TestSink() + TestExclusive() + TestExclusiveTry() + TestRanger() +} diff --git a/test/typeparam/chansimp.go b/test/typeparam/chansimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/chansimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/combine.go b/test/typeparam/combine.go new file mode 100644 index 0000000..361708f --- /dev/null +++ b/test/typeparam/combine.go @@ -0,0 +1,65 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type Gen[A any] func() (A, bool) + +func Combine[T1, T2, T any](g1 Gen[T1], g2 Gen[T2], join func(T1, T2) T) Gen[T] { + return func() (T, bool) { + var t T + t1, ok := g1() + if !ok { + return t, false + } + t2, ok := g2() + if !ok { + return t, false + } + return join(t1, t2), true + } +} + +type Pair[A, B any] struct { + A A + B B +} + +func _NewPair[A, B any](a A, b B) Pair[A, B] { + return Pair[A, B]{a, b} +} + +func Combine2[A, B any](ga Gen[A], gb Gen[B]) Gen[Pair[A, B]] { + return Combine(ga, gb, _NewPair[A, B]) +} + +func main() { + var g1 Gen[int] = func() (int, bool) { return 3, true } + var g2 Gen[string] = func() (string, bool) { return "x", false } + var g3 Gen[string] = func() (string, bool) { return "y", true } + + gc := Combine(g1, g2, _NewPair[int, string]) + if got, ok := gc(); ok { + panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok)) + } + gc2 := Combine2(g1, g2) + if got, ok := gc2(); ok { + panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok)) + } + + gc3 := Combine(g1, g3, _NewPair[int, string]) + if got, ok := gc3(); !ok || got.A != 3 || got.B != "y" { + panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) + } + gc4 := Combine2(g1, g3) + if got, ok := gc4(); !ok || got.A != 3 || got.B != "y" { + panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) + } +} diff --git a/test/typeparam/cons.go b/test/typeparam/cons.go new file mode 100644 index 0000000..733e579 --- /dev/null +++ b/test/typeparam/cons.go @@ -0,0 +1,100 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +// Overriding the predeclare "any", so it can be used as a type constraint or a type +// argument +type any interface{} + +type Function[a, b any] interface { + Apply(x a) b +} + +type incr struct{ n int } + +func (this incr) Apply(x int) int { + return x + this.n +} + +type pos struct{} + +func (this pos) Apply(x int) bool { + return x > 0 +} + +type compose[a, b, c any] struct { + f Function[a, b] + g Function[b, c] +} + +func (this compose[a, b, c]) Apply(x a) c { + return this.g.Apply(this.f.Apply(x)) +} + +type _Eq[a any] interface { + Equal(a) bool +} + +type Int int + +func (this Int) Equal(that int) bool { + return int(this) == that +} + +type List[a any] interface { + Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any +} + +type Nil[a any] struct { +} + +func (xs Nil[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { + return casenil.Apply(xs) +} + +type Cons[a any] struct { + Head a + Tail List[a] +} + +func (xs Cons[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { + return casecons.Apply(xs) +} + +type mapNil[a, b any] struct { +} + +func (m mapNil[a, b]) Apply(_ Nil[a]) any { + return Nil[b]{} +} + +type mapCons[a, b any] struct { + f Function[a, b] +} + +func (m mapCons[a, b]) Apply(xs Cons[a]) any { + return Cons[b]{m.f.Apply(xs.Head), Map[a, b](m.f, xs.Tail)} +} + +func Map[a, b any](f Function[a, b], xs List[a]) List[b] { + return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(List[b]) +} + +func main() { + var xs List[int] = Cons[int]{3, Cons[int]{6, Nil[int]{}}} + var ys List[int] = Map[int, int](incr{-5}, xs) + var xz List[bool] = Map[int, bool](pos{}, ys) + cs1 := xz.(Cons[bool]) + cs2 := cs1.Tail.(Cons[bool]) + _, ok := cs2.Tail.(Nil[bool]) + if cs1.Head != false || cs2.Head != true || !ok { + panic(fmt.Sprintf("got %v, %v, %v, expected false, true, true", + cs1.Head, cs2.Head, ok)) + } +} diff --git a/test/typeparam/dedup.dir/a.go b/test/typeparam/dedup.dir/a.go new file mode 100644 index 0000000..f5cb6dc --- /dev/null +++ b/test/typeparam/dedup.dir/a.go @@ -0,0 +1,10 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +//go:noinline +func F[T comparable](a, b T) bool { + return a == b +} diff --git a/test/typeparam/dedup.dir/b.go b/test/typeparam/dedup.dir/b.go new file mode 100644 index 0000000..8507c64 --- /dev/null +++ b/test/typeparam/dedup.dir/b.go @@ -0,0 +1,14 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func B() { + var x int64 + println(a.F(&x, &x)) + var y int32 + println(a.F(&y, &y)) +} diff --git a/test/typeparam/dedup.dir/c.go b/test/typeparam/dedup.dir/c.go new file mode 100644 index 0000000..a1c950f --- /dev/null +++ b/test/typeparam/dedup.dir/c.go @@ -0,0 +1,14 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package c + +import "./a" + +func C() { + var x int64 + println(a.F(&x, &x)) + var y int32 + println(a.F(&y, &y)) +} diff --git a/test/typeparam/dedup.dir/main.go b/test/typeparam/dedup.dir/main.go new file mode 100644 index 0000000..920591b --- /dev/null +++ b/test/typeparam/dedup.dir/main.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./b" + "./c" +) + +func main() { + b.B() + c.C() +} diff --git a/test/typeparam/dedup.go b/test/typeparam/dedup.go new file mode 100644 index 0000000..3b98e03 --- /dev/null +++ b/test/typeparam/dedup.go @@ -0,0 +1,12 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Note: this doesn't really test the deduplication of +// instantiations. It just provides an easy mechanism to build a +// binary that you can then check with objdump manually to make sure +// deduplication is happening. TODO: automate this somehow? + +package ignored diff --git a/test/typeparam/dedup.out b/test/typeparam/dedup.out new file mode 100644 index 0000000..1140ff5 --- /dev/null +++ b/test/typeparam/dedup.out @@ -0,0 +1,4 @@ +true +true +true +true diff --git a/test/typeparam/dictionaryCapture-noinline.go b/test/typeparam/dictionaryCapture-noinline.go new file mode 100644 index 0000000..4c5e7ec --- /dev/null +++ b/test/typeparam/dictionaryCapture-noinline.go @@ -0,0 +1,126 @@ +// run -gcflags="-l" + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test situations where functions/methods are not +// immediately called and we need to capture the dictionary +// required for later invocation. + +package main + +func main() { + functions() + methodExpressions() + methodValues() + interfaceMethods() + globals() +} + +func g0[T any](x T) { +} +func g1[T any](x T) T { + return x +} +func g2[T any](x T) (T, T) { + return x, x +} + +func functions() { + f0 := g0[int] + f0(7) + f1 := g1[int] + is7(f1(7)) + f2 := g2[int] + is77(f2(7)) +} + +func is7(x int) { + if x != 7 { + println(x) + panic("assertion failed") + } +} +func is77(x, y int) { + if x != 7 || y != 7 { + println(x, y) + panic("assertion failed") + } +} + +type s[T any] struct { + a T +} + +func (x s[T]) g0() { +} +func (x s[T]) g1() T { + return x.a +} +func (x s[T]) g2() (T, T) { + return x.a, x.a +} + +func methodExpressions() { + x := s[int]{a: 7} + f0 := s[int].g0 + f0(x) + f1 := s[int].g1 + is7(f1(x)) + f2 := s[int].g2 + is77(f2(x)) +} + +func methodValues() { + x := s[int]{a: 7} + f0 := x.g0 + f0() + f1 := x.g1 + is7(f1()) + f2 := x.g2 + is77(f2()) +} + +var x interface { + g0() + g1() int + g2() (int, int) +} = s[int]{a: 7} +var y interface{} = s[int]{a: 7} + +func interfaceMethods() { + x.g0() + is7(x.g1()) + is77(x.g2()) + y.(interface{ g0() }).g0() + is7(y.(interface{ g1() int }).g1()) + is77(y.(interface{ g2() (int, int) }).g2()) +} + +// Also check for instantiations outside functions. +var gg0 = g0[int] +var gg1 = g1[int] +var gg2 = g2[int] + +var hh0 = s[int].g0 +var hh1 = s[int].g1 +var hh2 = s[int].g2 + +var xtop = s[int]{a: 7} +var ii0 = x.g0 +var ii1 = x.g1 +var ii2 = x.g2 + +func globals() { + gg0(7) + is7(gg1(7)) + is77(gg2(7)) + x := s[int]{a: 7} + hh0(x) + is7(hh1(x)) + is77(hh2(x)) + ii0() + is7(ii1()) + is77(ii2()) +} diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go new file mode 100644 index 0000000..b503abb --- /dev/null +++ b/test/typeparam/dictionaryCapture.go @@ -0,0 +1,203 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test situations where functions/methods are not +// immediately called and we need to capture the dictionary +// required for later invocation. + +package main + +import ( + "fmt" +) + +func main() { + functions() + methodExpressions() + genMethodExpressions[int](7) + methodValues() + genMethodValues[int](7) + interfaceMethods() + globals() + recursive() +} + +func g0[T any](x T) { +} +func g1[T any](x T) T { + return x +} +func g2[T any](x T) (T, T) { + return x, x +} + +func functions() { + f0 := g0[int] + f0(7) + f1 := g1[int] + is7(f1(7)) + f2 := g2[int] + is77(f2(7)) +} + +func is7(x int) { + if x != 7 { + println(x) + panic("assertion failed") + } +} +func is77(x, y int) { + if x != 7 || y != 7 { + println(x, y) + panic("assertion failed") + } +} + +type s[T any] struct { + a T +} + +func (x s[T]) g0() { +} +func (x s[T]) g1() T { + return x.a +} +func (x s[T]) g2() (T, T) { + return x.a, x.a +} + +func methodExpressions() { + x := s[int]{a: 7} + f0 := s[int].g0 + f0(x) + f0p := (*s[int]).g0 + f0p(&x) + f1 := s[int].g1 + is7(f1(x)) + f1p := (*s[int]).g1 + is7(f1p(&x)) + f2 := s[int].g2 + is77(f2(x)) + f2p := (*s[int]).g2 + is77(f2p(&x)) +} + +func genMethodExpressions[T comparable](want T) { + x := s[T]{a: want} + f0 := s[T].g0 + f0(x) + f0p := (*s[T]).g0 + f0p(&x) + f1 := s[T].g1 + if got := f1(x); got != want { + panic(fmt.Sprintf("f1(x) == %d, want %d", got, want)) + } + f1p := (*s[T]).g1 + if got := f1p(&x); got != want { + panic(fmt.Sprintf("f1p(&x) == %d, want %d", got, want)) + } + f2 := s[T].g2 + if got1, got2 := f2(x); got1 != want || got2 != want { + panic(fmt.Sprintf("f2(x) == %d, %d, want %d, %d", got1, got2, want, want)) + } +} + +func methodValues() { + x := s[int]{a: 7} + f0 := x.g0 + f0() + f1 := x.g1 + is7(f1()) + f2 := x.g2 + is77(f2()) +} + +func genMethodValues[T comparable](want T) { + x := s[T]{a: want} + f0 := x.g0 + f0() + f1 := x.g1 + if got := f1(); got != want { + panic(fmt.Sprintf("f1() == %d, want %d", got, want)) + } + f2 := x.g2 + if got1, got2 := f2(); got1 != want || got2 != want { + panic(fmt.Sprintf("f2() == %d, %d, want %d, %d", got1, got2, want, want)) + } +} + +var x interface { + g0() + g1() int + g2() (int, int) +} = s[int]{a: 7} +var y interface{} = s[int]{a: 7} + +func interfaceMethods() { + x.g0() + is7(x.g1()) + is77(x.g2()) + y.(interface{ g0() }).g0() + is7(y.(interface{ g1() int }).g1()) + is77(y.(interface{ g2() (int, int) }).g2()) +} + +// Also check for instantiations outside functions. +var gg0 = g0[int] +var gg1 = g1[int] +var gg2 = g2[int] + +var hh0 = s[int].g0 +var hh1 = s[int].g1 +var hh2 = s[int].g2 + +var xtop = s[int]{a: 7} +var ii0 = x.g0 +var ii1 = x.g1 +var ii2 = x.g2 + +func globals() { + gg0(7) + is7(gg1(7)) + is77(gg2(7)) + x := s[int]{a: 7} + hh0(x) + is7(hh1(x)) + is77(hh2(x)) + ii0() + is7(ii1()) + is77(ii2()) +} + +func recursive() { + if got, want := recur1[int](5), 110; got != want { + panic(fmt.Sprintf("recur1[int](5) = %d, want = %d", got, want)) + } +} + +type Integer interface { + int | int32 | int64 +} + +func recur1[T Integer](n T) T { + if n == 0 || n == 1 { + return T(1) + } else { + return n * recur2(n-1) + } +} + +func recur2[T Integer](n T) T { + list := make([]T, n) + for i, _ := range list { + list[i] = T(i + 1) + } + var sum T + for _, elt := range list { + sum += elt + } + return sum + recur1(n-1) +} diff --git a/test/typeparam/dottype.go b/test/typeparam/dottype.go new file mode 100644 index 0000000..9f1630d --- /dev/null +++ b/test/typeparam/dottype.go @@ -0,0 +1,86 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T any](x interface{}) T { + return x.(T) +} +func f2[T any](x interface{}) (T, bool) { + t, ok := x.(T) + return t, ok +} + +type I interface { + foo() +} + +type myint int + +func (myint) foo() { +} + +type myfloat float64 + +func (myfloat) foo() { +} + +func g[T I](x I) T { + return x.(T) +} +func g2[T I](x I) (T, bool) { + t, ok := x.(T) + return t, ok +} + +func h[T any](x interface{}) struct{ a, b T } { + return x.(struct{ a, b T }) +} + +func k[T any](x interface{}) interface{ bar() T } { + return x.(interface{ bar() T }) +} + +type mybar int + +func (x mybar) bar() int { + return int(x) +} + +func main() { + var i interface{} = int(3) + var j I = myint(3) + var x interface{} = float64(3) + var y I = myfloat(3) + + println(f[int](i)) + shouldpanic(func() { f[int](x) }) + println(f2[int](i)) + println(f2[int](x)) + + println(g[myint](j)) + shouldpanic(func() { g[myint](y) }) + println(g2[myint](j)) + println(g2[myint](y)) + + println(h[int](struct{ a, b int }{3, 5}).a) + + println(k[int](mybar(3)).bar()) + + type large struct {a,b,c,d,e,f int} + println(f[large](large{}).a) + l2, ok := f2[large](large{}) + println(l2.a, ok) +} +func shouldpanic(x func()) { + defer func() { + e := recover() + if e == nil { + panic("didn't panic") + } + }() + x() +} diff --git a/test/typeparam/dottype.out b/test/typeparam/dottype.out new file mode 100644 index 0000000..8e6a3c2 --- /dev/null +++ b/test/typeparam/dottype.out @@ -0,0 +1,10 @@ +3 +3 true +0 false +3 +3 true +0 false +3 +3 +0 +0 true diff --git a/test/typeparam/double.go b/test/typeparam/double.go new file mode 100644 index 0000000..fbbe602 --- /dev/null +++ b/test/typeparam/double.go @@ -0,0 +1,72 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "reflect" +) + +type Number interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 +} + +type MySlice []int +type MyFloatSlice []float64 + +type _SliceOf[E any] interface { + ~[]E +} + +func _DoubleElems[S _SliceOf[E], E Number](s S) S { + r := make(S, len(s)) + for i, v := range s { + r[i] = v + v + } + return r +} + +// Test use of untyped constant in an expression with a generically-typed parameter +func _DoubleElems2[S _SliceOf[E], E Number](s S) S { + r := make(S, len(s)) + for i, v := range s { + r[i] = v * 2 + } + return r +} + +func main() { + arg := MySlice{1, 2, 3} + want := MySlice{2, 4, 6} + got := _DoubleElems[MySlice, int](arg) + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + // constraint type inference + got = _DoubleElems[MySlice](arg) + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + got = _DoubleElems(arg) + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + farg := MyFloatSlice{1.2, 2.0, 3.5} + fwant := MyFloatSlice{2.4, 4.0, 7.0} + fgot := _DoubleElems(farg) + if !reflect.DeepEqual(fgot, fwant) { + panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) + } + + fgot = _DoubleElems2(farg) + if !reflect.DeepEqual(fgot, fwant) { + panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) + } +} diff --git a/test/typeparam/eface.go b/test/typeparam/eface.go new file mode 100644 index 0000000..05d5503 --- /dev/null +++ b/test/typeparam/eface.go @@ -0,0 +1,67 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Make sure we handle instantiated empty interfaces. + +package main + +type E[T any] interface { +} + +//go:noinline +func f[T any](x E[T]) interface{} { + return x +} + +//go:noinline +func g[T any](x interface{}) E[T] { + return x +} + +type I[T any] interface { + foo() +} + +type myint int + +func (x myint) foo() {} + +//go:noinline +func h[T any](x I[T]) interface{ foo() } { + return x +} + +//go:noinline +func i[T any](x interface{ foo() }) I[T] { + return x +} + +func main() { + if f[int](1) != 1 { + println("test 1 failed") + } + if f[int](2) != (interface{})(2) { + println("test 2 failed") + } + if g[int](3) != 3 { + println("test 3 failed") + } + if g[int](4) != (E[int])(4) { + println("test 4 failed") + } + if h[int](myint(5)) != myint(5) { + println("test 5 failed") + } + if h[int](myint(6)) != interface{ foo() }(myint(6)) { + println("test 6 failed") + } + if i[int](myint(7)) != myint(7) { + println("test 7 failed") + } + if i[int](myint(8)) != I[int](myint(8)) { + println("test 8 failed") + } +} diff --git a/test/typeparam/equal.go b/test/typeparam/equal.go new file mode 100644 index 0000000..21e2103 --- /dev/null +++ b/test/typeparam/equal.go @@ -0,0 +1,69 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// comparisons of type parameters to interfaces + +package main + +func f[T comparable](t, u T) bool { + // Comparing two type parameters directly. + // (Not really testing comparisons to interfaces, but just 'cause we're here.) + return t == u +} + +func g[T comparable](t T, i interface{}) bool { + // Compare type parameter value to empty interface. + return t == i +} + +type I interface { + foo() +} + +type C interface { + comparable + I +} + +func h[T C](t T, i I) bool { + // Compare type parameter value to nonempty interface. + return t == i +} + +type myint int + +func (x myint) foo() { +} + +func k[T comparable](t T, i interface{}) bool { + // Compare derived type value to interface. + return struct{ a, b T }{t, t} == i +} + +func main() { + assert(f(3, 3)) + assert(!f(3, 5)) + assert(g(3, 3)) + assert(!g(3, 5)) + assert(h(myint(3), myint(3))) + assert(!h(myint(3), myint(5))) + + type S struct{ a, b float64 } + + assert(f(S{3, 5}, S{3, 5})) + assert(!f(S{3, 5}, S{4, 6})) + assert(g(S{3, 5}, S{3, 5})) + assert(!g(S{3, 5}, S{4, 6})) + + assert(k(3, struct{ a, b int }{3, 3})) + assert(!k(3, struct{ a, b int }{3, 4})) +} + +func assert(b bool) { + if !b { + panic("assertion failed") + } +} diff --git a/test/typeparam/fact.go b/test/typeparam/fact.go new file mode 100644 index 0000000..3c9a13a --- /dev/null +++ b/test/typeparam/fact.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +func fact[T interface{ ~int | ~int64 | ~float64 }](n T) T { + if n == 1 { + return 1 + } + return n * fact(n-1) +} + +func main() { + const want = 120 + + if got := fact(5); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := fact[int64](5); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := fact(5.0); got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } +} diff --git a/test/typeparam/factimp.dir/a.go b/test/typeparam/factimp.dir/a.go new file mode 100644 index 0000000..0bd73a8 --- /dev/null +++ b/test/typeparam/factimp.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func Fact[T interface{ int | int64 | float64 }](n T) T { + if n == 1 { + return 1 + } + return n * Fact(n-1) +} diff --git a/test/typeparam/factimp.dir/main.go b/test/typeparam/factimp.dir/main.go new file mode 100644 index 0000000..75e08da --- /dev/null +++ b/test/typeparam/factimp.dir/main.go @@ -0,0 +1,26 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + const want = 120 + + if got := a.Fact(5); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Fact[int64](5); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Fact(5.0); got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } +} diff --git a/test/typeparam/factimp.go b/test/typeparam/factimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/factimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/gencrawler.dir/a.go b/test/typeparam/gencrawler.dir/a.go new file mode 100644 index 0000000..50d6b4a --- /dev/null +++ b/test/typeparam/gencrawler.dir/a.go @@ -0,0 +1,27 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +var V val[int] + +type val[T any] struct { + valx T +} + +func (v *val[T]) Print() { + v.print1() +} + +func (v *val[T]) print1() { + println(v.valx) +} + +func (v *val[T]) fnprint1() { + println(v.valx) +} + +func FnPrint[T any](v *val[T]) { + v.fnprint1() +} diff --git a/test/typeparam/gencrawler.dir/main.go b/test/typeparam/gencrawler.dir/main.go new file mode 100644 index 0000000..198d117 --- /dev/null +++ b/test/typeparam/gencrawler.dir/main.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + a.V.Print() + a.FnPrint(&a.V) +} diff --git a/test/typeparam/gencrawler.go b/test/typeparam/gencrawler.go new file mode 100644 index 0000000..66b5f43 --- /dev/null +++ b/test/typeparam/gencrawler.go @@ -0,0 +1,10 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Testing that all methods of a private generic type are exported, if a variable +// with that type is exported. + +package ignored diff --git a/test/typeparam/gencrawler.out b/test/typeparam/gencrawler.out new file mode 100644 index 0000000..aa47d0d --- /dev/null +++ b/test/typeparam/gencrawler.out @@ -0,0 +1,2 @@ +0 +0 diff --git a/test/typeparam/genembed.go b/test/typeparam/genembed.go new file mode 100644 index 0000000..6a11be1 --- /dev/null +++ b/test/typeparam/genembed.go @@ -0,0 +1,52 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test wrappers/interfaces for generic type embedding another generic type. + +package main + +import "fmt" + +type A[T any] struct { + B[T] +} + +type B[T any] struct { + val T +} + +func (b *B[T]) get() T { + return b.val +} + +type getter[T any] interface { + get() T +} + +//go:noinline +func doGet[T any](i getter[T]) T { + return i.get() +} + +//go:noline +func doGet2[T any](i interface{}) T { + i2 := i.(getter[T]) + return i2.get() +} + +func main() { + a := A[int]{B: B[int]{3}} + var i getter[int] = &a + + if got, want := doGet(i), 3; got != want { + panic(fmt.Sprintf("got %v, want %v", got, want)) + } + + as := A[string]{B: B[string]{"abc"}} + if got, want := doGet2[string](&as), "abc"; got != want { + panic(fmt.Sprintf("got %v, want %v", got, want)) + } +} diff --git a/test/typeparam/genembed2.go b/test/typeparam/genembed2.go new file mode 100644 index 0000000..f75731f --- /dev/null +++ b/test/typeparam/genembed2.go @@ -0,0 +1,46 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test for declaration and use of a parameterized embedded field. + +package main + +import ( + "fmt" + "sync" +) + +type MyStruct[T any] struct { + val T +} + +type Lockable[T any] struct { + MyStruct[T] + mu sync.Mutex +} + +// Get returns the value stored in a Lockable. +func (l *Lockable[T]) Get() T { + l.mu.Lock() + defer l.mu.Unlock() + return l.MyStruct.val +} + +// Set sets the value in a Lockable. +func (l *Lockable[T]) Set(v T) { + l.mu.Lock() + defer l.mu.Unlock() + l.MyStruct = MyStruct[T]{v} +} + +func main() { + var li Lockable[int] + + li.Set(5) + if got, want := li.Get(), 5; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/geninline.dir/a.go b/test/typeparam/geninline.dir/a.go new file mode 100644 index 0000000..fe5ba22 --- /dev/null +++ b/test/typeparam/geninline.dir/a.go @@ -0,0 +1,56 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type IVal[T comparable] interface { + check(want T) +} + +type Val[T comparable] struct { + val T +} + +//go:noinline +func (l *Val[T]) check(want T) { + if l.val != want { + panic("hi") + } +} + +func Test1() { + var l Val[int] + if l.val != 0 { + panic("hi") + } + _ = IVal[int](&l) +} + +func Test2() { + var l Val[float64] + l.val = 3.0 + l.check(float64(3)) + _ = IVal[float64](&l) +} + +type privateVal[T comparable] struct { + val T +} + +//go:noinline +func (l *privateVal[T]) check(want T) { + if l.val != want { + panic("hi") + } +} + +type Outer struct { + val privateVal[string] +} + +func Test3() { + var o Outer + o.val.check("") + _ = IVal[string](&o.val) +} diff --git a/test/typeparam/geninline.dir/main.go b/test/typeparam/geninline.dir/main.go new file mode 100644 index 0000000..cfc4885 --- /dev/null +++ b/test/typeparam/geninline.dir/main.go @@ -0,0 +1,16 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +// Testing inlining of functions that refer to instantiated exported and non-exported +// generic types. + +func main() { + a.Test1() + a.Test2() + a.Test3() +} diff --git a/test/typeparam/geninline.go b/test/typeparam/geninline.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/geninline.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/graph.go b/test/typeparam/graph.go new file mode 100644 index 0000000..5cd1faa --- /dev/null +++ b/test/typeparam/graph.go @@ -0,0 +1,230 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "errors" + "fmt" +) + +// _Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func _SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// A Graph is a collection of nodes. A node may have an arbitrary number +// of edges. An edge connects two nodes. Both nodes and edges must be +// comparable. This is an undirected simple graph. +type _Graph[_Node _NodeC[_Edge], _Edge _EdgeC[_Node]] struct { + nodes []_Node +} + +// _NodeC is the constraints on a node in a graph, given the _Edge type. +type _NodeC[_Edge any] interface { + comparable + Edges() []_Edge +} + +// Edgec is the constraints on an edge in a graph, given the _Node type. +type _EdgeC[_Node any] interface { + comparable + Nodes() (a, b _Node) +} + +// _New creates a new _Graph from a collection of Nodes. +func _New[_Node _NodeC[_Edge], _Edge _EdgeC[_Node]](nodes []_Node) *_Graph[_Node, _Edge] { + return &_Graph[_Node, _Edge]{nodes: nodes} +} + +// nodePath holds the path to a node during ShortestPath. +// This should ideally be a type defined inside ShortestPath, +// but the translator tool doesn't support that. +type nodePath[_Node _NodeC[_Edge], _Edge _EdgeC[_Node]] struct { + node _Node + path []_Edge +} + +// ShortestPath returns the shortest path between two nodes, +// as an ordered list of edges. If there are multiple shortest paths, +// which one is returned is unpredictable. +func (g *_Graph[_Node, _Edge]) ShortestPath(from, to _Node) ([]_Edge, error) { + visited := make(map[_Node]bool) + visited[from] = true + workqueue := []nodePath[_Node, _Edge]{nodePath[_Node, _Edge]{from, nil}} + for len(workqueue) > 0 { + current := workqueue + workqueue = nil + for _, np := range current { + edges := np.node.Edges() + for _, edge := range edges { + a, b := edge.Nodes() + if a == np.node { + a = b + } + if !visited[a] { + ve := append([]_Edge(nil), np.path...) + ve = append(ve, edge) + if a == to { + return ve, nil + } + workqueue = append(workqueue, nodePath[_Node, _Edge]{a, ve}) + visited[a] = true + } + } + } + } + return nil, errors.New("no path") +} + +type direction int + +const ( + north direction = iota + ne + east + se + south + sw + west + nw + up + down +) + +func (dir direction) String() string { + strs := map[direction]string{ + north: "north", + ne: "ne", + east: "east", + se: "se", + south: "south", + sw: "sw", + west: "west", + nw: "nw", + up: "up", + down: "down", + } + if str, ok := strs[dir]; ok { + return str + } + return fmt.Sprintf("direction %d", dir) +} + +type mazeRoom struct { + index int + exits [10]int +} + +type mazeEdge struct { + from, to int + dir direction +} + +// Edges returns the exits from the room. +func (m mazeRoom) Edges() []mazeEdge { + var r []mazeEdge + for i, exit := range m.exits { + if exit != 0 { + r = append(r, mazeEdge{ + from: m.index, + to: exit, + dir: direction(i), + }) + } + } + return r +} + +// Nodes returns the rooms connected by an edge. +//go:noinline +func (e mazeEdge) Nodes() (mazeRoom, mazeRoom) { + m1, ok := zork[e.from] + if !ok { + panic("bad edge") + } + m2, ok := zork[e.to] + if !ok { + panic("bad edge") + } + return m1, m2 +} + +// The first maze in Zork. Room indexes based on original Fortran data file. +// You are in a maze of twisty little passages, all alike. +var zork = map[int]mazeRoom{ + 11: {exits: [10]int{north: 11, south: 12, east: 14}}, // west to Troll Room + 12: {exits: [10]int{south: 11, north: 14, east: 13}}, + 13: {exits: [10]int{west: 12, north: 14, up: 16}}, + 14: {exits: [10]int{west: 13, north: 11, east: 15}}, + 15: {exits: [10]int{south: 14}}, // Dead End + 16: {exits: [10]int{east: 17, north: 13, sw: 18}}, // skeleton, etc. + 17: {exits: [10]int{west: 16}}, // Dead End + 18: {exits: [10]int{down: 16, east: 19, west: 18, up: 22}}, + 19: {exits: [10]int{up: 29, west: 18, ne: 15, east: 20, south: 30}}, + 20: {exits: [10]int{ne: 19, west: 20, se: 21}}, + 21: {exits: [10]int{north: 20}}, // Dead End + 22: {exits: [10]int{north: 18, east: 24, down: 23, south: 28, west: 26, nw: 22}}, + 23: {exits: [10]int{east: 22, west: 28, up: 24}}, + 24: {exits: [10]int{ne: 25, down: 23, nw: 28, sw: 26}}, + 25: {exits: [10]int{sw: 24}}, // Grating room (up to Clearing) + 26: {exits: [10]int{west: 16, sw: 24, east: 28, up: 22, north: 27}}, + 27: {exits: [10]int{south: 26}}, // Dead End + 28: {exits: [10]int{east: 22, down: 26, south: 23, west: 24}}, + 29: {exits: [10]int{west: 30, nw: 29, ne: 19, south: 19}}, + 30: {exits: [10]int{west: 29, south: 19}}, // ne to Cyclops Room +} + +func TestShortestPath() { + // The Zork maze is not a proper undirected simple graph, + // as there are some one way paths (e.g., 19 -> 15), + // but for this test that doesn't matter. + + // Set the index field in the map. Simpler than doing it in the + // composite literal. + for k := range zork { + r := zork[k] + r.index = k + zork[k] = r + } + + var nodes []mazeRoom + for idx, room := range zork { + mridx := room + mridx.index = idx + nodes = append(nodes, mridx) + } + g := _New[mazeRoom, mazeEdge](nodes) + path, err := g.ShortestPath(zork[11], zork[30]) + if err != nil { + panic(fmt.Sprintf("%v", err)) + } + var steps []direction + for _, edge := range path { + steps = append(steps, edge.dir) + } + want := []direction{east, west, up, sw, east, south} + if !_SliceEqual(steps, want) { + panic(fmt.Sprintf("ShortestPath returned %v, want %v", steps, want)) + } +} + +func main() { + TestShortestPath() +} diff --git a/test/typeparam/ifaceconv.go b/test/typeparam/ifaceconv.go new file mode 100644 index 0000000..4dfc68f --- /dev/null +++ b/test/typeparam/ifaceconv.go @@ -0,0 +1,83 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that we can convert type parameters to both empty +// and nonempty interfaces, and named and nonnamed versions +// thereof. + +package main + +import "fmt" + +type E interface{} + +func f[T any](x T) interface{} { + var i interface{} = x + return i +} + +func fs[T any](x T) interface{} { + y := []T{x} + var i interface{} = y + return i +} + +func g[T any](x T) E { + var i E = x + return i +} + +type C interface { + foo() int +} + +type myInt int + +func (x myInt) foo() int { + return int(x + 1) +} + +func h[T C](x T) interface{ foo() int } { + var i interface{ foo() int } = x + return i +} +func i[T C](x T) C { + var i C = x // conversion in assignment + return i +} + +func j[T C](t T) C { + return C(t) // explicit conversion +} + +func js[T any](x T) interface{} { + y := []T{x} + return interface{}(y) +} + +func main() { + if got, want := f[int](7), 7; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := fs[int](7), []int{7}; got.([]int)[0] != want[0] { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := g[int](7), 7; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := h[myInt](7).foo(), 8; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := i[myInt](7).foo(), 8; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := j[myInt](7).foo(), 8; got != want { + panic(fmt.Sprintf("got %d want %d", got, want)) + } + if got, want := js[int](7), []int{7}; got.([]int)[0] != want[0] { + panic(fmt.Sprintf("got %d want %d", got, want)) + } +} diff --git a/test/typeparam/importtest.go b/test/typeparam/importtest.go new file mode 100644 index 0000000..a49dcd9 --- /dev/null +++ b/test/typeparam/importtest.go @@ -0,0 +1,16 @@ +// compile + +// 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 checks that basic importing works in -G mode. + +package p + +import "fmt" +import "math" + +func f(x float64) { + fmt.Println(math.Sin(x)) +} diff --git a/test/typeparam/index.go b/test/typeparam/index.go new file mode 100644 index 0000000..064d33c --- /dev/null +++ b/test/typeparam/index.go @@ -0,0 +1,81 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +// Index returns the index of x in s, or -1 if not found. +func Index[T comparable](s []T, x T) int { + for i, v := range s { + // v and x are type T, which has the comparable + // constraint, so we can use == here. + if v == x { + return i + } + } + return -1 +} + +type obj struct { + x int +} + +type obj2 struct { + x int8 + y float64 +} + +type obj3 struct { + x int64 + y int8 +} + +type inner struct { + y int64 + z int32 +} + +type obj4 struct { + x int32 + s inner +} + +func main() { + want := 2 + + vec1 := []string{"ab", "cd", "ef"} + if got := Index(vec1, "ef"); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + vec2 := []byte{'c', '6', '@'} + if got := Index(vec2, '@'); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + vec3 := []*obj{&obj{2}, &obj{42}, &obj{1}} + if got := Index(vec3, vec3[2]); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + vec4 := []obj2{obj2{2, 3.0}, obj2{3, 4.0}, obj2{4, 5.0}} + if got := Index(vec4, vec4[2]); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + vec5 := []obj3{obj3{2, 3}, obj3{3, 4}, obj3{4, 5}} + if got := Index(vec5, vec5[2]); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + vec6 := []obj4{obj4{2, inner{3, 4}}, obj4{3, inner{4, 5}}, obj4{4, inner{5, 6}}} + if got := Index(vec6, vec6[2]); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/index2.go b/test/typeparam/index2.go new file mode 100644 index 0000000..ae1b44a --- /dev/null +++ b/test/typeparam/index2.go @@ -0,0 +1,67 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Testing various generic uses of indexing, both for reads and writes. + +package main + +import "fmt" + +// Can index an argument (read/write) constrained to be a slice or an array. +func Index1[T interface{ []int64 | [5]int64 }](x T) int64 { + x[2] = 5 + return x[3] +} + +// Can index an argument (read) constrained to be a byte array or a string. +func Index2[T interface{ []byte | string }](x T) byte { + return x[3] +} + +// Can index an argument (write) constrained to be a byte array, but not a string. +func Index2a[T interface{ []byte }](x T) byte { + x[2] = 'b' + return x[3] +} + +// Can index an argument (read/write) constrained to be a map. Maps can't +// be combined with any other type for indexing purposes. +func Index3[T interface{ map[int]int64 }](x T) int64 { + x[2] = 43 + return x[3] +} + +// But the type of the map keys or values can be parameterized. +func Index4[T any](x map[int]T) T { + var zero T + x[2] = zero + return x[3] +} + +func test[T comparable](got, want T) { + if got != want { + panic(fmt.Sprintf("got %v, want %v", got, want)) + } +} + +func main() { + x := make([]int64, 4) + x[3] = 2 + y := [5]int64{1, 2, 3, 4, 5} + z := "abcd" + w := make([]byte, 4) + w[3] = 5 + v := make(map[int]int64) + v[3] = 18 + + test(Index1(x), int64(2)) + test(Index1(y), int64(4)) + test(Index2(z), byte(100)) + test(Index2(w), byte(5)) + test(Index2a(w), byte(5)) + test(Index3(v), int64(18)) + test(Index4(v), int64(18)) +} diff --git a/test/typeparam/interfacearg.go b/test/typeparam/interfacearg.go new file mode 100644 index 0000000..0e1fd00 --- /dev/null +++ b/test/typeparam/interfacearg.go @@ -0,0 +1,46 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I interface{} + +type _S[T any] struct { + x *T +} + +// F is a non-generic function, but has a type _S[I] which is instantiated from a +// generic type. Test that _S[I] is successfully exported. +func F() { + v := _S[I]{} + if v.x != nil { + panic(v) + } +} + +// Testing the various combinations of method expressions. +type S1 struct{} + +func (*S1) M() {} + +type S2 struct{} + +func (S2) M() {} + +func _F1[T interface{ M() }](t T) { + _ = T.M +} + +func F2() { + _F1(&S1{}) + _F1(S2{}) + _F1(&S2{}) +} + +func main() { + F() + F2() +} diff --git a/test/typeparam/issue23536.go b/test/typeparam/issue23536.go new file mode 100644 index 0000000..1d6d79b --- /dev/null +++ b/test/typeparam/issue23536.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2022 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 case where a slice of a user-defined byte type (not uint8 or byte) is +// converted to a string. Same for slice of runes. + +package main + +type MyByte byte + +type MyRune rune + +func f[T []MyByte](x T) string { + return string(x) +} + +func g[T []MyRune](x T) string { + return string(x) +} + +func main() { + var y []MyByte + _ = f(y) + _ = string(y) + + var z []MyRune + _ = g(z) + _ = string(z) +} diff --git a/test/typeparam/issue376214.go b/test/typeparam/issue376214.go new file mode 100644 index 0000000..269b684 --- /dev/null +++ b/test/typeparam/issue376214.go @@ -0,0 +1,20 @@ +// run + +// Copyright 2022 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 main + +func add[S ~string | ~[]byte](buf *[]byte, s S) { + *buf = append(*buf, s...) +} + +func main() { + var buf []byte + add(&buf, "foo") + add(&buf, []byte("bar")) + if string(buf) != "foobar" { + panic("got " + string(buf)) + } +} diff --git a/test/typeparam/issue39755.go b/test/typeparam/issue39755.go new file mode 100644 index 0000000..52c7e7c --- /dev/null +++ b/test/typeparam/issue39755.go @@ -0,0 +1,27 @@ +// compile + +// 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. + +// copied from cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go + +package p + +func _[T interface{ ~map[string]int }](x T) { + _ = x == nil +} + +// simplified test case from issue + +type PathParamsConstraint interface { + ~map[string]string | ~[]struct{ key, value string } +} + +type PathParams[T PathParamsConstraint] struct { + t T +} + +func (pp *PathParams[T]) IsNil() bool { + return pp.t == nil // this must succeed +} diff --git a/test/typeparam/issue42758.go b/test/typeparam/issue42758.go new file mode 100644 index 0000000..25fb85f --- /dev/null +++ b/test/typeparam/issue42758.go @@ -0,0 +1,19 @@ +// run + +// Copyright 2022 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 main + +func F[T, U int]() interface{} { + switch interface{}(nil) { + case int(0), T(0), U(0): + } + + return map[interface{}]int{int(0): 0, T(0): 0, U(0): 0} +} + +func main() { + F[int, int]() +} diff --git a/test/typeparam/issue44688.go b/test/typeparam/issue44688.go new file mode 100644 index 0000000..48160e0 --- /dev/null +++ b/test/typeparam/issue44688.go @@ -0,0 +1,149 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// derived & expanded from cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go2 + +package main + +type A1[T any] struct { + val T +} + +func (p *A1[T]) m1(val T) { + p.val = val +} + +type A2[T any] interface { + m2(T) +} + +type B1[T any] struct { + filler int + *A1[T] + A2[T] +} + +type B2[T any] interface { + A2[T] +} + +type ImpA2[T any] struct { + f T +} + +func (a2 *ImpA2[T]) m2(s T) { + a2.f = s +} + +type C[T any] struct { + filler1 int + filler2 int + B1[T] +} + +type D[T any] struct { + filler1 int + filler2 int + filler3 int + C[T] +} + +func test1[T any](arg T) { + // calling embedded methods + var b1 B1[T] + b1.A1 = &A1[T]{} + b1.A2 = &ImpA2[T]{} + + b1.A1.m1(arg) + b1.m1(arg) + + b1.A2.m2(arg) + b1.m2(arg) + + var b2 B2[T] + b2 = &ImpA2[T]{} + b2.m2(arg) + + // a deeper nesting + var d D[T] + d.C.B1.A1 = &A1[T]{} + d.C.B1.A2 = &ImpA2[T]{} + d.m1(arg) + d.m2(arg) + + // calling method expressions + m1x := B1[T].m1 + m1x(b1, arg) + // TODO(khr): reenable these. + //m2x := B2[T].m2 + //m2x(b2, arg) + + // calling method values + m1v := b1.m1 + m1v(arg) + m2v := b1.m2 + m2v(arg) + b2v := b2.m2 + b2v(arg) +} + +func test2() { + // calling embedded methods + var b1 B1[string] + b1.A1 = &A1[string]{} + b1.A2 = &ImpA2[string]{} + + b1.A1.m1("") + b1.m1("") + + b1.A2.m2("") + b1.m2("") + + var b2 B2[string] + b2 = &ImpA2[string]{} + b2.m2("") + + // a deeper nesting + var d D[string] + d.C.B1.A1 = &A1[string]{} + d.C.B1.A2 = &ImpA2[string]{} + d.m1("") + d.m2("") + + // calling method expressions + m1x := B1[string].m1 + m1x(b1, "") + m2x := B2[string].m2 + m2x(b2, "") + + // calling method values + m1v := b1.m1 + m1v("") + m2v := b1.m2 + m2v("") + b2v := b2.m2 + b2v("") +} + +// actual test case from issue + +type A[T any] struct{} + +func (*A[T]) f(T) {} + +type B[T any] struct{ A[T] } + +func test3() { + var b B[string] + b.A.f("") + b.f("") +} + +func main() { + test1[string]("") + test2() + test3() +} diff --git a/test/typeparam/issue45547.go b/test/typeparam/issue45547.go new file mode 100644 index 0000000..0024f36 --- /dev/null +++ b/test/typeparam/issue45547.go @@ -0,0 +1,20 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f[T any]() (f, g T) { return f, g } + +// Tests for generic function instantiation on the right hande side of multi-value +// assignments. + +func g() { + // Multi-value assignment within a function + var _, _ = f[int]() +} + +// Multi-value assignment outside a function. +var _, _ = f[int]() diff --git a/test/typeparam/issue45722.go b/test/typeparam/issue45722.go new file mode 100644 index 0000000..52a3c63 --- /dev/null +++ b/test/typeparam/issue45722.go @@ -0,0 +1,34 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "log" +) + +func try[T any](v T, err error) T { + if err != nil { + panic(err) + } + return v +} + +func handle(handle func(error)) { + if issue := recover(); issue != nil { + if e, ok := issue.(error); ok && e != nil { + handle(e) + } else { + handle(fmt.Errorf("%v", e)) + } + } +} + +func main() { + defer handle(func(e error) { log.Fatalln(e) }) + _ = try(fmt.Print("")) +} diff --git a/test/typeparam/issue45738.go b/test/typeparam/issue45738.go new file mode 100644 index 0000000..89b3b11 --- /dev/null +++ b/test/typeparam/issue45738.go @@ -0,0 +1,18 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +//go:noinline +func f[T any]() { + x := 5 + g := func() int { return x } + g() +} + +func main() { + f[int]() +} diff --git a/test/typeparam/issue45817.go b/test/typeparam/issue45817.go new file mode 100644 index 0000000..78e472f --- /dev/null +++ b/test/typeparam/issue45817.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type s[T any] struct { + a T +} + +func (x s[T]) f() T { + return x.a +} +func main() { + x := s[int]{a: 7} + f := x.f + if got, want := f(), 7; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/issue46461.go b/test/typeparam/issue46461.go new file mode 100644 index 0000000..363a87c --- /dev/null +++ b/test/typeparam/issue46461.go @@ -0,0 +1,13 @@ +// errorcheck + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type T[U interface{ M() T[U] }] int // ERROR "invalid recursive type: T refers to itself" + +type X int + +func (X) M() T[X] { return 0 } diff --git a/test/typeparam/issue46461b.dir/a.go b/test/typeparam/issue46461b.dir/a.go new file mode 100644 index 0000000..fcb4142 --- /dev/null +++ b/test/typeparam/issue46461b.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type T[U interface{ M() int }] int diff --git a/test/typeparam/issue46461b.dir/b.go b/test/typeparam/issue46461b.dir/b.go new file mode 100644 index 0000000..a458325 --- /dev/null +++ b/test/typeparam/issue46461b.dir/b.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +type X int + +func (X) M() int { return 0 } + +type _ a.T[X] diff --git a/test/typeparam/issue46461b.go b/test/typeparam/issue46461b.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue46461b.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue46472.go b/test/typeparam/issue46472.go new file mode 100644 index 0000000..027a8aa --- /dev/null +++ b/test/typeparam/issue46472.go @@ -0,0 +1,20 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func foo[T any](d T) { + switch v := interface{}(d).(type) { + case string: + if v != "x" { + panic("unexpected v: " + v) + } + } + +} +func main() { + foo("x") +} diff --git a/test/typeparam/issue46591.go b/test/typeparam/issue46591.go new file mode 100644 index 0000000..9e2c31d --- /dev/null +++ b/test/typeparam/issue46591.go @@ -0,0 +1,22 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type T[_ any] struct{} + +var m = map[interface{}]int{ + T[struct{ int }]{}: 0, + T[struct { + int "x" + }]{}: 0, +} + +func main() { + if len(m) != 2 { + panic(len(m)) + } +} diff --git a/test/typeparam/issue47258.go b/test/typeparam/issue47258.go new file mode 100644 index 0000000..7b202c9 --- /dev/null +++ b/test/typeparam/issue47258.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type Numeric interface { + int32 | int64 | float64 | complex64 +} + +//go:noline +func inc[T Numeric](x T) T { + x++ + return x +} +func main() { + if got, want := inc(int32(5)), int32(6); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := inc(float64(5)), float64(6.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := inc(complex64(5)), complex64(6.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/issue47272.go b/test/typeparam/issue47272.go new file mode 100644 index 0000000..79748ad --- /dev/null +++ b/test/typeparam/issue47272.go @@ -0,0 +1,55 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "errors" + "fmt" +) + +type Option[T any] struct { + ok bool + val T +} + +func (o Option[T]) String() string { + if o.ok { + return fmt.Sprintf("Some(%v)", o.val) + } + return "None" +} + +func Some[T any](val T) Option[T] { return Option[T]{ok: true, val: val} } +func None[T any]() Option[T] { return Option[T]{ok: false} } + +type Result[T, E any] struct { + ok bool + val T + err E +} + +func (r Result[T, E]) String() string { + if r.ok { + return fmt.Sprintf("Ok(%v)", r.val) + } + return fmt.Sprintf("Err(%v)", r.err) +} + +func Ok[T, E any](val T) Result[T, E] { return Result[T, E]{ok: true, val: val} } +func Err[T, E any](err E) Result[T, E] { return Result[T, E]{ok: false, err: err} } + +func main() { + a := Some[int](1) + b := None[int]() + fmt.Println(a, b) + + x := Ok[int, error](1) + y := Err[int, error](errors.New("test")) + fmt.Println(x, y) + // fmt.Println(x) + _, _, _, _ = a, b, x, y +} diff --git a/test/typeparam/issue47272.out b/test/typeparam/issue47272.out new file mode 100644 index 0000000..9c433fa --- /dev/null +++ b/test/typeparam/issue47272.out @@ -0,0 +1,2 @@ +Some(1) None +Ok(1) Err(test) diff --git a/test/typeparam/issue47514.go b/test/typeparam/issue47514.go new file mode 100644 index 0000000..1fc054e --- /dev/null +++ b/test/typeparam/issue47514.go @@ -0,0 +1,20 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that closures inside a generic function are not exported, +// even though not themselves generic. + +package main + +func Do[T any]() { + _ = func() string { + return "" + } +} + +func main() { + Do[int]() +} diff --git a/test/typeparam/issue47514b.go b/test/typeparam/issue47514b.go new file mode 100644 index 0000000..0609296 --- /dev/null +++ b/test/typeparam/issue47514b.go @@ -0,0 +1,19 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func Do[T any](do func() (T, string)) { + _ = func() (T, string) { + return do() + } +} + +func main() { + Do[int](func() (int, string) { + return 3, "3" + }) +} diff --git a/test/typeparam/issue47514c.dir/a.go b/test/typeparam/issue47514c.dir/a.go new file mode 100644 index 0000000..782b1d2 --- /dev/null +++ b/test/typeparam/issue47514c.dir/a.go @@ -0,0 +1,5 @@ +package a + +type Doer[T any] interface { + Do() T +} diff --git a/test/typeparam/issue47514c.dir/main.go b/test/typeparam/issue47514c.dir/main.go new file mode 100644 index 0000000..0ef423f --- /dev/null +++ b/test/typeparam/issue47514c.dir/main.go @@ -0,0 +1,10 @@ +package main + +import "./a" + +func Do[T any](doer a.Doer[T]) { + doer.Do() +} + +func main() { +} diff --git a/test/typeparam/issue47514c.go b/test/typeparam/issue47514c.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue47514c.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue47631.go b/test/typeparam/issue47631.go new file mode 100644 index 0000000..32fd837 --- /dev/null +++ b/test/typeparam/issue47631.go @@ -0,0 +1,31 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func g[T any]() { + type U []T + type V []int +} + +type S[T any] struct { +} + +func (s S[T]) m() { + type U []T + type V []int +} + +func f() { + type U []int +} + +type X struct { +} + +func (x X) m() { + type U []int +} diff --git a/test/typeparam/issue47676.go b/test/typeparam/issue47676.go new file mode 100644 index 0000000..8569378 --- /dev/null +++ b/test/typeparam/issue47676.go @@ -0,0 +1,23 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + d := diff([]int{}, func(int) string { + return "foo" + }) + d() +} + +func diff[T any](previous []T, uniqueKey func(T) string) func() { + return func() { + newJSON := map[string]T{} + for _, prev := range previous { + delete(newJSON, uniqueKey(prev)) + } + } +} diff --git a/test/typeparam/issue47684.go b/test/typeparam/issue47684.go new file mode 100644 index 0000000..f0e4ed0 --- /dev/null +++ b/test/typeparam/issue47684.go @@ -0,0 +1,19 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[G any]() int { + return func() int { + return func() int { + return 0 + }() + }() +} + +func main() { + f[int]() +} diff --git a/test/typeparam/issue47684b.go b/test/typeparam/issue47684b.go new file mode 100644 index 0000000..3e9fa93 --- /dev/null +++ b/test/typeparam/issue47684b.go @@ -0,0 +1,23 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[G any]() interface{} { + return func() interface{} { + return func() interface{} { + var x G + return x + }() + }() +} + +func main() { + x := f[int]() + if v, ok := x.(int); !ok || v != 0 { + panic("bad") + } +} diff --git a/test/typeparam/issue47684c.go b/test/typeparam/issue47684c.go new file mode 100644 index 0000000..b1d4520 --- /dev/null +++ b/test/typeparam/issue47684c.go @@ -0,0 +1,19 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[G any]() func()func()int { + return func() func()int { + return func() int { + return 0 + } + } +} + +func main() { + f[int]()()() +} diff --git a/test/typeparam/issue47708.go b/test/typeparam/issue47708.go new file mode 100644 index 0000000..d6140f3 --- /dev/null +++ b/test/typeparam/issue47708.go @@ -0,0 +1,37 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type FooType[T any] interface { + Foo(BarType[T]) string +} +type BarType[T any] interface { + Bar(FooType[T]) string +} + +// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). +// type Baz[T any] T +// func (l Baz[T]) Foo(v BarType[T]) string { +// return v.Bar(l) +// } +// type Bob[T any] T +// func (l Bob[T]) Bar(v FooType[T]) string { +// if v,ok := v.(Baz[T]);ok{ +// return fmt.Sprintf("%v%v",v,l) +// } +// return "" +// } + +func main() { + // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). + // var baz Baz[int] = 123 + // var bob Bob[int] = 456 + // + // if got, want := baz.Foo(bob), "123456"; got != want { + // panic(fmt.Sprintf("got %s want %s", got, want)) + // } +} diff --git a/test/typeparam/issue47710.go b/test/typeparam/issue47710.go new file mode 100644 index 0000000..2263c8b --- /dev/null +++ b/test/typeparam/issue47710.go @@ -0,0 +1,19 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type FooType[t any] interface { + Foo(BarType[t]) +} +type BarType[t any] interface { + Int(IntType[t]) FooType[int] +} + +type IntType[t any] int + +func (n IntType[t]) Foo(BarType[t]) {} +func (n IntType[_]) String() {} diff --git a/test/typeparam/issue47713.go b/test/typeparam/issue47713.go new file mode 100644 index 0000000..7e3b5a5 --- /dev/null +++ b/test/typeparam/issue47713.go @@ -0,0 +1,52 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "encoding" + "fmt" +) + +type Seralizable interface { + encoding.BinaryMarshaler + encoding.BinaryUnmarshaler +} + +type SerDeString string + +func (s *SerDeString) UnmarshalBinary(in []byte) error { + *s = SerDeString(in) + return nil +} + +func (s SerDeString) MarshalBinary() ([]byte, error) { + return []byte(s), nil +} + + +type GenericSerializable[T Seralizable] struct { + Key string + Value T +} + +func (g GenericSerializable[T]) Send() { + out, err := g.Value.MarshalBinary() + if err != nil { + panic("bad") + } + var newval SerDeString + newval.UnmarshalBinary(out) + fmt.Printf("Sent %s\n", newval) +} + +func main() { + val := SerDeString("asdf") + x := GenericSerializable[*SerDeString]{ + Value: &val, + } + x.Send() +} diff --git a/test/typeparam/issue47713.out b/test/typeparam/issue47713.out new file mode 100644 index 0000000..a6e7719 --- /dev/null +++ b/test/typeparam/issue47713.out @@ -0,0 +1 @@ +Sent asdf diff --git a/test/typeparam/issue47716.go b/test/typeparam/issue47716.go new file mode 100644 index 0000000..5024ac9 --- /dev/null +++ b/test/typeparam/issue47716.go @@ -0,0 +1,68 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "unsafe" +) + +// size returns the size of type T +func size[T any](x T) uintptr { + return unsafe.Sizeof(x) +} + +// size returns the alignment of type T +func align[T any](x T) uintptr { + return unsafe.Alignof(x) +} + +type Tstruct[T any] struct { + f1 T + f2 int +} + +// offset returns the offset of field f2 in the generic type Tstruct +func (r *Tstruct[T]) offset() uintptr { + return unsafe.Offsetof(r.f2) +} + +func main() { + v1 := int(5) + if got, want := size(v1), unsafe.Sizeof(v1); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := align(v1), unsafe.Alignof(v1); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + v2 := "abc" + if got, want := size(v2), unsafe.Sizeof(v2); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := align(v2), unsafe.Alignof(v2); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + var v3 Tstruct[int] + if got, want := unsafe.Offsetof(v3.f2), unsafe.Sizeof(v1); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + var v4 Tstruct[interface{}] + var v5 interface{} + if got, want := unsafe.Offsetof(v4.f2), unsafe.Sizeof(v5); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got, want := v3.offset(), unsafe.Offsetof(v3.f2); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := v4.offset(), unsafe.Offsetof(v4.f2); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/issue47723.go b/test/typeparam/issue47723.go new file mode 100644 index 0000000..44c55b6 --- /dev/null +++ b/test/typeparam/issue47723.go @@ -0,0 +1,23 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[_ any]() int { + var a [1]int + _ = func() int { + return func() int { + return 0 + }() + }() + return a[func() int { + return 0 + }()] +} + +func main() { + f[int]() +} diff --git a/test/typeparam/issue47740.go b/test/typeparam/issue47740.go new file mode 100644 index 0000000..f34394c --- /dev/null +++ b/test/typeparam/issue47740.go @@ -0,0 +1,40 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +type Exp[Ty any] interface { + Eval() Ty +} + +// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). +// type Lit[Ty any] Ty +// +// func (lit Lit[Ty]) Eval() Ty { return Ty(lit) } +// func (lit Lit[Ty]) String() string { return fmt.Sprintf("(lit %v)", Ty(lit)) } + +type Eq[Ty any] struct { + a Exp[Ty] + b Exp[Ty] +} + +func (e Eq[Ty]) String() string { + return fmt.Sprintf("(eq %v %v)", e.a, e.b) +} + +// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). +// var ( +// e0 = Eq[int]{Lit[int](128), Lit[int](64)} +// e1 = Eq[bool]{Lit[bool](true), Lit[bool](true)} +// ) + +func main() { + // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). + // fmt.Printf("%v\n", e0) + // fmt.Printf("%v\n", e1) +} diff --git a/test/typeparam/issue47740.out b/test/typeparam/issue47740.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/typeparam/issue47740.out diff --git a/test/typeparam/issue47740b.go b/test/typeparam/issue47740b.go new file mode 100644 index 0000000..d46d058 --- /dev/null +++ b/test/typeparam/issue47740b.go @@ -0,0 +1,23 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "reflect" + +type S[T any] struct { + a interface{} +} + +func (e S[T]) M() { + v := reflect.ValueOf(e.a) + _, _ = v.Interface().(int) +} + +func main() { + e := S[int]{0} + e.M() +} diff --git a/test/typeparam/issue47775.dir/b.go b/test/typeparam/issue47775.dir/b.go new file mode 100644 index 0000000..b6d7ba9 --- /dev/null +++ b/test/typeparam/issue47775.dir/b.go @@ -0,0 +1,19 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +type C[T any] struct { +} + +func (c *C[T]) reset() { +} + +func New[T any]() { + c := &C[T]{} + z(c.reset) +} + +func z(interface{}) { +} diff --git a/test/typeparam/issue47775.dir/main.go b/test/typeparam/issue47775.dir/main.go new file mode 100644 index 0000000..5ec85a4 --- /dev/null +++ b/test/typeparam/issue47775.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./b" + +func main() { + b.New[int]() +} diff --git a/test/typeparam/issue47775.go b/test/typeparam/issue47775.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue47775.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue47775b.go b/test/typeparam/issue47775b.go new file mode 100644 index 0000000..e084e03 --- /dev/null +++ b/test/typeparam/issue47775b.go @@ -0,0 +1,28 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type C[T any] struct { +} + +func (c *C[T]) reset() { +} + +func New[T any]() { + c := &C[T]{} + i = c.reset + z(c.reset) +} + +var i interface{} + +func z(interface{}) { +} + +func main() { + New[int]() +} diff --git a/test/typeparam/issue47797.go b/test/typeparam/issue47797.go new file mode 100644 index 0000000..ad89bcc --- /dev/null +++ b/test/typeparam/issue47797.go @@ -0,0 +1,22 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type Foo[T any] struct { + Val T +} + +func (f Foo[T]) Bat() {} + +type Bar struct { + Foo[int] +} + +func foo() { + var b Bar + b.Bat() +} diff --git a/test/typeparam/issue47877.go b/test/typeparam/issue47877.go new file mode 100644 index 0000000..be5c5c0 --- /dev/null +++ b/test/typeparam/issue47877.go @@ -0,0 +1,23 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Map[K comparable, V any] struct { + m map[K]V +} + +func NewMap[K comparable, V any]() Map[K, V] { + return Map[K, V]{m: map[K]V{}} +} + +func (m Map[K, V]) Get(key K) V { + return m.m[key] +} + +func main() { + _ = NewMap[int, struct{}]() +} diff --git a/test/typeparam/issue47878.go b/test/typeparam/issue47878.go new file mode 100644 index 0000000..25758cb --- /dev/null +++ b/test/typeparam/issue47878.go @@ -0,0 +1,56 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Src1[T any] func() Src1[T] + +func (s *Src1[T]) Next() { + *s = (*s)() +} + +type Src2[T any] []func() Src2[T] + +func (s Src2[T]) Next() { + _ = s[0]() +} + +type Src3[T comparable] map[T]func() Src3[T] + +func (s Src3[T]) Next() { + var a T + _ = s[a]() +} + +type Src4[T any] chan func() T + +func (s Src4[T]) Next() { + _ = (<-s)() +} + +type Src5[T any] func() Src5[T] + +func (s Src5[T]) Next() { + var x interface{} = s + _ = (x.(Src5[T]))() +} + +func main() { + var src1 Src1[int] + src1.Next() + + var src2 Src2[int] + src2.Next() + + var src3 Src3[string] + src3.Next() + + var src4 Src4[int] + src4.Next() + + var src5 Src5[int] + src5.Next() +} diff --git a/test/typeparam/issue47892.dir/a.go b/test/typeparam/issue47892.dir/a.go new file mode 100644 index 0000000..b63d604 --- /dev/null +++ b/test/typeparam/issue47892.dir/a.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Index[T any] interface { + G() T +} + +type I1[T any] struct { + a T +} + +func (i *I1[T]) G() T { + return i.a +} diff --git a/test/typeparam/issue47892.dir/main.go b/test/typeparam/issue47892.dir/main.go new file mode 100644 index 0000000..348e38b --- /dev/null +++ b/test/typeparam/issue47892.dir/main.go @@ -0,0 +1,21 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +type Model[T any] struct { + index a.Index[T] +} + +func NewModel[T any](index a.Index[T]) Model[T] { + return Model[T]{ + index: index, + } +} + +func main() { + _ = NewModel[int]((*a.I1[int])(nil)) +} diff --git a/test/typeparam/issue47892.go b/test/typeparam/issue47892.go new file mode 100644 index 0000000..5bb6a74 --- /dev/null +++ b/test/typeparam/issue47892.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored
\ No newline at end of file diff --git a/test/typeparam/issue47892b.dir/a.go b/test/typeparam/issue47892b.dir/a.go new file mode 100644 index 0000000..5adb492 --- /dev/null +++ b/test/typeparam/issue47892b.dir/a.go @@ -0,0 +1,29 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type T struct{ p *int64 } + +type i struct{} + +func G() *T { return &T{nil} } + +func (j i) F(a, b *T) *T { + n := *a.p + *b.p + return &T{&n} +} + +func (j i) G() *T { + return &T{} +} + +type I[Idx any] interface { + G() Idx + F(a, b Idx) Idx +} + +func Gen() I[*T] { + return i{} +} diff --git a/test/typeparam/issue47892b.dir/main.go b/test/typeparam/issue47892b.dir/main.go new file mode 100644 index 0000000..3cd658f --- /dev/null +++ b/test/typeparam/issue47892b.dir/main.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +type S[Idx any] struct { + A string + B Idx +} + +type O[Idx any] struct { + A int + B a.I[Idx] +} diff --git a/test/typeparam/issue47892b.go b/test/typeparam/issue47892b.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue47892b.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue47896.go b/test/typeparam/issue47896.go new file mode 100644 index 0000000..616e907 --- /dev/null +++ b/test/typeparam/issue47896.go @@ -0,0 +1,74 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "database/sql" +) + +// Collection generic interface which things can be added to. +type Collection[T any] interface { + Add(T) +} + +// Slice generic slice implementation of a Collection +type Slice[T any] []*T + +func (s *Slice[T]) Add(t *T) { + *s = append(*s, t) +} + +type Scanner interface { + Scan(...interface{}) error +} + +type Mapper[T any] func(s Scanner, t T) error + +type Repository[T any] struct { + db *sql.DB +} + +func (r *Repository[T]) scan(rows *sql.Rows, m Mapper[*T], c Collection[*T]) error { + for rows.Next() { + t := new(T) + if err := m(rows, t); err != nil { + return err + } + c.Add(t) + } + return rows.Err() +} + +func (r *Repository[T]) query(query string, m Mapper[*T], c Collection[*T]) error { + rows, err := r.db.Query(query) + if err != nil { + return err + } + if err := r.scan(rows, m, c); err != nil { + rows.Close() + return err + } + return rows.Close() +} + +type Actor struct { + ActorID uint16 + FirstName string + LastName string +} + +type ActorRepository struct { + r Repository[Actor] +} + +func (ActorRepository) scan(s Scanner, a *Actor) error { + return s.Scan(&a.ActorID, &a.FirstName, &a.LastName) +} + +func (r *ActorRepository) SelectAll(c Collection[*Actor]) error { + return r.r.query("SELECT `actor_id`, `first_name`, `last_name` FROM `actor` LIMIT 10", r.scan, c) +} diff --git a/test/typeparam/issue47901.go b/test/typeparam/issue47901.go new file mode 100644 index 0000000..e005135 --- /dev/null +++ b/test/typeparam/issue47901.go @@ -0,0 +1,21 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Chan[T any] chan Chan[T] + +func (ch Chan[T]) recv() Chan[T] { + return <-ch +} + +func main() { + ch := Chan[int](make(chan Chan[int])) + go func() { + ch <- make(Chan[int]) + }() + ch.recv() +} diff --git a/test/typeparam/issue47924.go b/test/typeparam/issue47924.go new file mode 100644 index 0000000..eea7acb --- /dev/null +++ b/test/typeparam/issue47924.go @@ -0,0 +1,15 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type Cache[K any] struct{} + +func (c Cache[K]) foo(x interface{}, f func(K) bool) { + f(x.(K)) +} + +var _ Cache[int] diff --git a/test/typeparam/issue47925.go b/test/typeparam/issue47925.go new file mode 100644 index 0000000..c595e14 --- /dev/null +++ b/test/typeparam/issue47925.go @@ -0,0 +1,20 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type myifacer[T any] interface{ do(T) error } + +type stuff[T any] struct{} + +func (s stuff[T]) run() interface{} { + var i myifacer[T] + return i +} + +func main() { + stuff[int]{}.run() +} diff --git a/test/typeparam/issue47925b.go b/test/typeparam/issue47925b.go new file mode 100644 index 0000000..bffbe4e --- /dev/null +++ b/test/typeparam/issue47925b.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I[T any] interface { + foo() +} + +type E[T any] interface { +} + +//go:noinline +func f[T I[T]](x T) E[T] { + // contains a cast from nonempty to empty interface + return E[T](I[T](x)) +} + +type S struct { + x int +} + +func (s *S) foo() {} + +func main() { + i := f(&S{x: 7}) + if i.(*S).x != 7 { + panic("bad") + } +} diff --git a/test/typeparam/issue47925c.go b/test/typeparam/issue47925c.go new file mode 100644 index 0000000..9636b9d --- /dev/null +++ b/test/typeparam/issue47925c.go @@ -0,0 +1,36 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I[T any] interface { + foo() +} + +type J[T any] interface { + foo() + bar() +} + +//go:noinline +func f[T J[T]](x T) I[T] { + // contains a cast between two nonempty interfaces + return I[T](J[T](x)) +} + +type S struct { + x int +} + +func (s *S) foo() {} +func (s *S) bar() {} + +func main() { + i := f(&S{x: 7}) + if i.(*S).x != 7 { + panic("bad") + } +} diff --git a/test/typeparam/issue47925d.go b/test/typeparam/issue47925d.go new file mode 100644 index 0000000..c5647f9 --- /dev/null +++ b/test/typeparam/issue47925d.go @@ -0,0 +1,47 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I[T any] interface { + foo() +} + +type J[T any] interface { + foo() + bar() +} + +//go:noinline +func f[T J[T]](x T, g func(T) T) I[T] { + // contains a cast between two nonempty interfaces + // Also make sure we don't evaluate g(x) twice. + return I[T](J[T](g(x))) +} + +type S struct { + x int +} + +func (s *S) foo() {} +func (s *S) bar() {} + +var cnt int + +func inc(s *S) *S { + cnt++ + return s +} + +func main() { + i := f(&S{x: 7}, inc) + if i.(*S).x != 7 { + panic("bad") + } + if cnt != 1 { + panic("multiple calls") + } +} diff --git a/test/typeparam/issue47929.go b/test/typeparam/issue47929.go new file mode 100644 index 0000000..1aa6885 --- /dev/null +++ b/test/typeparam/issue47929.go @@ -0,0 +1,29 @@ +// compile -p=p + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package v4 + +var sink interface{} + +//go:noinline +func Do(result, body interface{}) { + sink = &result +} + +func DataAction(result DataActionResponse, body DataActionRequest) { + Do(&result, body) +} + +type DataActionRequest struct { + Action *interface{} +} + +type DataActionResponse struct { + ValidationErrors *ValidationError +} + +type ValidationError struct { +} diff --git a/test/typeparam/issue47948.go b/test/typeparam/issue47948.go new file mode 100644 index 0000000..deab0ef --- /dev/null +++ b/test/typeparam/issue47948.go @@ -0,0 +1,18 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type fun func() + +func F[T any]() { + _ = fun(func() { + + }) +} +func main() { + F[int]() +} diff --git a/test/typeparam/issue47966.go b/test/typeparam/issue47966.go new file mode 100644 index 0000000..ec66478 --- /dev/null +++ b/test/typeparam/issue47966.go @@ -0,0 +1,9 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type C comparable diff --git a/test/typeparam/issue48013.go b/test/typeparam/issue48013.go new file mode 100644 index 0000000..3fbf249 --- /dev/null +++ b/test/typeparam/issue48013.go @@ -0,0 +1,39 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "unsafe" +) + +type S[T any] struct { + val T +} + +// Test type substitution where base type is unsafe.Pointer +type U[T any] unsafe.Pointer + +func test[T any]() T { + var q U[T] + var v struct { + // Test derived type that contains an unsafe.Pointer + p unsafe.Pointer + val T + } + _ = q + return v.val +} + +func main() { + want := 0 + got := test[int]() + if got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } + +} diff --git a/test/typeparam/issue48016.go b/test/typeparam/issue48016.go new file mode 100644 index 0000000..dbc87ec --- /dev/null +++ b/test/typeparam/issue48016.go @@ -0,0 +1,35 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "strconv" +) + +func test1[T any](fn func(T) int, v T) int { + fn1 := func() int { + var i interface{} = v + val := fn(i.(T)) + return val + } + return fn1() +} + +func main() { + want := 123 + got := test1(func(s string) int { + r, err := strconv.Atoi(s) + if err != nil { + return 0 + } + return r + }, "123") + if got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } +} diff --git a/test/typeparam/issue48030.go b/test/typeparam/issue48030.go new file mode 100644 index 0000000..23494f9 --- /dev/null +++ b/test/typeparam/issue48030.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Src[T any] func() Src[T] + +func Seq[T any]() Src[T] { + return nil +} + +func Seq2[T1 any, T2 any](v1 T1, v2 T2) Src[T2] { + return nil +} + +func main() { + // Type args fully supplied + Seq[int]() + // Partial inference of type args + Seq2[int](5, "abc") + // Full inference of type args + Seq2(5, "abc") +} diff --git a/test/typeparam/issue48042.go b/test/typeparam/issue48042.go new file mode 100644 index 0000000..1cfbfbe --- /dev/null +++ b/test/typeparam/issue48042.go @@ -0,0 +1,77 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "reflect" +) + +type G[T any] interface { + g() func()(*T) +} +type Foo[T any] struct { + +} +// OCALL +func (l *Foo[T]) f1() (*T) { + return g[T]()() +} +// OCALLFUNC +func (l *Foo[T]) f2() (*T) { + var f = g[T] + return f()() +} +// OCALLMETH +func (l *Foo[T]) f3() (*T) { + return l.g()() +} +// OCALLINTER +func (l *Foo[T]) f4() (*T) { + var g G[T] = l + return g.g()() +} +// ODYNAMICDOTTYPE +func (l *Foo[T]) f5() (*T) { + var x interface{} + x = g[T] + return x.(func()func()(*T))()() +} +func (l *Foo[T]) g() func() (*T) { + return func() (*T) { + t := new(T) + reflect.ValueOf(t).Elem().SetInt(100) + return t + } +} +func g[T any]() func() (*T) { + return func() (*T) { + t := new(T) + reflect.ValueOf(t).Elem().SetInt(100) + return t + } +} + +func main() { + foo := Foo[int]{} + // Make sure the function conversion is correct + if n := *(foo.f1()) ; n != 100{ + panic(fmt.Sprintf("%v",n)) + } + if n := *(foo.f2()) ; n != 100{ + panic(fmt.Sprintf("%v",n)) + } + if n := *(foo.f3()) ; n != 100{ + panic(fmt.Sprintf("%v",n)) + } + if n := *(foo.f4()) ; n != 100{ + panic(fmt.Sprintf("%v",n)) + } + if n := *(foo.f5()) ; n != 100{ + panic(fmt.Sprintf("%v",n)) + } +}
\ No newline at end of file diff --git a/test/typeparam/issue48047.go b/test/typeparam/issue48047.go new file mode 100644 index 0000000..06a2ebd --- /dev/null +++ b/test/typeparam/issue48047.go @@ -0,0 +1,30 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type A[T any] struct { + field B[T] +} + +type B[T any] interface { + Work(T) +} + +func (a *A[T]) Work(t T) { + a.field.Work(t) +} + +type BImpl struct{} + +func (b BImpl) Work(s string) {} + +func main() { + a := &A[string]{ + field: BImpl{}, + } + a.Work("") +} diff --git a/test/typeparam/issue48049.go b/test/typeparam/issue48049.go new file mode 100644 index 0000000..3e87b38 --- /dev/null +++ b/test/typeparam/issue48049.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + Gooer2[byte]() +} + +type Fooer[T any] interface { + Foo(p T) +} + +type fooer1[T any] struct{} + +func (fooer1[T]) Foo(T) {} + +type fooer2[T any] struct { + r []Fooer[T] +} + +//go:noinline +func (mr fooer2[T]) Foo(p T) { + mr.r[0] = fooer1[T]{} + return +} + +func Gooer2[T any]() Fooer[T] { + return fooer2[T]{} +} diff --git a/test/typeparam/issue48056.go b/test/typeparam/issue48056.go new file mode 100644 index 0000000..e91d689 --- /dev/null +++ b/test/typeparam/issue48056.go @@ -0,0 +1,27 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type B[T any] interface { + Work() +} +type BImpl[T any] struct{} + +func (b *BImpl[T]) Work() { +} + +type A[T any] struct { + B[T] +} + +func f[T any]() { + s := &A[T]{ + &BImpl[T]{}, + } + // golang.org/issue/48056 + s.Work() +} diff --git a/test/typeparam/issue48094.dir/a.go b/test/typeparam/issue48094.dir/a.go new file mode 100644 index 0000000..dd8c16f --- /dev/null +++ b/test/typeparam/issue48094.dir/a.go @@ -0,0 +1,26 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import "unsafe" + +func F[T any]() uintptr { + var t T + return unsafe.Sizeof(t) +} + +func G[T any]() uintptr { + var t T + return unsafe.Alignof(t) +} + +//func H[T any]() uintptr { +// type S struct { +// a T +// b T +// } +// var s S +// return unsafe.Offsetof(s.b) +//} diff --git a/test/typeparam/issue48094.dir/main.go b/test/typeparam/issue48094.dir/main.go new file mode 100644 index 0000000..78337da --- /dev/null +++ b/test/typeparam/issue48094.dir/main.go @@ -0,0 +1,20 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + if a.F[int64]() != 8 { + panic("bad") + } + if a.G[int8]() != 1 { + panic("bad") + } + // TODO: enable once 47631 is fixed. + //if a.H[int64]() != 8 { + // panic("bad") + //} +} diff --git a/test/typeparam/issue48094.go b/test/typeparam/issue48094.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48094.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48094b.dir/a.go b/test/typeparam/issue48094b.dir/a.go new file mode 100644 index 0000000..a113a22 --- /dev/null +++ b/test/typeparam/issue48094b.dir/a.go @@ -0,0 +1,8 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F() { G(0) } +func G[T any](t T) {} diff --git a/test/typeparam/issue48094b.dir/b.go b/test/typeparam/issue48094b.dir/b.go new file mode 100644 index 0000000..242b34a --- /dev/null +++ b/test/typeparam/issue48094b.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func H() { a.F() } diff --git a/test/typeparam/issue48094b.go b/test/typeparam/issue48094b.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue48094b.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48137.go b/test/typeparam/issue48137.go new file mode 100644 index 0000000..84a0f6d --- /dev/null +++ b/test/typeparam/issue48137.go @@ -0,0 +1,25 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Constraint[T any] interface { + ~func() T +} + +func Foo[T Constraint[T]]() T { + var t T + + t = func() T { + return t + } + return t +} + +func main() { + type Bar func() Bar + Foo[Bar]() +} diff --git a/test/typeparam/issue48185a.dir/p.go b/test/typeparam/issue48185a.dir/p.go new file mode 100644 index 0000000..176c7f4 --- /dev/null +++ b/test/typeparam/issue48185a.dir/p.go @@ -0,0 +1,19 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type MarshalOptions struct { + Marshalers *Marshalers +} + +type Encoder struct {} + +type Marshalers = marshalers[MarshalOptions, Encoder] + +type marshalers[Options, Coder any] struct{} + +func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers { + return &Marshalers{} +} diff --git a/test/typeparam/issue48185a.dir/p_test.go b/test/typeparam/issue48185a.dir/p_test.go new file mode 100644 index 0000000..a89d697 --- /dev/null +++ b/test/typeparam/issue48185a.dir/p_test.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./p" + +func main() { + _ = p.MarshalFuncV1[int](func(int) ([]byte, error) { return nil, nil }) +} diff --git a/test/typeparam/issue48185a.go b/test/typeparam/issue48185a.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48185a.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48185b.dir/a.go b/test/typeparam/issue48185b.dir/a.go new file mode 100644 index 0000000..9aed60c --- /dev/null +++ b/test/typeparam/issue48185b.dir/a.go @@ -0,0 +1,37 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import ( + "reflect" + "sync" +) + +type addressableValue struct{ reflect.Value } + +type arshalers[Options, Coder any] struct { + fncVals []typedArshaler[Options, Coder] + fncCache sync.Map // map[reflect.Type]unmarshaler +} +type typedArshaler[Options, Coder any] struct { + typ reflect.Type + fnc func(Options, *Coder, addressableValue) error +} + +type UnmarshalOptions1 struct { + // Unmarshalers is a list of type-specific unmarshalers to use. + Unmarshalers *arshalers[UnmarshalOptions1, Decoder1] +} + +type Decoder1 struct { +} + +func (a *arshalers[Options, Coder]) lookup(fnc func(Options, *Coder, addressableValue) error, t reflect.Type) func(Options, *Coder, addressableValue) error { + return fnc +} + +func UnmarshalFuncV2[T any](fn func(UnmarshalOptions1, *Decoder1, T) error) *arshalers[UnmarshalOptions1, Decoder1] { + return &arshalers[UnmarshalOptions1, Decoder1]{} +} diff --git a/test/typeparam/issue48185b.dir/main.go b/test/typeparam/issue48185b.dir/main.go new file mode 100644 index 0000000..ea157f7 --- /dev/null +++ b/test/typeparam/issue48185b.dir/main.go @@ -0,0 +1,18 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + _ = a.UnmarshalOptions1{ + Unmarshalers: a.UnmarshalFuncV2(func(opts a.UnmarshalOptions1, dec *a.Decoder1, val *interface{}) (err error) { + return fmt.Errorf("error") + }), + } +} diff --git a/test/typeparam/issue48185b.go b/test/typeparam/issue48185b.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48185b.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48191.go b/test/typeparam/issue48191.go new file mode 100644 index 0000000..9c3218b --- /dev/null +++ b/test/typeparam/issue48191.go @@ -0,0 +1,269 @@ +// compile -c=2 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I1 interface { + int8 | int16 | int32 | int64 | int | uint +} +type I2 interface{ float32 | float64 } +type I3 interface{ string } + +func F[G1 I1, G2 I2, G3 I3]() { + var m0 map[G2]rune + var ch0, ch1 chan bool + var ast0, ast1 []struct{ s0 G3 } + var ai64_2 []int64 + var m1, m2, m3 map[bool]map[int]struct { + m0 map[G2]byte + s1 G3 + } + var i8_0, i8_1 G1 + var i16_0 int16 + var am3, am4 []map[float64]map[G2]*func(*byte, map[uint]int64, G3, struct{}) G2 + var pi64_0, pi64_1 *int64 + var i, i1, i2 int + var as5, as6, as7 []G3 + var ch2, ch3, ch4 chan uint + var m4, m5, m6 map[G1]chan bool + + if func(G2, int32) byte { + return m1[false][30].m0[G2(28.6)] * m3[func(bool, uint) bool { + return false + }(false, uint(94))][31].m0[G2(185.0)] * m1[(true || true) && (false && false)][51-i2].m0[G2(278.6)] + }(G2(672.5), int32(35)) < m3[<-m5[func(int64, int64) G1 { + return i8_1 + }(*pi64_0, int64(50))]][15&i1^i2^i2].m0[G2(895.3)] || (func(int64, uint) uint { + return uint(94) + }(int64(30), uint(95))&^<-ch2^<-ch4)&<-ch2^<-ch4 == <-ch2 { + var f0 float64 + var pf2 *float64 + var ch5, ch6 chan int16 + var fnc0 func(*int64, G2, struct { + i8_0 G1 + m1 map[float64]bool + i64_2 int64 + }, map[byte]func(G2, float64, *uint, float64) struct{}) complex128 = func(p0 *int64, p1 G2, p2 struct { + i8_0 G1 + m1 map[float64]bool + i64_2 int64 + }, p3 map[byte]func(G2, float64, *uint, float64) struct{}) complex128 { + p0 = pi64_1 + m5 = map[G1]chan bool{(p2.i8_0 + i8_1 + i8_1 ^ i8_1) * p2.i8_0 / p2.i8_0: m4[p2.i8_0>><-ch2]} + return (2.65i - 31.18i) * func(byte, byte) complex128 { + return 13.12i - 32.90i + (44.15i - 70.53i - (87.16i*92.67i + (24.18i - 9.13i))) + (func(G1, int16) complex128 { + return 55.80i + }(G1(30), int16(80)) + 8.48i*79.18i + (37.30i*73.81i + (21.01i - 76.30i)) + func(G3, G2) complex128 { + return 35.58i + }(G3("2JYizeFiEMvXLkUR"), p1)*(81.59i-21.76i)) + }(m1[<-m5[G1(37)*i8_1<<i8_1%p2.i8_0]][i2].m0[p1], m1[<-ch0][55&i2/i2^i].m0[func(G3, float64) G2 { + return G2(619.2) + }(G3(""), 954.0)]) + } + var m7 map[G2]int64 + var ch7 chan byte + var fnc1 func(bool, func(chan G2, struct { + h0 G2 + }, int64) **rune, int) map[complex128]int32 = func(p0 bool, p1 func(chan G2, struct { + h0 G2 + }, int64) **rune, p2 int) map[complex128]int32 { + pf2 = pf2 + as7 = as7 + return map[complex128]int32{(94.02i - 22.19i) * (fnc0(pi64_0, G2(554.1)*G2(i1), struct { + i8_0 G1 + m1 map[float64]bool + i64_2 int64 + }{G1(68)*i8_0 ^ i8_0, map[float64]bool{f0: <-m6[G1(33)]}, (int64(40) ^ ai64_2[77]) % *pi64_1}, map[byte]func(G2, float64, *uint, float64) struct { + }{func(float64, float64) byte { + return byte(32) + }(878.2, 984.4) + m3[true][12].m0[G2(594.0)]: nil}) - (fnc0(pi64_0, G2(241.1)+G2(i2), struct { + i8_0 G1 + m1 map[float64]bool + i64_2 int64 + }{i8_0, map[float64]bool{904.1: false}, int64(83) + m7[G2(357.7)]}, map[byte]func(G2, float64, *uint, float64) struct { + }{byte(85) | m1[true][99].m0[G2(372.7)]: nil}) - (fnc0(pi64_0, G2(239.9), struct { + i8_0 G1 + m1 map[float64]bool + i64_2 int64 + }{G1(68), map[float64]bool{555.6: false}, int64(0)}, map[byte]func(G2, float64, *uint, float64) struct { + }{byte(18) & <-ch7: nil}) + (88.17i - 0.55i)))): int32(73) % int32(i)} + } + as5[54] = as6[(len(func(bool, G2) G3 { + return G3("") + }(false, G2(190.8)))|i1^i1)%i1-i1] + m2[68 != i || 'M'&'\xf4'|'H'&'\u1311' >= '4'&'\uab3e'>>uint(83) && (<-m6[G1(24)%i8_0] && <-ch1)][i].s1 + i = len([]G3{ast1[2].s0}) + i16_0 = <-ch6 / i16_0 & <-ch6 + i = (i1^i|i2|i2)/i + i + m6 = m4 + am3 = am3 + m1[G2(869.6) == G2(i2)] = m2[func(float64, rune) byte { + return func(G3, byte) byte { + return byte(42) + }(G3("8iDnlygG194xl"), byte(89)) + }(*pf2, '\u9cf4')/m1[func(G3, float64) bool { + return false + }(G3("6MbwBSHYzr9t0zD"), 774.4)][76].m0[G2(508.0)]/m2[<-m4[i8_0]][92&^i2].m0[G2(807.0)] > m3[(int32(39)|int32(i2))&^int32(i2) < int32(i2)][89*i1&i2].m0[G2(327.5)]] + m2[<-m4[func(G1, complex128) G1 { + return i8_1 + }(i8_0, 35.01i)] && <-m4[func(int, G1) G1 { + return G1(0) + }(10, G1(70))*i8_1&i8_1>><-ch2] || fnc0(pi64_0, G2(689.5), struct { + i8_0 G1 + m1 map[float64]bool + i64_2 int64 + }{(G1(78)*i8_1 - i8_1) / i8_1, map[float64]bool{499.2: <-m6[G1(88)^i8_0]}, int64(83) &^ ai64_2[33] & *pi64_1 * ai64_2[i1]}, map[byte]func(G2, float64, *uint, float64) struct { + }{m1[len(G3("bNIJZq")+G3("Fri5pn1MsZzYtsaV7b")) >= i][i^i1].m0[G2(691.7)]: nil}) != 71.77i-34.84i] = map[int]struct { + m0 map[G2]byte + s1 G3 + }{((18+i2)&^i2%i2 ^ i) / i: m3[(G2(267.1)*G2(i1) > G2(i2) || (false || true || (true || false))) && func(int32, int64) bool { + return <-ch0 + }(int32(63), ai64_2[61&^i1&i2])][i|i^i1]} + i2 = 90 - i1 + _, _, _, _, _, _, _, _ = f0, pf2, ch5, ch6, fnc0, m7, ch7, fnc1 + } else { + var m7 map[G1]chan uint + var ch5, ch6, ch7 chan G3 + var i32_0, i32_1 int32 + var m8, m9, m10 map[bool]struct { + } + pi64_1 = pi64_0 + m6[func(G3, G2) G1 { + return (G1(35) | i8_0) << i8_1 / i8_1 &^ i8_1 / i8_1 + }(G3("YBiKg"), G2(122.6))] = make(chan bool) + ast0 = ast0 + i8_1 = (((G1(10)+i8_1)&i8_0+i8_0)&i8_0&i8_1 ^ i8_1) & i8_1 + am4 = am3 + i32_1 = int32(10) &^ i32_0 + m8[func(float64, G3) bool { + return func(rune, int16) bool { + return (G2(267.0)*G2(i2) == G2(i) || func(G2, G3) bool { + return <-ch0 + }(G2(53.3), <-ch5)) && func(G2, G1) int32 { + return int32(63) + }(G2(804.8), G1(2))-i32_0 < i32_1 + }('\xbd', i16_0) + }(370.9, ast0[len([]complex128{})+i-i2].s0) && (G2(245.0)-G2(i1) == G2(i1) || byte(17)&m2[false][26].m0[G2(628.5)] > m3[false][55].m0[G2(608.8)] || func(G1, G1) bool { + return true + }(G1(24), G1(2)) || (<-m5[G1(38)] || <-ch1) && func(int32, int) bool { + return false && true + }(int32(6), i1) && '\x26'&'\x27'|func(G2, G3) rune { + return '\x13' + }(G2(229.6), G3("ys1msVeg61uSImCDkRG3C")) <= 'V'>>uint(88)-('\xbe'+'\uafd4')) == (53.04i == 37.22i)] = m8[func(byte, int64) bool { + return <-ch1 + }(m3[false && false][96].m0[G2(147.6)], *pi64_0) && 643.5 > float64(i1) && (<-ch0 && <-ch1)] + i8_1 = func(byte, uint) G1 { + return G1(68) + }(m2[<-ch1 || <-m5[G1(96)+i8_0] || func(bool, int32) bool { + return func(int, byte) bool { + return m1[true][89].s1 <= G3("2ZMnHGOMQnyHSbJ") + }(i2, m2[<-m6[G1(47)]][94].m0[G2(981.3)]) + }(<-m4[G1(0)&^i8_0&i8_0], i32_0)][i2%i&^i].m0[func(complex128, rune) G2 { + return G2(93.1) * G2(i2) + }(4.63i, m0[G2(975.8)])], uint(21)) + _, _, _, _, _, _, _, _, _ = m7, ch5, ch6, ch7, i32_0, i32_1, m8, m9, m10 + } + + if *pi64_0>><-ch3 <= *pi64_0 || func(bool, int32) int32 { + return (int32(69)&^int32(i2) + int32(i2)) * int32(i2) + }(true, int32(49))^int32(i2) >= int32(i) { + var ai8_8, ai8_9 []G1 + var pi2, pi3, pi4 *int + var pi8_5, pi8_6 *G1 + var i64_0, i64_1 int64 + m1[754.8*float64(i2) != float64(i) && 6.26i == 69.99i] = map[int]struct { + m0 map[G2]byte + s1 G3 + }{len([]G2{G2(935.9) / G2(i2), func(int64, G2) G2 { + return G2(720.5) + }(int64(36), G2(349.7))})&*pi2 + i2 - i1: m1[(uint(29) >= <-ch4 || int64(45)+ai64_2[18] >= *pi64_1) == (func(G2, G2) bool { + return <-m5[G1(25)] + }(G2(447.2), G2(946.6)) || func(int, int16) bool { + return true + }(40, int16(41)) && byte(51) >= m2[true][13].m0[G2(6.6)])][*pi3]} + am4 = []map[float64]map[G2]*func(*byte, map[uint]int64, G3, struct { + }) G2{am4[i2%*pi3]} + pi2 = &i2 + pi64_0 = pi64_1 + ai8_8[*pi3] = *pi8_5&ai8_9[(*pi4+*pi3)%*pi3] ^ ai8_8[90+i2|*pi4] + ai64_2 = []int64{} + m4 = m4 + pi2 = &i1 + pi3 = &i2 + _, _, _, _, _, _, _, _, _ = ai8_8, ai8_9, pi2, pi3, pi4, pi8_5, pi8_6, i64_0, i64_1 + } + + if (true || false || int32(68) > int32(i1) || <-m5[G1(11)-i8_0] && true) && func(int, float64) bool { + return <-m5[(G1(83)-i8_1)&^i8_1] + }(i1, 886.6) || func(byte, int) bool { + return 401.0/float64(i1)/float64(i1)-float64(i) == float64(i2) + }(m1[(G1(85)^i8_1)&^i8_1 <= i8_1][72].m0[G2(617.4)], i1) || (<-m6[(G1(3)|i8_0)>><-ch2%i8_0|i8_0] || <-ch0) { + var ch5 chan map[byte]complex128 + var fnc0 func(int32, *map[rune]complex128) complex128 + var c0 complex128 + var st0, st1, st2 struct { + } + var au8 []uint + var st3, st4, st5 struct { + ph0 *G2 + st1 struct { + m0 map[rune]complex128 + pch1 *chan int64 + m2 map[bool]byte + st3 struct { + ch0 chan func(map[G1]*struct { + pm0 *map[bool]int64 + h1 G2 + }, struct { + u0 uint + }, uint, float64) *struct { + ch0 chan map[int16]G2 + } + i1 int + ch2 chan complex128 + } + } + pm2 *map[int64]struct { + s0 G3 + pi1 *int + st2 struct { + m0 map[int]map[rune]int64 + r1 rune + } + } + } + var am9, am10, am11 []map[uint]int64 + m1[G3("E")+(*st4.pm2)[*pi64_0+<-*st3.st1.pch1].s0 < (*st4.pm2)[int64(46)].s0+(G3("4Jsp3pv0x")+G3("MTKt98c")+(G3("E6Nxqpl70")+G3("eXhhxb")))+(G3("siISQNeBXoQIHwGB")+G3("CzocwLRWIUD")+(G3("cDWy3E3qpeJOmw1wP9wZ")+G3("S3ZRONdtB7K1LBC"))+func(G1, uint) G3 { + return m2[false][74].s1 + }(G1(9), uint(26)))+func(G2, int) G3 { + return G3("WzncXvaqK4zPn") + }(G2(291.6), i)+(ast1[(40^i1+i1)&^st4.st1.st3.i1].s0+func(byte, int64) G3 { + return m2[207.7 == float64(i2) && (false || false)][i2].s1 + }(byte(34), am11[25][func(int32, float64) uint { + return uint(77) + }(int32(29), 403.1)]))] = map[int]struct { + m0 map[G2]byte + s1 G3 + }{st3.st1.st3.i1: m2[<-m4[i8_1]][st5.st1.st3.i1-st3.st1.st3.i1-i2]} + st1 = struct { + }{} + pi64_0 = pi64_1 + m4 = m6 + as7 = as7 + m6[(i8_0+i8_0)&^i8_1&^i8_1] = m5[G1(96)^i8_1] + st2 = struct { + }{} + st1 = struct { + }{} + am10 = []map[uint]int64{am9[len((*st4.pm2)[int64(65)].s0)+i], am11[st4.st1.st3.i1%st4.st1.st3.i1^i1]} + i2 = st5.st1.st3.i1*i - st5.st1.st3.i1 + _, _, _, _, _, _, _, _, _, _, _, _, _ = ch5, fnc0, c0, st0, st1, st2, au8, st3, st4, st5, am9, am10, am11 + } + +} + +func main() { + F[int16, float32, string]() +} diff --git a/test/typeparam/issue48198.go b/test/typeparam/issue48198.go new file mode 100644 index 0000000..1ed29b8 --- /dev/null +++ b/test/typeparam/issue48198.go @@ -0,0 +1,22 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package p + +type Foo[T any] struct { +} + +func (foo Foo[T]) Get() { +} + +var( + _ = Foo[byte]{} + _ = Foo[[]byte]{} + _ = Foo[map[byte]rune]{} + + _ = Foo[rune]{} + _ = Foo[[]rune]{} + _ = Foo[map[rune]byte]{} +) diff --git a/test/typeparam/issue48225.go b/test/typeparam/issue48225.go new file mode 100644 index 0000000..702bc07 --- /dev/null +++ b/test/typeparam/issue48225.go @@ -0,0 +1,37 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "reflect" + +type Foo[T any] struct { + val int +} + +func (foo Foo[T]) Get() *T { + if foo.val != 1 { + panic("bad val field in Foo receiver") + } + return new(T) +} + +var ( + newInt = Foo[int]{val: 1}.Get + newString = Foo[string]{val: 1}.Get +) + +func main() { + i := newInt() + s := newString() + + if t := reflect.TypeOf(i).String(); t != "*int" { + panic(t) + } + if t := reflect.TypeOf(s).String(); t != "*string" { + panic(t) + } +} diff --git a/test/typeparam/issue48253.go b/test/typeparam/issue48253.go new file mode 100644 index 0000000..20d5db6 --- /dev/null +++ b/test/typeparam/issue48253.go @@ -0,0 +1,34 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "reflect" +) + +type A[T any] struct { + B[int] +} + +type B[T any] struct { +} + +func (b B[T]) Bat() { + t := new(T) + if tt := reflect.TypeOf(t); tt.Kind() != reflect.Pointer || tt.Elem().Kind() != reflect.Int { + panic("unexpected type, want: *int, got: "+tt.String()) + } +} + +type Foo struct { + A[string] +} +func main() { + Foo{}.A.Bat() + Foo{}.A.B.Bat() + Foo{}.Bat() +} diff --git a/test/typeparam/issue48276a.go b/test/typeparam/issue48276a.go new file mode 100644 index 0000000..2a79268 --- /dev/null +++ b/test/typeparam/issue48276a.go @@ -0,0 +1,19 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +func main() { + IsZero[int](0) +} + +func IsZero[T comparable](val T) bool { + var zero T + fmt.Printf("%v:%v\n", zero, val) + return val != zero +} diff --git a/test/typeparam/issue48276a.out b/test/typeparam/issue48276a.out new file mode 100644 index 0000000..8f38db9 --- /dev/null +++ b/test/typeparam/issue48276a.out @@ -0,0 +1 @@ +0:0 diff --git a/test/typeparam/issue48276b.go b/test/typeparam/issue48276b.go new file mode 100644 index 0000000..774898d --- /dev/null +++ b/test/typeparam/issue48276b.go @@ -0,0 +1,15 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + f[interface{}](nil) +} + +func f[T any](x T) { + var _ interface{} = x +} diff --git a/test/typeparam/issue48280.dir/a.go b/test/typeparam/issue48280.dir/a.go new file mode 100644 index 0000000..f66fd30 --- /dev/null +++ b/test/typeparam/issue48280.dir/a.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type I[T any] interface { + F() T +} + +type S struct{} diff --git a/test/typeparam/issue48280.dir/main.go b/test/typeparam/issue48280.dir/main.go new file mode 100644 index 0000000..2c8387d --- /dev/null +++ b/test/typeparam/issue48280.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + _ = a.S{} +} diff --git a/test/typeparam/issue48280.go b/test/typeparam/issue48280.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48280.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48306.dir/a.go b/test/typeparam/issue48306.dir/a.go new file mode 100644 index 0000000..fdfd86c --- /dev/null +++ b/test/typeparam/issue48306.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type I[T any] interface { + F() T +} diff --git a/test/typeparam/issue48306.dir/main.go b/test/typeparam/issue48306.dir/main.go new file mode 100644 index 0000000..260c3c8 --- /dev/null +++ b/test/typeparam/issue48306.dir/main.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +type S struct{} + +func (*S) F() *S { return nil } + +func main() { + var _ a.I[*S] = &S{} +} diff --git a/test/typeparam/issue48306.go b/test/typeparam/issue48306.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48306.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48317.go b/test/typeparam/issue48317.go new file mode 100644 index 0000000..0220360 --- /dev/null +++ b/test/typeparam/issue48317.go @@ -0,0 +1,38 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "encoding/json" +) + +type A[T any] struct { + F1 string `json:"t1"` + F2 T `json:"t2"` + B B `json:"t3"` +} + +type B struct { + F4 int `json:"t4"` +} + +func a[T any]() { + data := `{"t1":"1","t2":2,"t3":{"t4":4}}` + a1 := A[T]{} + if err := json.Unmarshal([]byte(data), &a1); err != nil { + panic(err) + } + if bytes, err := json.Marshal(&a1); err != nil { + panic(err) + } else if string(bytes) != data { + panic(string(bytes)) + } +} + +func main() { + a[int]() +} diff --git a/test/typeparam/issue48318.go b/test/typeparam/issue48318.go new file mode 100644 index 0000000..b75c520 --- /dev/null +++ b/test/typeparam/issue48318.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "encoding/xml" + "fmt" +) + +type A[T, U any] struct { + Name T `xml:"name"` + Data U `xml:"data"` +} + +func main() { + src := &A[string, int]{Name: "name", Data: 1} + data, err := xml.Marshal(src) + if err != nil { + panic(err) + } + dst := &A[string, int]{} + err = xml.Unmarshal(data, dst) + if err != nil { + panic(err) + } + if *src != *dst { + panic(fmt.Sprintf("wanted %#v got %#v", src, dst)) + } +} diff --git a/test/typeparam/issue48337a.dir/a.go b/test/typeparam/issue48337a.dir/a.go new file mode 100644 index 0000000..6f1b128 --- /dev/null +++ b/test/typeparam/issue48337a.dir/a.go @@ -0,0 +1,32 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import ( + "fmt" + "sync" +) + +type WrapperWithLock[T any] interface { + PrintWithLock() +} + +func NewWrapperWithLock[T any](value T) WrapperWithLock[T] { + return &wrapperWithLock[T]{ + Object: value, + } +} + +type wrapperWithLock[T any] struct { + Lock sync.Mutex + Object T +} + +func (w *wrapperWithLock[T]) PrintWithLock() { + w.Lock.Lock() + defer w.Lock.Unlock() + + fmt.Println(w.Object) +} diff --git a/test/typeparam/issue48337a.dir/main.go b/test/typeparam/issue48337a.dir/main.go new file mode 100644 index 0000000..ddf6724 --- /dev/null +++ b/test/typeparam/issue48337a.dir/main.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + obj := a.NewWrapperWithLock("this file does import sync") + obj.PrintWithLock() +} diff --git a/test/typeparam/issue48337a.go b/test/typeparam/issue48337a.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48337a.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48337a.out b/test/typeparam/issue48337a.out new file mode 100644 index 0000000..fa8d3ee --- /dev/null +++ b/test/typeparam/issue48337a.out @@ -0,0 +1 @@ +this file does import sync diff --git a/test/typeparam/issue48337b.dir/a.go b/test/typeparam/issue48337b.dir/a.go new file mode 100644 index 0000000..a3c2e88 --- /dev/null +++ b/test/typeparam/issue48337b.dir/a.go @@ -0,0 +1,25 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Container[T any] struct { + X T +} + +func NewContainer[T any](x T) *Container[T] { + return &Container[T]{x} +} + +type MetaContainer struct { + C *Container[Value] +} + +type Value struct{} + +func NewMetaContainer() *MetaContainer { + c := NewContainer(Value{}) + // c := &Container[Value]{Value{}} // <-- this works + return &MetaContainer{c} +} diff --git a/test/typeparam/issue48337b.dir/main.go b/test/typeparam/issue48337b.dir/main.go new file mode 100644 index 0000000..0318b67 --- /dev/null +++ b/test/typeparam/issue48337b.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + a.NewMetaContainer() +} diff --git a/test/typeparam/issue48337b.go b/test/typeparam/issue48337b.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48337b.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48344.go b/test/typeparam/issue48344.go new file mode 100644 index 0000000..220bce9 --- /dev/null +++ b/test/typeparam/issue48344.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type G[T any] interface { + g() +} + +type Foo[T any] struct { +} + +func (foo *Foo[T]) g() { + +} + +func f[T any]() { + v := []G[T]{} + v = append(v, &Foo[T]{}) +} +func main() { + f[int]() +} diff --git a/test/typeparam/issue48424.go b/test/typeparam/issue48424.go new file mode 100644 index 0000000..c5e5d4b --- /dev/null +++ b/test/typeparam/issue48424.go @@ -0,0 +1,54 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Smoke test for constraint literals with elided interface +// per issue #48424. + +package main + +func identity[T int](x T) T { + return x +} + +func min[T int | string](x, y T) T { + if x < y { + return x + } + return y +} + +func max[T ~int | ~float64](x, y T) T { + if x > y { + return x + } + return y +} + +func main() { + if identity(1) != 1 { + panic("identity(1) failed") + } + + if min(2, 3) != 2 { + panic("min(2, 3) failed") + } + + if min("foo", "bar") != "bar" { + panic(`min("foo", "bar") failed`) + } + + if max(2, 3) != 3 { + panic("max(2, 3) failed") + } +} + +// Some random type parameter lists with elided interfaces. + +type ( + _[T struct{}] struct{} + _[M map[K]V, K comparable, V any] struct{} + _[_ interface{} | int] struct{} +) diff --git a/test/typeparam/issue48453.go b/test/typeparam/issue48453.go new file mode 100644 index 0000000..ef8c7f7 --- /dev/null +++ b/test/typeparam/issue48453.go @@ -0,0 +1,21 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +//go:noinline +func CopyMap[M interface{ ~map[K]V }, K comparable, V any](m M) M { + out := make(M, len(m)) + for k, v := range m { + out[k] = v + } + return out +} + +func main() { + var m map[*string]int + CopyMap(m) +} diff --git a/test/typeparam/issue48454.dir/a.go b/test/typeparam/issue48454.dir/a.go new file mode 100644 index 0000000..9613916 --- /dev/null +++ b/test/typeparam/issue48454.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import "sync" + +type Val[T any] struct { + mu sync.RWMutex + val T +} + +func (v *Val[T]) Has() { + v.mu.RLock() +} diff --git a/test/typeparam/issue48454.dir/b.go b/test/typeparam/issue48454.dir/b.go new file mode 100644 index 0000000..deb59d2 --- /dev/null +++ b/test/typeparam/issue48454.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +type Session struct { + privateField a.Val[string] +} diff --git a/test/typeparam/issue48454.dir/main.go b/test/typeparam/issue48454.dir/main.go new file mode 100644 index 0000000..ad9d290 --- /dev/null +++ b/test/typeparam/issue48454.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./b" + +func main() { + var _ b.Session +} diff --git a/test/typeparam/issue48454.go b/test/typeparam/issue48454.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48454.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48462.dir/a.go b/test/typeparam/issue48462.dir/a.go new file mode 100644 index 0000000..26c704d --- /dev/null +++ b/test/typeparam/issue48462.dir/a.go @@ -0,0 +1,22 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func Unique[T comparable](set []T) []T { + nset := make([]T, 0, 8) + +loop: + for _, s := range set { + for _, e := range nset { + if s == e { + continue loop + } + } + + nset = append(nset, s) + } + + return nset +} diff --git a/test/typeparam/issue48462.dir/main.go b/test/typeparam/issue48462.dir/main.go new file mode 100644 index 0000000..e615367 --- /dev/null +++ b/test/typeparam/issue48462.dir/main.go @@ -0,0 +1,23 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "reflect" + + "./a" +) + +func main() { + e := []int{1, 2, 2, 3, 1, 6} + + got := a.Unique(e) + want := []int{1, 2, 3, 6} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + +} diff --git a/test/typeparam/issue48462.go b/test/typeparam/issue48462.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48462.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48537.go b/test/typeparam/issue48537.go new file mode 100644 index 0000000..3ae85c7 --- /dev/null +++ b/test/typeparam/issue48537.go @@ -0,0 +1,21 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { +} + +type C interface { + map[int]string +} + +func f[A C]() A { + return A{ + 1: "a", + 2: "b", + } +} diff --git a/test/typeparam/issue48538.go b/test/typeparam/issue48538.go new file mode 100644 index 0000000..985f84e --- /dev/null +++ b/test/typeparam/issue48538.go @@ -0,0 +1,60 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Testing composite literal for a type param constrained to be a struct or a map. + +package p + +type C interface { + ~struct{ b1, b2 string } +} + +func f[T C]() T { + return T{ + b1: "a", + b2: "b", + } +} + +func f2[T ~struct{ b1, b2 string }]() T { + return T{ + b1: "a", + b2: "b", + } +} + +type D interface { + map[string]string | S +} + +type S map[string]string + +func g[T D]() T { + b1 := "foo" + b2 := "bar" + return T{ + b1: "a", + b2: "b", + } +} + +func g2[T map[string]string]() T { + b1 := "foo" + b2 := "bar" + return T{ + b1: "a", + b2: "b", + } +} + +func g3[T S]() T { + b1 := "foo" + b2 := "bar" + return T{ + b1: "a", + b2: "b", + } +} diff --git a/test/typeparam/issue48598.go b/test/typeparam/issue48598.go new file mode 100644 index 0000000..945b332 --- /dev/null +++ b/test/typeparam/issue48598.go @@ -0,0 +1,28 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Iterator[T any] interface { + Iterate() +} + +type IteratorFunc[T any] func(fn func(T) bool) + +func (f IteratorFunc[T]) Iterate() { +} + +func FromIterator[T any](it Iterator[T]) { + it.Iterate() +} + +func Foo[T, R any]() { + FromIterator[R](IteratorFunc[R](nil)) +} + +func main() { + Foo[int, int]() +} diff --git a/test/typeparam/issue48602.go b/test/typeparam/issue48602.go new file mode 100644 index 0000000..c544697 --- /dev/null +++ b/test/typeparam/issue48602.go @@ -0,0 +1,25 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Iterator[T any] interface { + Iterate(fn T) +} + +type IteratorFunc[T any] func(fn T) + +func (f IteratorFunc[T]) Iterate(fn T) { + f(fn) +} + +func Foo[R any]() { + var _ Iterator[R] = IteratorFunc[R](nil) +} + +func main() { + Foo[int]() +} diff --git a/test/typeparam/issue48604.go b/test/typeparam/issue48604.go new file mode 100644 index 0000000..348abf7 --- /dev/null +++ b/test/typeparam/issue48604.go @@ -0,0 +1,25 @@ +// build + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Foo[T any] interface { + CreateBar() Bar[T] +} + +type Bar[T any] func() Bar[T] + +func (f Bar[T]) CreateBar() Bar[T] { + return f +} + +func abc[R any]() { + var _ Foo[R] = Bar[R](nil)() +} + +func main() { + abc[int]() +}
\ No newline at end of file diff --git a/test/typeparam/issue48609.go b/test/typeparam/issue48609.go new file mode 100644 index 0000000..53144d2 --- /dev/null +++ b/test/typeparam/issue48609.go @@ -0,0 +1,16 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f[T ~chan E, E any](e E) T { + ch := make(T) + go func() { + defer close(ch) + ch <- e + }() + return ch +} diff --git a/test/typeparam/issue48617.go b/test/typeparam/issue48617.go new file mode 100644 index 0000000..96978d4 --- /dev/null +++ b/test/typeparam/issue48617.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Foo[T any] interface { + CreateBar() Bar[T] +} + +type Bar[T any] func() Bar[T] + +func (f Bar[T]) CreateBar() Bar[T] { + return f +} + +func abc[T any]() { + var b Bar[T] = func() Bar[T] { + var b Bar[T] + return b + } + var _ Foo[T] = b() +} + +func main() { + abc[int]() +} diff --git a/test/typeparam/issue48645a.go b/test/typeparam/issue48645a.go new file mode 100644 index 0000000..39267a9 --- /dev/null +++ b/test/typeparam/issue48645a.go @@ -0,0 +1,31 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "reflect" +) + +type Stream[T any] struct { +} + +func (s Stream[T]) DropWhile() Stream[T] { + return Pipe[T, T](s) +} + +func Pipe[T, R any](s Stream[T]) Stream[R] { + it := func(fn func(R) bool) { + } + fmt.Println(reflect.TypeOf(it).String()) + return Stream[R]{} +} + +func main() { + s := Stream[int]{} + s = s.DropWhile() +} diff --git a/test/typeparam/issue48645a.out b/test/typeparam/issue48645a.out new file mode 100644 index 0000000..5093d0f --- /dev/null +++ b/test/typeparam/issue48645a.out @@ -0,0 +1 @@ +func(func(int) bool) diff --git a/test/typeparam/issue48645b.go b/test/typeparam/issue48645b.go new file mode 100644 index 0000000..619e7ee --- /dev/null +++ b/test/typeparam/issue48645b.go @@ -0,0 +1,81 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Iterator[T any] interface { + Iterate(fn func(T) bool) +} + +type IteratorFunc[T any] func(fn func(T) bool) + +func (f IteratorFunc[T]) Iterate(fn func(T) bool) { + f(fn) +} + +type Stream[T any] struct { + it Iterator[T] +} + +func (s Stream[T]) Iterate(fn func(T) bool) { + if s.it == nil { + return + } + s.it.Iterate(fn) +} + +func FromIterator[T any](it Iterator[T]) Stream[T] { + return Stream[T]{it: it} +} + +func (s Stream[T]) DropWhile(fn func(T) bool) Stream[T] { + return Pipe[T, T](s, func(t T) (T, bool) { + return t, true + }) +} + +func Pipe[T, R any](s Stream[T], op func(d T) (R, bool)) Stream[R] { + it := func(fn func(R) bool) { + // XXX Not getting the closure right when converting to interface. + // s.it.Iterate(func(t T) bool { + // r, ok := op(t) + // if !ok { + // return true + // } + + // return fn(r) + // }) + } + + return FromIterator[R](IteratorFunc[R](it)) +} + +func Reduce[T, U any](s Stream[T], identity U, acc func(U, T) U) (r U) { + r = identity + s.Iterate(func(t T) bool { + r = acc(r, t) + return true + }) + + return r +} + +type myIterator struct { +} + +func (myIterator) Iterate(fn func(int) bool) { +} + +func main() { + s := Stream[int]{} + s.it = myIterator{} + s = s.DropWhile(func(i int) bool { + return false + }) + Reduce(s, nil, func(acc []int, e int) []int { + return append(acc, e) + }) +} diff --git a/test/typeparam/issue48711.go b/test/typeparam/issue48711.go new file mode 100644 index 0000000..477a5d5 --- /dev/null +++ b/test/typeparam/issue48711.go @@ -0,0 +1,18 @@ +// errorcheck + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T interface{ ~[]P }, P any](t T) { // ERROR "instantiation cycle" + if t == nil { + return + } + f[[]T, T]([]T{t}) +} + +func main() { + f[[]int](nil) +} diff --git a/test/typeparam/issue48716.dir/a.go b/test/typeparam/issue48716.dir/a.go new file mode 100644 index 0000000..63e599d --- /dev/null +++ b/test/typeparam/issue48716.dir/a.go @@ -0,0 +1,51 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Pair[L, R any] struct { + L L + R R +} + +func Two[L, R any](l L, r R) Pair[L, R] { + return Pair[L, R]{L: l, R: r} +} + +type Map[K, V any] interface { + Put(K, V) + Len() int + Iterate(func(Pair[K, V]) bool) +} + +type HashMap[K comparable, V any] struct { + m map[K]V +} + +func NewHashMap[K comparable, V any](capacity int) HashMap[K, V] { + var m map[K]V + if capacity >= 1 { + m = make(map[K]V, capacity) + } else { + m = map[K]V{} + } + + return HashMap[K, V]{m: m} +} + +func (m HashMap[K, V]) Put(k K, v V) { + m.m[k] = v +} + +func (m HashMap[K, V]) Len() int { + return len(m.m) +} + +func (m HashMap[K, V]) Iterate(cb func(Pair[K, V]) bool) { + for k, v := range m.m { + if !cb(Two(k, v)) { + return + } + } +} diff --git a/test/typeparam/issue48716.dir/main.go b/test/typeparam/issue48716.dir/main.go new file mode 100644 index 0000000..13a126e --- /dev/null +++ b/test/typeparam/issue48716.dir/main.go @@ -0,0 +1,58 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" +) + +// Creates copy of set +func Copy[T comparable](src MapSet[T]) (dst MapSet[T]) { + dst = HashSet[T](src.Len()) + Fill(src, dst) + return +} + +// Fill src from dst +func Fill[T any](src, dst MapSet[T]) { + src.Iterate(func(t T) bool { + dst.Add(t) + return true + }) + return +} + +type MapSet[T any] struct { + m a.Map[T, struct{}] +} + +func HashSet[T comparable](capacity int) MapSet[T] { + return FromMap[T](a.NewHashMap[T, struct{}](capacity)) +} + +func FromMap[T any](m a.Map[T, struct{}]) MapSet[T] { + return MapSet[T]{ + m: m, + } +} + +func (s MapSet[T]) Add(t T) { + s.m.Put(t, struct{}{}) +} + +func (s MapSet[T]) Len() int { + return s.m.Len() +} + +func (s MapSet[T]) Iterate(cb func(T) bool) { + s.m.Iterate(func(p a.Pair[T, struct{}]) bool { + return cb(p.L) + }) +} + +func main() { + x := FromMap[int](a.NewHashMap[int, struct{}](1)) + Copy[int](x) +} diff --git a/test/typeparam/issue48716.go b/test/typeparam/issue48716.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue48716.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue48838.go b/test/typeparam/issue48838.go new file mode 100644 index 0000000..1711d04 --- /dev/null +++ b/test/typeparam/issue48838.go @@ -0,0 +1,31 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + check[string]() +} + +func check[T any]() { + var result setter[T] + switch result.(type) { + case fooA[T]: + case fooB[T]: + } +} + +type setter[T any] interface { + Set(T) +} + +type fooA[T any] struct{} + +func (fooA[T]) Set(T) {} + +type fooB[T any] struct{} + +func (fooB[T]) Set(T) {} diff --git a/test/typeparam/issue48962.dir/a.go b/test/typeparam/issue48962.dir/a.go new file mode 100644 index 0000000..a6d2734 --- /dev/null +++ b/test/typeparam/issue48962.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2022 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 a + +type ( + A[P any] [10]P + S[P any] struct{ f P } + P[P any] *P + M[K comparable, V any] map[K]V +) diff --git a/test/typeparam/issue48962.dir/b.go b/test/typeparam/issue48962.dir/b.go new file mode 100644 index 0000000..e4eaa06 --- /dev/null +++ b/test/typeparam/issue48962.dir/b.go @@ -0,0 +1,51 @@ +// Copyright 2022 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 b + +import "./a" + +type ( + lA[P any] [10]P + lS[P any] struct{ f P } + lP[P any] *P + lM[K comparable, V any] map[K]V +) + +// local cycles +type ( + A lA[A] // ERROR "invalid recursive type" + S lS[S] // ERROR "invalid recursive type" + P lP[P] // ok (indirection through lP) + M1 lM[int, M1] // ok (indirection through lM) + M2 lM[lA[byte], M2] // ok (indirection through lM) + + A2 lA[lS[lP[A2]]] // ok (indirection through lP) + A3 lA[lS[lS[A3]]] // ERROR "invalid recursive type" +) + +// cycles through imported types +type ( + Ai a.A[Ai] // ERROR "invalid recursive type" + Si a.S[Si] // ERROR "invalid recursive type" + Pi a.P[Pi] // ok (indirection through a.P) + M1i a.M[int, M1i] // ok (indirection through a.M) + M2i a.M[a.A[byte], M2i] // ok (indirection through a.M) + + A2i a.A[a.S[a.P[A2i]]] // ok (indirection through a.P) + A3i a.A[a.S[a.S[A3i]]] // ERROR "invalid recursive type" + + T2 a.S[T0[T2]] // ERROR "invalid recursive type" + T3 T0[Ai] // no follow-on error here +) + +// test case from issue + +type T0[P any] struct { + f P +} + +type T1 struct { // ERROR "invalid recursive type" + _ T0[T1] +} diff --git a/test/typeparam/issue48962.go b/test/typeparam/issue48962.go new file mode 100644 index 0000000..24d0eb0 --- /dev/null +++ b/test/typeparam/issue48962.go @@ -0,0 +1,7 @@ +// errorcheckdir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue49027.dir/a.go b/test/typeparam/issue49027.dir/a.go new file mode 100644 index 0000000..da88297 --- /dev/null +++ b/test/typeparam/issue49027.dir/a.go @@ -0,0 +1,55 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func Conv(v interface{}) string { + return conv[string](v) +} + +func conv[T any](v interface{}) T { + return v.(T) +} + +func Conv2(v interface{}) (string, bool) { + return conv2[string](v) +} + +func conv2[T any](v interface{}) (T, bool) { + x, ok := v.(T) + return x, ok +} + +func Conv3(v interface{}) string { + return conv3[string](v) +} + +func conv3[T any](v interface{}) T { + switch v := v.(type) { + case T: + return v + default: + var z T + return z + } +} + +type Mystring string + +func (Mystring) Foo() { +} + +func Conv4(v interface{Foo()}) Mystring { + return conv4[Mystring](v) +} + +func conv4[T interface{Foo()}](v interface{Foo()}) T { + switch v := v.(type) { + case T: + return v + default: + var z T + return z + } +} diff --git a/test/typeparam/issue49027.dir/main.go b/test/typeparam/issue49027.dir/main.go new file mode 100644 index 0000000..d998c5b --- /dev/null +++ b/test/typeparam/issue49027.dir/main.go @@ -0,0 +1,33 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + s := "foo" + x := a.Conv(s) + if x != s { + panic(fmt.Sprintf("got %s wanted %s", x, s)) + } + y, ok := a.Conv2(s) + if !ok { + panic("conversion failed") + } + if y != s { + panic(fmt.Sprintf("got %s wanted %s", y, s)) + } + z := a.Conv3(s) + if z != s { + panic(fmt.Sprintf("got %s wanted %s", z, s)) + } + w := a.Conv4(a.Mystring(s)) + if w != a.Mystring(s) { + panic(fmt.Sprintf("got %s wanted %s", w, s)) + } +} diff --git a/test/typeparam/issue49027.go b/test/typeparam/issue49027.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue49027.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue49049.go b/test/typeparam/issue49049.go new file mode 100644 index 0000000..b4b3bae --- /dev/null +++ b/test/typeparam/issue49049.go @@ -0,0 +1,27 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type A[T any] interface { + m() +} + +type Z struct { + a,b int +} + +func (z *Z) m() { +} + +func test[T any]() { + var a A[T] = &Z{} + f := a.m + f() +} +func main() { + test[string]() +} diff --git a/test/typeparam/issue49241.dir/a.go b/test/typeparam/issue49241.dir/a.go new file mode 100644 index 0000000..34c9965 --- /dev/null +++ b/test/typeparam/issue49241.dir/a.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type T[P any] struct { + x P +} + +type U struct { + a,b int +} diff --git a/test/typeparam/issue49241.dir/b.go b/test/typeparam/issue49241.dir/b.go new file mode 100644 index 0000000..e5f1e12 --- /dev/null +++ b/test/typeparam/issue49241.dir/b.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +//go:noinline +func F() interface{} { + return a.T[int]{} +} + +//go:noinline +func G() interface{} { + return struct{ X, Y a.U }{} +} diff --git a/test/typeparam/issue49241.dir/c.go b/test/typeparam/issue49241.dir/c.go new file mode 100644 index 0000000..34ea7c3 --- /dev/null +++ b/test/typeparam/issue49241.dir/c.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package c + +import "./a" + +//go:noinline +func F() interface{} { + return a.T[int]{} +} + +//go:noinline +func G() interface{} { + return struct{ X, Y a.U }{} +} diff --git a/test/typeparam/issue49241.dir/main.go b/test/typeparam/issue49241.dir/main.go new file mode 100644 index 0000000..58bb8a0 --- /dev/null +++ b/test/typeparam/issue49241.dir/main.go @@ -0,0 +1,21 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./b" + "./c" +) + +func main() { + if b.G() != c.G() { + println(b.G(), c.G()) + panic("bad") + } + if b.F() != c.F() { + println(b.F(), c.F()) + panic("bad") + } +} diff --git a/test/typeparam/issue49241.go b/test/typeparam/issue49241.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue49241.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue49246.dir/a.go b/test/typeparam/issue49246.dir/a.go new file mode 100644 index 0000000..97459ee --- /dev/null +++ b/test/typeparam/issue49246.dir/a.go @@ -0,0 +1,20 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type R[T any] struct{ v T } + +func (r R[T]) Self() R[T] { return R[T]{} } + +type Fn[T any] func() R[T] + +func X() (r R[int]) { return r.Self() } + +func Y[T any](a Fn[T]) Fn[int] { + return func() (r R[int]) { + // No crash: return R[int]{} + return r.Self() + } +} diff --git a/test/typeparam/issue49246.dir/b.go b/test/typeparam/issue49246.dir/b.go new file mode 100644 index 0000000..5141b72 --- /dev/null +++ b/test/typeparam/issue49246.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func Crash() { a.Y(a.X)() } diff --git a/test/typeparam/issue49246.go b/test/typeparam/issue49246.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue49246.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue49295.go b/test/typeparam/issue49295.go new file mode 100644 index 0000000..f96c896 --- /dev/null +++ b/test/typeparam/issue49295.go @@ -0,0 +1,30 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "io" + +type Reader struct { + buf []byte +} +type Token *[16]byte + +func Read[T interface{ ~*[16]byte }](r *Reader) (t T, err error) { + if n := len(t); len(r.buf) >= n { + t = T(r.buf[:n]) + r.buf = r.buf[n:] + return + } + err = io.EOF + return +} + +func main() { + r := &Reader{buf: []byte("0123456789abcdef")} + token, err := Read[Token](r) + _, _ = token, err +} diff --git a/test/typeparam/issue49309.go b/test/typeparam/issue49309.go new file mode 100644 index 0000000..16c97cd --- /dev/null +++ b/test/typeparam/issue49309.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func genfunc[T any](f func(c T)) { + var r T + + f(r) +} + +func myfunc(c string) { + test2(c) +} + +//go:noinline +func test2(a interface{}) { + _ = a.(string) +} + +func main() { + genfunc(myfunc) +} diff --git a/test/typeparam/issue49421.go b/test/typeparam/issue49421.go new file mode 100644 index 0000000..65c32af --- /dev/null +++ b/test/typeparam/issue49421.go @@ -0,0 +1,27 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + var a, b foo + bar(a, b) +} + +type foo int + +func (a foo) less(b foo) bool { + return a < b +} + +type lesser[T any] interface { + less(T) bool + comparable +} + +func bar[T lesser[T]](a, b T) { + a.less(b) +} diff --git a/test/typeparam/issue49432.go b/test/typeparam/issue49432.go new file mode 100644 index 0000000..d522b22 --- /dev/null +++ b/test/typeparam/issue49432.go @@ -0,0 +1,22 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Handler func(in ...interface{}) + +type Foo[T any] struct{} + +func (b *Foo[T]) Bar(in ...interface{}) {} + +func (b *Foo[T]) Init() { + _ = Handler(b.Bar) +} + +func main() { + c := &Foo[int]{} + c.Init() +} diff --git a/test/typeparam/issue49497.dir/a.go b/test/typeparam/issue49497.dir/a.go new file mode 100644 index 0000000..86062d4 --- /dev/null +++ b/test/typeparam/issue49497.dir/a.go @@ -0,0 +1,26 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F[T any]() A[T] { + var x A[T] + return x +} + +type A[T any] struct { + b B[T] +} + +func (a A[T]) M() C[T] { + return C[T]{ + B: a.b, + } +} + +type B[T any] struct{} + +type C[T any] struct { + B B[T] +} diff --git a/test/typeparam/issue49497.dir/main.go b/test/typeparam/issue49497.dir/main.go new file mode 100644 index 0000000..e74dae0 --- /dev/null +++ b/test/typeparam/issue49497.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + a.F[string]() +} diff --git a/test/typeparam/issue49497.go b/test/typeparam/issue49497.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue49497.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue49516.go b/test/typeparam/issue49516.go new file mode 100644 index 0000000..11b460d --- /dev/null +++ b/test/typeparam/issue49516.go @@ -0,0 +1,26 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type Q[T any] struct { + s []T +} + +func (q *Q[T]) Push(v ...T) { + q.s = append(q.s, v...) +} + +func pushN(push func(*Q[int], ...int), n int) { + var q Q[int] + for i := 0; i < n; i++ { + push(&q, i) + } +} + +func f() { + pushN((*Q[int]).Push, 100) +} diff --git a/test/typeparam/issue49524.dir/a.go b/test/typeparam/issue49524.dir/a.go new file mode 100644 index 0000000..f40075e --- /dev/null +++ b/test/typeparam/issue49524.dir/a.go @@ -0,0 +1,8 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F[T any]() { +} diff --git a/test/typeparam/issue49524.dir/main.go b/test/typeparam/issue49524.dir/main.go new file mode 100644 index 0000000..8787e7e --- /dev/null +++ b/test/typeparam/issue49524.dir/main.go @@ -0,0 +1,11 @@ +package main + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +import "./a" + +func main() { + a.F[int]() +} diff --git a/test/typeparam/issue49524.go b/test/typeparam/issue49524.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue49524.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue49536.dir/a.go b/test/typeparam/issue49536.dir/a.go new file mode 100644 index 0000000..a95ad60 --- /dev/null +++ b/test/typeparam/issue49536.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2022 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 a + +func F() interface{} { return new(T[int]) } + +type T[P any] int + +func (x *T[P]) One() int { return x.Two() } +func (x *T[P]) Two() int { return 0 } diff --git a/test/typeparam/issue49536.dir/b.go b/test/typeparam/issue49536.dir/b.go new file mode 100644 index 0000000..b08a77b --- /dev/null +++ b/test/typeparam/issue49536.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2022 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 b + +import "./a" + +var _ = a.F() diff --git a/test/typeparam/issue49536.go b/test/typeparam/issue49536.go new file mode 100644 index 0000000..8bb5c3e --- /dev/null +++ b/test/typeparam/issue49536.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue49538.go b/test/typeparam/issue49538.go new file mode 100644 index 0000000..cb22a06 --- /dev/null +++ b/test/typeparam/issue49538.go @@ -0,0 +1,23 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type I interface { + M(interface{}) +} + +type a[T any] struct{} + +func (a[T]) M(interface{}) {} + +func f[T I](t *T) { + (*t).M(t) +} + +func g() { + f(&a[int]{}) +} diff --git a/test/typeparam/issue49547.go b/test/typeparam/issue49547.go new file mode 100644 index 0000000..6d359ba --- /dev/null +++ b/test/typeparam/issue49547.go @@ -0,0 +1,22 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +type foo int + +func main() { + want := "main.F[main.foo]" + got := fmt.Sprintf("%T", F[foo]{}) + if got != want { + fmt.Printf("want: %s, got: %s\n", want, got) + } +} + +type F[T any] struct { +} diff --git a/test/typeparam/issue49611.go b/test/typeparam/issue49611.go new file mode 100644 index 0000000..879e4d2 --- /dev/null +++ b/test/typeparam/issue49611.go @@ -0,0 +1,11 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f[T any]() { + var () +} diff --git a/test/typeparam/issue49659.dir/a.go b/test/typeparam/issue49659.dir/a.go new file mode 100644 index 0000000..718bc0c --- /dev/null +++ b/test/typeparam/issue49659.dir/a.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type A[T any] struct { + a int +} + +func (a A[T]) F() { + _ = &a.a +} diff --git a/test/typeparam/issue49659.dir/b.go b/test/typeparam/issue49659.dir/b.go new file mode 100644 index 0000000..4818a42 --- /dev/null +++ b/test/typeparam/issue49659.dir/b.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +type B[T any] struct { + v a.A[T] +} + +func (b B[T]) F() { + b.v.F() +} diff --git a/test/typeparam/issue49659.go b/test/typeparam/issue49659.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue49659.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue49659b.go b/test/typeparam/issue49659b.go new file mode 100644 index 0000000..7e1535e --- /dev/null +++ b/test/typeparam/issue49659b.go @@ -0,0 +1,28 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Testing that AddrTaken logic doesn't cause problems for function instantiations + +package main + +type A[T interface{ []int | [5]int }] struct { + val T +} + +//go:noinline +func (a A[T]) F() { + _ = &a.val[2] +} + +func main() { + var x A[[]int] + x.val = make([]int, 4) + _ = &x.val[3] + x.F() + var y A[[5]int] + _ = &y.val[3] + y.F() +} diff --git a/test/typeparam/issue49667.dir/a.go b/test/typeparam/issue49667.dir/a.go new file mode 100644 index 0000000..3b1889f --- /dev/null +++ b/test/typeparam/issue49667.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type A[T any] struct { +} + +func (a A[T]) F() { + _ = a +} diff --git a/test/typeparam/issue49667.dir/b.go b/test/typeparam/issue49667.dir/b.go new file mode 100644 index 0000000..81cdb80 --- /dev/null +++ b/test/typeparam/issue49667.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +type B[T any] struct { + _ a.A[T] +} diff --git a/test/typeparam/issue49667.dir/main.go b/test/typeparam/issue49667.dir/main.go new file mode 100644 index 0000000..f9fa60f --- /dev/null +++ b/test/typeparam/issue49667.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./b" + +func main() { + var _ b.B[int] +} diff --git a/test/typeparam/issue49667.go b/test/typeparam/issue49667.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue49667.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue49875.go b/test/typeparam/issue49875.go new file mode 100644 index 0000000..3fbe48c --- /dev/null +++ b/test/typeparam/issue49875.go @@ -0,0 +1,14 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f(args ...interface{}) {} + +func g() { + var args []any + f(args...) +} diff --git a/test/typeparam/issue49893.dir/a.go b/test/typeparam/issue49893.dir/a.go new file mode 100644 index 0000000..bc810cd --- /dev/null +++ b/test/typeparam/issue49893.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Option[T any] interface { + ToSeq() Seq[T] +} + +type Seq[T any] []T + +func (r Seq[T]) Find(p func(v T) bool) Option[T] { + panic("") +} diff --git a/test/typeparam/issue49893.dir/b.go b/test/typeparam/issue49893.dir/b.go new file mode 100644 index 0000000..b86b536 --- /dev/null +++ b/test/typeparam/issue49893.dir/b.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +type Ap1[A, B any] struct { + opt a.Option[A] +} + +type Ap2[A, B any] struct { + opt a.Option[A] +} diff --git a/test/typeparam/issue49893.dir/main.go b/test/typeparam/issue49893.dir/main.go new file mode 100644 index 0000000..447212d --- /dev/null +++ b/test/typeparam/issue49893.dir/main.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./b" + "fmt" +) + +func main() { + opt := b.Ap1[string, string]{} + fmt.Println(opt) +} diff --git a/test/typeparam/issue49893.go b/test/typeparam/issue49893.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue49893.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue50002.go b/test/typeparam/issue50002.go new file mode 100644 index 0000000..42d97f5 --- /dev/null +++ b/test/typeparam/issue50002.go @@ -0,0 +1,64 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test for cases where certain instantiations of a generic function (F in this +// example) will always fail on a type assertion or mismatch on a type case. + +package main + +import "fmt" + +type S struct{} + +func (S) M() byte { + return 0 +} + +type I[T any] interface { + M() T +} + +func F[T, A any](x I[T], shouldMatch bool) { + switch x.(type) { + case A: + if !shouldMatch { + fmt.Printf("wanted mis-match, got match") + } + default: + if shouldMatch { + fmt.Printf("wanted match, got mismatch") + } + } + + _, ok := x.(A) + if ok != shouldMatch { + fmt.Printf("ok: got %v, wanted %v", ok, shouldMatch) + } + + if !shouldMatch { + defer func() { + if shouldMatch { + fmt.Printf("Shouldn't have panicked") + } + recover() + }() + } + _ = x.(A) + if !shouldMatch { + fmt.Printf("Should have panicked") + } +} + +func main() { + // Test instantiation where the type switch/type asserts can't possibly succeed + // (since string does not implement I[byte]). + F[byte, string](S{}, false) + + // Test instantiation where the type switch/type asserts should succeed + // (since S does implement I[byte]) + F[byte, S](S{}, true) + F[byte, S](I[byte](S{}), true) +} diff --git a/test/typeparam/issue50109.go b/test/typeparam/issue50109.go new file mode 100644 index 0000000..30aebb2 --- /dev/null +++ b/test/typeparam/issue50109.go @@ -0,0 +1,105 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type AnyCacher[T any] interface { + // Get an item from the cache. Returns the item or nil, and a bool indicating + // whether the key was found. + Get(k string) (T, bool) + // Add an item to the cache, replacing any existing item. + Set(k string, x T) +} + +// Item ... +type Item[T any] struct { + Object T +} + +// AnyCache implements AnyCacher +type AnyCache[T any] struct { + *anyCache[T] +} + +type anyCache[T any] struct { + items map[string]Item[T] + janitor *janitor[T] // Needed for the failure in the issue +} + +// Set adds an item to the cache, replacing any existing item. +func (c *anyCache[T]) Set(k string, x T) { + c.items[k] = Item[T]{ + Object: x, + } +} + +// Get gets an item from the cache. Returns the item or nil, and a bool indicating +// whether the key was found. +func (c *anyCache[T]) Get(k string) (T, bool) { + // "Inlining" of get and Expired + item, found := c.items[k] + if !found { + var ret T + return ret, false + } + + return item.Object, true +} + +type janitor[T any] struct { + stop chan bool +} + +func newAnyCache[T any](m map[string]Item[T]) *anyCache[T] { + c := &anyCache[T]{ + items: m, + } + return c +} + +// NewAny[T any](...) returns a new AnyCache[T]. +func NewAny[T any]() *AnyCache[T] { + items := make(map[string]Item[T]) + return &AnyCache[T]{newAnyCache(items)} +} + +// NewAnyCacher[T any](...) returns an AnyCacher[T] interface. +func NewAnyCacher[T any]() AnyCacher[T] { + return NewAny[T]() +} + +type MyStruct struct { + Name string +} + +func main() { + // Create a generic cache. + // All items are cached as interface{} so they need to be cast back to their + // original type when retrieved. + // Failure in issue doesn't happen with 'any' replaced by 'interface{}' + c := NewAnyCacher[any]() + + myStruct := &MyStruct{"MySuperStruct"} + + c.Set("MySuperStruct", myStruct) + + myRawCachedStruct, found := c.Get("MySuperStruct") + + if found { + // Casting the retrieved object back to its original type + myCachedStruct := myRawCachedStruct.(*MyStruct) + fmt.Printf("%s", myCachedStruct.Name) + } else { + fmt.Printf("Error: MySuperStruct not found in cache") + } + + // Output: + // MySuperStruct +} diff --git a/test/typeparam/issue50109.out b/test/typeparam/issue50109.out new file mode 100644 index 0000000..7d6ecc0 --- /dev/null +++ b/test/typeparam/issue50109.out @@ -0,0 +1 @@ +MySuperStruct
\ No newline at end of file diff --git a/test/typeparam/issue50109b.go b/test/typeparam/issue50109b.go new file mode 100644 index 0000000..ee49441 --- /dev/null +++ b/test/typeparam/issue50109b.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + F[any]() +} + +func F[T any]() I[T] { + return (*S1[T])(nil) +} + +type I[T any] interface{} + +type S1[T any] struct { + *S2[T] +} + +type S2[T any] struct { + S3 *S3[T] +} + +type S3[T any] struct { + x int +} diff --git a/test/typeparam/issue50121.dir/a.go b/test/typeparam/issue50121.dir/a.go new file mode 100644 index 0000000..ca11b6b --- /dev/null +++ b/test/typeparam/issue50121.dir/a.go @@ -0,0 +1,26 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import ( + "math/rand" +) + +type Integer interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +type Builder[T Integer] struct{} + +func (r Builder[T]) New() T { + return T(rand.Int()) +} + +var IntBuilder = Builder[int]{} + +func BuildInt() int { + return IntBuilder.New() +} diff --git a/test/typeparam/issue50121.dir/main.go b/test/typeparam/issue50121.dir/main.go new file mode 100644 index 0000000..3978ef4 --- /dev/null +++ b/test/typeparam/issue50121.dir/main.go @@ -0,0 +1,18 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" +) + +//go:noinline +func BuildInt() int { + return a.BuildInt() +} + +func main() { + BuildInt() +} diff --git a/test/typeparam/issue50121.go b/test/typeparam/issue50121.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue50121.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue50121b.dir/a.go b/test/typeparam/issue50121b.dir/a.go new file mode 100644 index 0000000..4ddbb6e --- /dev/null +++ b/test/typeparam/issue50121b.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2022 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 a + +type Integer interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +type Builder[T Integer] struct{} + +func (r Builder[T]) New() T { + return T(42) +} diff --git a/test/typeparam/issue50121b.dir/b.go b/test/typeparam/issue50121b.dir/b.go new file mode 100644 index 0000000..efa6cbb --- /dev/null +++ b/test/typeparam/issue50121b.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 b + +import ( + "./a" +) + +var IntBuilder = a.Builder[int]{} diff --git a/test/typeparam/issue50121b.dir/c.go b/test/typeparam/issue50121b.dir/c.go new file mode 100644 index 0000000..1691356 --- /dev/null +++ b/test/typeparam/issue50121b.dir/c.go @@ -0,0 +1,13 @@ +// Copyright 2022 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 c + +import ( + "./b" +) + +func BuildInt() int { + return b.IntBuilder.New() +} diff --git a/test/typeparam/issue50121b.dir/d.go b/test/typeparam/issue50121b.dir/d.go new file mode 100644 index 0000000..93b40c9 --- /dev/null +++ b/test/typeparam/issue50121b.dir/d.go @@ -0,0 +1,13 @@ +// Copyright 2022 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 d + +import ( + "./c" +) + +func BuildInt() int { + return c.BuildInt() +} diff --git a/test/typeparam/issue50121b.dir/main.go b/test/typeparam/issue50121b.dir/main.go new file mode 100644 index 0000000..3398601 --- /dev/null +++ b/test/typeparam/issue50121b.dir/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "./d" + "fmt" +) + +func main() { + if got, want := d.BuildInt(), 42; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/issue50121b.go b/test/typeparam/issue50121b.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/issue50121b.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue50147.go b/test/typeparam/issue50147.go new file mode 100644 index 0000000..f97bace --- /dev/null +++ b/test/typeparam/issue50147.go @@ -0,0 +1,11 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func Foo[T any, U interface{ *T }](x T) { + var _ U = &x +} diff --git a/test/typeparam/issue50177.go b/test/typeparam/issue50177.go new file mode 100644 index 0000000..c4858fc --- /dev/null +++ b/test/typeparam/issue50177.go @@ -0,0 +1,101 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +type Fn[T any] func(T) +type FnErr[T any] func(T) error + +// Test that local generic types across functions don't conflict, and they also don't +// conflict with local non-generic types and local variables. +func caller0() { + type X[T any] struct { + fn Fn[int] + } + + x := X[int]{func(v int) { fmt.Println(v) }} + x.fn(0) +} + +func caller1(val int) { + type X[T any] struct { + fn FnErr[int] + } + + x := X[int]{func(v int) error { fmt.Println(v); return nil }} + x.fn(0) +} + +func caller1a(val int) { + type X struct { + fn func(float64) error + } + + x := X{func(v float64) error { fmt.Println(v); return nil }} + x.fn(float64(3.2)) +} + +func caller1b(val int) { + type Y struct { + fn func(float64) error + } + + X := Y{func(v float64) error { fmt.Println(v); return nil }} + X.fn(float64(3.2)) +} + +// Test that local generic types within different if clauses don't conflict. +func caller2(val int) { + if val > 2 { + type X[T any] struct { + fn func(v int) float64 + } + + x := X[int]{func(v int) float64 { fmt.Println(v); return 1.5 }} + x.fn(0) + } else { + type X[T any] struct { + fn func(v int) int + } + x := X[int]{func(v int) int { fmt.Println(v); return 5 }} + x.fn(0) + } +} + +// Test that local generic types within different cases don't conflict with each +// other or with local non-generic types or local variables. +func caller3(val int) { + switch val { + case 0: + type X[T any] struct { + fn func(v int) float64 + } + + x := X[int]{func(v int) float64 { fmt.Println(v); return 1.5 }} + x.fn(0) + case 1: + type X[T any] struct { + fn func(v int) int + } + x := X[int]{func(v int) int { fmt.Println(v); return 5 }} + x.fn(0) + case 2: + type X struct { + fn func(v int) bool + } + x := X{func(v int) bool { fmt.Println(v); return false }} + x.fn(0) + case 3: + type Y struct { + fn func(v int) bool + } + X := Y{func(v int) bool { fmt.Println(v); return false }} + X.fn(0) + + } +} diff --git a/test/typeparam/issue50193.go b/test/typeparam/issue50193.go new file mode 100644 index 0000000..8b4b841 --- /dev/null +++ b/test/typeparam/issue50193.go @@ -0,0 +1,35 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type Complex interface { + ~complex64 | ~complex128 +} + +func zero[T Complex]() T { + return T(0) +} +func pi[T Complex]() T { + return T(3.14) +} +func sqrtN1[T Complex]() T { + return T(-1i) +} + +func main() { + fmt.Println(zero[complex128]()) + fmt.Println(pi[complex128]()) + fmt.Println(sqrtN1[complex128]()) + fmt.Println(zero[complex64]()) + fmt.Println(pi[complex64]()) + fmt.Println(sqrtN1[complex64]()) +} + diff --git a/test/typeparam/issue50193.out b/test/typeparam/issue50193.out new file mode 100644 index 0000000..6818622 --- /dev/null +++ b/test/typeparam/issue50193.out @@ -0,0 +1,6 @@ +(0+0i) +(3.14+0i) +(0-1i) +(0+0i) +(3.14+0i) +(0-1i) diff --git a/test/typeparam/issue50259.go b/test/typeparam/issue50259.go new file mode 100644 index 0000000..50edf8f --- /dev/null +++ b/test/typeparam/issue50259.go @@ -0,0 +1,13 @@ +// compile + +// Copyright 2022 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 + +var x T[B] + +type T[_ any] struct{} +type A T[B] +type B = T[A] diff --git a/test/typeparam/issue50264.go b/test/typeparam/issue50264.go new file mode 100644 index 0000000..1acab87 --- /dev/null +++ b/test/typeparam/issue50264.go @@ -0,0 +1,45 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type hello struct{} + +func main() { + _ = Some(hello{}) + res := Applicative2(func(a int, b int) int { + return 0 + }) + _ = res +} + +type NoneType[T any] struct{} + +func (r NoneType[T]) Recover() any { + return nil +} + +type Func2[A1, A2, R any] func(a1 A1, a2 A2) R + +func Some[T any](v T) any { + _ = Some2[T](v) + return NoneType[T]{}.Recover() +} + +//go:noinline +func Some2[T any](v T) any { + return v +} + +type Nil struct{} + +type ApplicativeFunctor2[H, HT, A1, A2, R any] struct { + h any +} + +func Applicative2[A1, A2, R any](fn Func2[A1, A2, R]) ApplicativeFunctor2[Nil, Nil, A1, A2, R] { + return ApplicativeFunctor2[Nil, Nil, A1, A2, R]{Some(Nil{})} +} diff --git a/test/typeparam/issue50317.go b/test/typeparam/issue50317.go new file mode 100644 index 0000000..c33c4f0 --- /dev/null +++ b/test/typeparam/issue50317.go @@ -0,0 +1,15 @@ +// errorcheck + +// Copyright 2022 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 S struct{} + +func (S) _[_ any]() {} // ERROR "method must have no type parameters" + +type _ interface { + m[_ any]() // ERROR "method must have no type parameters" +} diff --git a/test/typeparam/issue50417.go b/test/typeparam/issue50417.go new file mode 100644 index 0000000..b32e270 --- /dev/null +++ b/test/typeparam/issue50417.go @@ -0,0 +1,146 @@ +// run + +// Copyright 2022 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 main + +func main() {} + +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. + +/* +type Sf struct { + f int +} + +func f0[P Sf](p P) { + _ = p.f + p.f = 0 +} + +func f0t[P ~struct{ f int }](p P) { + _ = p.f + p.f = 0 +} + +var _ = f0[Sf] +var _ = f0t[Sf] + +func f1[P interface { + ~struct{ f int } + m() +}](p P) { + _ = p.f + p.f = 0 + p.m() +} + +var _ = f1[Sfm] + +type Sm struct{} + +func (Sm) m() {} + +type Sfm struct { + f int +} + +func (Sfm) m() {} + +func f2[P interface { + Sfm + m() +}](p P) { + _ = p.f + p.f = 0 + p.m() +} + +var _ = f2[Sfm] + +// special case: core type is a named pointer type + +type PSfm *Sfm + +func f3[P interface{ PSfm }](p P) { + _ = p.f + p.f = 0 +} + +var _ = f3[PSfm] + +// special case: core type is an unnamed pointer type + +func f4[P interface{ *Sfm }](p P) { + _ = p.f + p.f = 0 +} + +var _ = f4[*Sfm] + +type A int +type B int +type C float64 + +type Int interface { + *Sf | A + *Sf | B +} + +func f5[P Int](p P) { + _ = p.f + p.f = 0 +} + +var _ = f5[*Sf] + +type Int2 interface { + *Sf | A + any + *Sf | C +} + +func f6[P Int2](p P) { + _ = p.f + p.f = 0 +} + +var _ = f6[*Sf] + +type Int3 interface { + Sf + ~struct{ f int } +} + +func f7[P Int3](p P) { + _ = p.f + p.f = 0 +} + +var _ = f7[Sf] + +type Em1 interface { + *Sf | A +} + +type Em2 interface { + *Sf | B +} + +type Int4 interface { + Em1 + Em2 + any +} + +func f8[P Int4](p P) { + _ = p.f + p.f = 0 +} + +var _ = f8[*Sf] +*/ diff --git a/test/typeparam/issue50417b.go b/test/typeparam/issue50417b.go new file mode 100644 index 0000000..1c803b0 --- /dev/null +++ b/test/typeparam/issue50417b.go @@ -0,0 +1,58 @@ +// run + +// Copyright 2022 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 main + +func main() {} + +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. + +/* +import "fmt" + +type MyStruct struct { + b1, b2 string + E +} + +type E struct { + val int +} + +type C interface { + ~struct { + b1, b2 string + E + } +} + +func f[T C]() T { + var x T = T{ + b1: "a", + b2: "b", + } + + if got, want := x.b2, "b"; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + x.b1 = "y" + x.val = 5 + + return x +} + +func main() { + x := f[MyStruct]() + if got, want := x.b1, "y"; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + if got, want := x.val, 5; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} +*/ diff --git a/test/typeparam/issue50419.go b/test/typeparam/issue50419.go new file mode 100644 index 0000000..dfe55f9 --- /dev/null +++ b/test/typeparam/issue50419.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2022 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 that type substitution works correctly even for a method of a generic type +// that has multiple blank type params. + +package main + +import ( + "fmt" +) + +func main() { + foo := &Foo[string, int]{ + valueA: "i am a string", + valueB: 123, + } + if got, want := fmt.Sprintln(foo), "i am a string 123\n"; got != want { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } +} + +type Foo[T1 any, T2 any] struct { + valueA T1 + valueB T2 +} + +func (f *Foo[_, _]) String() string { + return fmt.Sprintf("%v %v", f.valueA, f.valueB) +} diff --git a/test/typeparam/issue50437.dir/a.go b/test/typeparam/issue50437.dir/a.go new file mode 100644 index 0000000..4a136b5 --- /dev/null +++ b/test/typeparam/issue50437.dir/a.go @@ -0,0 +1,43 @@ +// Copyright 2022 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 a + +type MarshalOptions struct { + *typedArshalers[MarshalOptions] +} + +func Marshal(in interface{}) (out []byte, err error) { + return MarshalOptions{}.Marshal(in) +} + +func (mo MarshalOptions) Marshal(in interface{}) (out []byte, err error) { + err = mo.MarshalNext(in) + return nil, err +} + +func (mo MarshalOptions) MarshalNext(in interface{}) error { + a := new(arshaler) + a.marshal = func(MarshalOptions) error { return nil } + return a.marshal(mo) +} + +type arshaler struct { + marshal func(MarshalOptions) error +} + +type typedArshalers[Options any] struct { + m M +} + +func (a *typedArshalers[Options]) lookup(fnc func(Options) error) (func(Options) error, bool) { + a.m.Load(nil) + return fnc, false +} + +type M struct {} + +func (m *M) Load(key any) (value any, ok bool) { + return +} diff --git a/test/typeparam/issue50437.dir/b.go b/test/typeparam/issue50437.dir/b.go new file mode 100644 index 0000000..afddc3f --- /dev/null +++ b/test/typeparam/issue50437.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 b + +import "./a" + +func f() { + a.Marshal(map[int]int{}) +} diff --git a/test/typeparam/issue50437.go b/test/typeparam/issue50437.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue50437.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue50481b.dir/b.go b/test/typeparam/issue50481b.dir/b.go new file mode 100644 index 0000000..d458357 --- /dev/null +++ b/test/typeparam/issue50481b.dir/b.go @@ -0,0 +1,16 @@ +// Copyright 2022 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 b + +import "fmt" + +type Foo[T1 ~string, T2 ~int] struct { + ValueA T1 + ValueB T2 +} + +func (f *Foo[_, _]) String() string { + return fmt.Sprintf("%v %v", f.ValueA, f.ValueB) +} diff --git a/test/typeparam/issue50481b.dir/main.go b/test/typeparam/issue50481b.dir/main.go new file mode 100644 index 0000000..6a5067c --- /dev/null +++ b/test/typeparam/issue50481b.dir/main.go @@ -0,0 +1,23 @@ +// Copyright 2022 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 that type substitution and export/import works correctly even for a method of +// a generic type that has multiple blank type params. + +package main + +import ( + "./b" + "fmt" +) + +func main() { + foo := &b.Foo[string, int]{ + ValueA: "i am a string", + ValueB: 123, + } + if got, want := fmt.Sprintln(foo), "i am a string 123\n"; got != want { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } +} diff --git a/test/typeparam/issue50481b.go b/test/typeparam/issue50481b.go new file mode 100644 index 0000000..aefbe67 --- /dev/null +++ b/test/typeparam/issue50481b.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue50481c.dir/a.go b/test/typeparam/issue50481c.dir/a.go new file mode 100644 index 0000000..384ba23 --- /dev/null +++ b/test/typeparam/issue50481c.dir/a.go @@ -0,0 +1,30 @@ +// Copyright 2022 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 a + +type A interface { + int | int64 +} + +type B interface { + string +} + +type C interface { + String() string +} + +type Myint int + +func (i Myint) String() string { + return "aa" +} + +type T[P A, _ C, _ B] int + +func (v T[P, Q, R]) test() { + var r Q + r.String() +} diff --git a/test/typeparam/issue50481c.dir/main.go b/test/typeparam/issue50481c.dir/main.go new file mode 100644 index 0000000..178542b --- /dev/null +++ b/test/typeparam/issue50481c.dir/main.go @@ -0,0 +1,18 @@ +// Copyright 2022 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 that type substitution works and export/import works correctly even for a +// generic type that has multiple blank type params. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + var x a.T[int, a.Myint, string] + fmt.Printf("%v\n", x) +} diff --git a/test/typeparam/issue50481c.go b/test/typeparam/issue50481c.go new file mode 100644 index 0000000..aefbe67 --- /dev/null +++ b/test/typeparam/issue50481c.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue50481c.out b/test/typeparam/issue50481c.out new file mode 100644 index 0000000..573541a --- /dev/null +++ b/test/typeparam/issue50481c.out @@ -0,0 +1 @@ +0 diff --git a/test/typeparam/issue50485.dir/a.go b/test/typeparam/issue50485.dir/a.go new file mode 100644 index 0000000..3a7c71a --- /dev/null +++ b/test/typeparam/issue50485.dir/a.go @@ -0,0 +1,239 @@ +package a + +import "fmt" + +type ImplicitOrd interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +func LessGiven[T ImplicitOrd]() Ord[T] { + return LessFunc[T](func(a, b T) bool { + return a < b + }) +} + +type Eq[T any] interface { + Eqv(a T, b T) bool +} + +type Ord[T any] interface { + Eq[T] + Less(a T, b T) bool +} + +type LessFunc[T any] func(a, b T) bool + +func (r LessFunc[T]) Eqv(a, b T) bool { + return r(a, b) == false && r(b, a) == false +} + +func (r LessFunc[T]) Less(a, b T) bool { + return r(a, b) +} + +type Option[T any] struct { + v *T +} + +func (r Option[T]) IsDefined() bool { + return r.v != nil +} + +func (r Option[T]) IsEmpty() bool { + return !r.IsDefined() +} + +func (r Option[T]) Get() T { + return *r.v +} + +func (r Option[T]) String() string { + if r.IsDefined() { + return fmt.Sprintf("Some(%v)", r.v) + } else { + return "None" + } +} + +func (r Option[T]) OrElse(t T) T { + if r.IsDefined() { + return *r.v + } + return t +} + +func (r Option[T]) Recover(f func() T) Option[T] { + if r.IsDefined() { + return r + } + t := f() + return Option[T]{&t} +} + +type Func1[A1, R any] func(a1 A1) R + +type Func2[A1, A2, R any] func(a1 A1, a2 A2) R + +func (r Func2[A1, A2, R]) Curried() Func1[A1, Func1[A2, R]] { + return func(a1 A1) Func1[A2, R] { + return Func1[A2, R](func(a2 A2) R { + return r(a1, a2) + }) + } +} + +type HList interface { + sealed() +} + +// Header is constrains interface type, enforce Head type of Cons is HT +type Header[HT any] interface { + HList + Head() HT +} + +// Cons means H :: T +// zero value of Cons[H,T] is not allowed. +// so Cons defined as interface type +type Cons[H any, T HList] interface { + HList + Head() H + Tail() T +} + +type Nil struct { +} + +func (r Nil) Head() Nil { + return r +} + +func (r Nil) Tail() Nil { + return r +} + +func (r Nil) String() string { + return "Nil" +} + +func (r Nil) sealed() { + +} + +type hlistImpl[H any, T HList] struct { + head H + tail T +} + +func (r hlistImpl[H, T]) Head() H { + return r.head +} + +func (r hlistImpl[H, T]) Tail() T { + return r.tail +} + +func (r hlistImpl[H, T]) String() string { + return fmt.Sprintf("%v :: %v", r.head, r.tail) +} + +func (r hlistImpl[H, T]) sealed() { + +} + +func hlist[H any, T HList](h H, t T) Cons[H, T] { + return hlistImpl[H, T]{h, t} +} + +func Concat[H any, T HList](h H, t T) Cons[H, T] { + return hlist(h, t) +} + +func Empty() Nil { + return Nil{} +} +func Some[T any](v T) Option[T] { + return Option[T]{}.Recover(func() T { + return v + }) +} + +func None[T any]() Option[T] { + return Option[T]{} +} + +func Ap[T, U any](t Option[Func1[T, U]], a Option[T]) Option[U] { + return FlatMap(t, func(f Func1[T, U]) Option[U] { + return Map(a, f) + }) +} + +func Map[T, U any](opt Option[T], f func(v T) U) Option[U] { + return FlatMap(opt, func(v T) Option[U] { + return Some(f(v)) + }) +} + +func FlatMap[T, U any](opt Option[T], fn func(v T) Option[U]) Option[U] { + if opt.IsDefined() { + return fn(opt.Get()) + } + return None[U]() +} + +type ApplicativeFunctor1[H Header[HT], HT, A, R any] struct { + h Option[H] + fn Option[Func1[A, R]] +} + +func (r ApplicativeFunctor1[H, HT, A, R]) ApOption(a Option[A]) Option[R] { + return Ap(r.fn, a) +} + +func (r ApplicativeFunctor1[H, HT, A, R]) Ap(a A) Option[R] { + return r.ApOption(Some(a)) +} + +func Applicative1[A, R any](fn Func1[A, R]) ApplicativeFunctor1[Nil, Nil, A, R] { + return ApplicativeFunctor1[Nil, Nil, A, R]{Some(Empty()), Some(fn)} +} + +type ApplicativeFunctor2[H Header[HT], HT, A1, A2, R any] struct { + h Option[H] + fn Option[Func1[A1, Func1[A2, R]]] +} + +func (r ApplicativeFunctor2[H, HT, A1, A2, R]) ApOption(a Option[A1]) ApplicativeFunctor1[Cons[A1, H], A1, A2, R] { + + nh := FlatMap(r.h, func(hv H) Option[Cons[A1, H]] { + return Map(a, func(av A1) Cons[A1, H] { + return Concat(av, hv) + }) + }) + + return ApplicativeFunctor1[Cons[A1, H], A1, A2, R]{nh, Ap(r.fn, a)} +} +func (r ApplicativeFunctor2[H, HT, A1, A2, R]) Ap(a A1) ApplicativeFunctor1[Cons[A1, H], A1, A2, R] { + + return r.ApOption(Some(a)) + +} + +func Applicative2[A1, A2, R any](fn Func2[A1, A2, R]) ApplicativeFunctor2[Nil, Nil, A1, A2, R] { + return ApplicativeFunctor2[Nil, Nil, A1, A2, R]{Some(Empty()), Some(fn.Curried())} +} +func OrdOption[T any](m Ord[T]) Ord[Option[T]] { + return LessFunc[Option[T]](func(t1 Option[T], t2 Option[T]) bool { + if !t1.IsDefined() && !t2.IsDefined() { + return false + } + return Applicative2(m.Less).ApOption(t1).ApOption(t2).OrElse(!t1.IsDefined()) + }) +} + +func Given[T ImplicitOrd]() Ord[T] { + return LessGiven[T]() +} diff --git a/test/typeparam/issue50485.dir/main.go b/test/typeparam/issue50485.dir/main.go new file mode 100644 index 0000000..7181b93 --- /dev/null +++ b/test/typeparam/issue50485.dir/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "./a" +) + +func main() { + _ = a.OrdOption(a.Given[int]()) +} diff --git a/test/typeparam/issue50485.go b/test/typeparam/issue50485.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue50485.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue50486.dir/goerror_fp.go b/test/typeparam/issue50486.dir/goerror_fp.go new file mode 100644 index 0000000..fec9095 --- /dev/null +++ b/test/typeparam/issue50486.dir/goerror_fp.go @@ -0,0 +1,75 @@ +// Copyright 2022 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 goerror_fp + +type Seq[T any] []T + +func (r Seq[T]) Size() int { + return len(r) +} + +func (r Seq[T]) Append(items ...T) Seq[T] { + tail := Seq[T](items) + ret := make(Seq[T], r.Size()+tail.Size()) + + for i := range r { + ret[i] = r[i] + } + + for i := range tail { + ret[i+r.Size()] = tail[i] + } + + return ret +} + +func (r Seq[T]) Iterator() Iterator[T] { + idx := 0 + + return Iterator[T]{ + IsHasNext: func() bool { + return idx < r.Size() + }, + GetNext: func() T { + ret := r[idx] + idx++ + return ret + }, + } +} + +type Iterator[T any] struct { + IsHasNext func() bool + GetNext func() T +} + +func (r Iterator[T]) ToSeq() Seq[T] { + ret := Seq[T]{} + for r.HasNext() { + ret = append(ret, r.Next()) + } + return ret +} + +func (r Iterator[T]) Map(f func(T) any) Iterator[any] { + return MakeIterator(r.HasNext, func() any { + return f(r.Next()) + }) +} + +func (r Iterator[T]) HasNext() bool { + return r.IsHasNext() +} + +func (r Iterator[T]) Next() T { + return r.GetNext() +} + +func MakeIterator[T any](has func() bool, next func() T) Iterator[T] { + return Iterator[T]{ + IsHasNext: has, + GetNext: next, + } +} diff --git a/test/typeparam/issue50486.dir/main.go b/test/typeparam/issue50486.dir/main.go new file mode 100644 index 0000000..c2c8eea --- /dev/null +++ b/test/typeparam/issue50486.dir/main.go @@ -0,0 +1,16 @@ +package main + +import fp "./goerror_fp" + +func Fold[A, B any](zero B, a A, f func(B, A) B) B { + return f(zero, a) +} + +func main() { + + var v any = "hello" + Fold(fp.Seq[any]{}, v, func(seq fp.Seq[any], v any) fp.Seq[any] { + return seq.Append(v) + }) + +} diff --git a/test/typeparam/issue50486.go b/test/typeparam/issue50486.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue50486.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue50552.dir/a.go b/test/typeparam/issue50552.dir/a.go new file mode 100644 index 0000000..89b9bcb --- /dev/null +++ b/test/typeparam/issue50552.dir/a.go @@ -0,0 +1,16 @@ +package a + +type Builder[T any] struct{} + +func (r Builder[T]) New() T { + var v T + return v +} + +func (r Builder[T]) New2() T { + return r.New() +} + +func BuildInt() int { + return Builder[int]{}.New() +} diff --git a/test/typeparam/issue50552.dir/main.go b/test/typeparam/issue50552.dir/main.go new file mode 100644 index 0000000..0ff2ed3 --- /dev/null +++ b/test/typeparam/issue50552.dir/main.go @@ -0,0 +1,20 @@ +// Copyright 2022 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 main + +import ( + "./a" + "fmt" +) + +func BuildInt() int { + return a.BuildInt() +} + +func main() { + if got, want := BuildInt(), 0; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/issue50552.go b/test/typeparam/issue50552.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/issue50552.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue50561.dir/diameter.go b/test/typeparam/issue50561.dir/diameter.go new file mode 100644 index 0000000..2bfe924 --- /dev/null +++ b/test/typeparam/issue50561.dir/diameter.go @@ -0,0 +1,86 @@ +// Copyright 2022 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 diameter + +type Runnable interface { + Run() +} + +// RunnableFunc is converter which converts function to Runnable interface +type RunnableFunc func() + +// Run is Runnable.Run +func (r RunnableFunc) Run() { + r() +} + +type Executor interface { + ExecuteUnsafe(runnable Runnable) +} + +type Promise[T any] interface { + Future() Future[T] + Success(value T) bool + Failure(err error) bool + IsCompleted() bool + Complete(result Try[T]) bool +} + +type Future[T any] interface { + OnFailure(cb func(err error), ctx ...Executor) + OnSuccess(cb func(success T), ctx ...Executor) + Foreach(f func(v T), ctx ...Executor) + OnComplete(cb func(try Try[T]), ctx ...Executor) + IsCompleted() bool + // Value() Option[Try[T]] + Failed() Future[error] + Recover(f func(err error) T, ctx ...Executor) Future[T] + RecoverWith(f func(err error) Future[T], ctx ...Executor) Future[T] +} + +type Try[T any] struct { + v *T + err error +} + +func (r Try[T]) IsSuccess() bool { + return r.v != nil +} + +type ByteBuffer struct { + pos int + buf []byte + underflow error +} + +// InboundHandler is extends of uclient.NetInboundHandler +type InboundHandler interface { + OriginHost() string + OriginRealm() string +} + +type transactionID struct { + hopID uint32 + endID uint32 +} + +type roundTripper struct { + promise map[transactionID]Promise[*ByteBuffer] + host string + realm string +} + +func (r *roundTripper) OriginHost() string { + return r.host +} +func (r *roundTripper) OriginRealm() string { + return r.realm +} + +func NewInboundHandler(host string, realm string, productName string) InboundHandler { + ret := &roundTripper{promise: make(map[transactionID]Promise[*ByteBuffer]), host: host, realm: realm} + + return ret +} diff --git a/test/typeparam/issue50561.dir/main.go b/test/typeparam/issue50561.dir/main.go new file mode 100644 index 0000000..3e656bd --- /dev/null +++ b/test/typeparam/issue50561.dir/main.go @@ -0,0 +1,13 @@ +// Copyright 2022 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 main + +import ( + "./diameter" +) + +func main() { + diameter.NewInboundHandler("hello", "world", "hi") +} diff --git a/test/typeparam/issue50561.go b/test/typeparam/issue50561.go new file mode 100644 index 0000000..8bb5c3e --- /dev/null +++ b/test/typeparam/issue50561.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue50598.dir/a0.go b/test/typeparam/issue50598.dir/a0.go new file mode 100644 index 0000000..61d353e --- /dev/null +++ b/test/typeparam/issue50598.dir/a0.go @@ -0,0 +1,23 @@ +// Copyright 2022 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 a0 + +type Builder[T any] struct{} + +func (r Builder[T]) New1() T { + var v T + return v +} + +func (r Builder[T]) New2() T { + var v T + return v +} + +type IntBuilder struct{} + +func (b IntBuilder) New() int { + return Builder[int]{}.New2() +} diff --git a/test/typeparam/issue50598.dir/a1.go b/test/typeparam/issue50598.dir/a1.go new file mode 100644 index 0000000..36624b4 --- /dev/null +++ b/test/typeparam/issue50598.dir/a1.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 a1 + +import "./a0" + +func New() int { + return a0.IntBuilder{}.New() +} diff --git a/test/typeparam/issue50598.dir/a2.go b/test/typeparam/issue50598.dir/a2.go new file mode 100644 index 0000000..c28be66 --- /dev/null +++ b/test/typeparam/issue50598.dir/a2.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 a2 + +import "./a0" + +func New() int { + return a0.Builder[int]{}.New1() +} diff --git a/test/typeparam/issue50598.dir/main.go b/test/typeparam/issue50598.dir/main.go new file mode 100644 index 0000000..b0b6844 --- /dev/null +++ b/test/typeparam/issue50598.dir/main.go @@ -0,0 +1,22 @@ +// Copyright 2022 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 main + +import ( + "fmt" + + "./a1" + "./a2" +) + +func New() int { + return a1.New() + a2.New() +} + +func main() { + if got, want := New(), 0; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/issue50598.go b/test/typeparam/issue50598.go new file mode 100644 index 0000000..aefbe67 --- /dev/null +++ b/test/typeparam/issue50598.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue50642.go b/test/typeparam/issue50642.go new file mode 100644 index 0000000..d2d4a66 --- /dev/null +++ b/test/typeparam/issue50642.go @@ -0,0 +1,63 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +type Temp[T any] struct { +} + +var temp, temp1 any +var ch any + +func (it Temp[T]) HasNext() bool { + var ok bool + temp1 = <-ch.(chan T) + // test conversion of T to interface{} during an OAS2RECV + temp, ok = <-ch.(chan T) + return ok +} + +type MyInt int + +func (i MyInt) String() string { + return "a" +} + +type Stringer interface { + String() string +} + +type Temp2[T Stringer] struct { +} + +var temp2 Stringer + +func (it Temp2[T]) HasNext() string { + var x map[int]T + + var ok bool + // test conversion of T to Stringer during an OAS2MAPR + temp2, ok = x[43] + _ = ok + return temp2.String() +} + +func main() { + ch1 := make(chan int, 2) + ch1 <- 5 + ch1 <- 6 + ch = ch1 + iter := Temp[int]{} + iter.HasNext() + + iter2 := Temp2[MyInt]{} + if got, want := iter2.HasNext(), "a"; got != want { + panic(fmt.Sprintf("got %v, want %v", got, want)) + } + +} diff --git a/test/typeparam/issue50690a.go b/test/typeparam/issue50690a.go new file mode 100644 index 0000000..6691af0 --- /dev/null +++ b/test/typeparam/issue50690a.go @@ -0,0 +1,75 @@ +// run + +// Copyright 2022 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 main + +import ( + "fmt" +) + +// Numeric expresses a type constraint satisfied by any numeric type. +type Numeric interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~float32 | ~float64 | + ~complex64 | ~complex128 +} + +// Sum returns the sum of the provided arguments. +func Sum[T Numeric](args ...T) T { + var sum T + for i := 0; i < len(args); i++ { + sum += args[i] + } + return sum +} + +// Ledger is an identifiable, financial record. +type Ledger[T ~string, K Numeric] struct { + // ID identifies the ledger. + ID_ T + + // Amounts is a list of monies associated with this ledger. + Amounts_ []K + + // SumFn is a function that can be used to sum the amounts + // in this ledger. + SumFn_ func(...K) K +} + +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. +// Use accessor methods instead. + +func (l Ledger[T, _]) ID() T { return l.ID_ } +func (l Ledger[_, K]) Amounts() []K { return l.Amounts_ } +func (l Ledger[_, K]) SumFn() func(...K) K { return l.SumFn_ } + +func PrintLedger[ + T ~string, + K Numeric, + L interface { + ~struct { + ID_ T + Amounts_ []K + SumFn_ func(...K) K + } + ID() T + Amounts() []K + SumFn() func(...K) K + }, +](l L) { + fmt.Printf("%s has a sum of %v\n", l.ID(), l.SumFn()(l.Amounts()...)) +} + +func main() { + PrintLedger(Ledger[string, int]{ + ID_: "fake", + Amounts_: []int{1, 2, 3}, + SumFn_: Sum[int], + }) +} diff --git a/test/typeparam/issue50690a.out b/test/typeparam/issue50690a.out new file mode 100644 index 0000000..2932767 --- /dev/null +++ b/test/typeparam/issue50690a.out @@ -0,0 +1 @@ +fake has a sum of 6 diff --git a/test/typeparam/issue50690b.go b/test/typeparam/issue50690b.go new file mode 100644 index 0000000..09c84e0 --- /dev/null +++ b/test/typeparam/issue50690b.go @@ -0,0 +1,51 @@ +// run + +// Copyright 2022 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 main + +import ( + "fmt" +) + +type Printer[T ~string] struct { + PrintFn func(T) +} + +func Print[T ~string](s T) { + fmt.Println(s) +} + +func PrintWithPrinter[T ~string, S interface { + ~struct { + ID T + PrintFn_ func(T) + } + PrintFn() func(T) +}](message T, obj S) { + obj.PrintFn()(message) +} + +type PrintShop[T ~string] struct { + ID T + PrintFn_ func(T) +} + +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. +// Use accessor method instead. + +func (s PrintShop[T]) PrintFn() func(T) { return s.PrintFn_ } + +func main() { + PrintWithPrinter( + "Hello, world.", + PrintShop[string]{ + ID: "fake", + PrintFn_: Print[string], + }, + ) +} diff --git a/test/typeparam/issue50690b.out b/test/typeparam/issue50690b.out new file mode 100644 index 0000000..f75ba05 --- /dev/null +++ b/test/typeparam/issue50690b.out @@ -0,0 +1 @@ +Hello, world. diff --git a/test/typeparam/issue50690c.go b/test/typeparam/issue50690c.go new file mode 100644 index 0000000..2db1487 --- /dev/null +++ b/test/typeparam/issue50690c.go @@ -0,0 +1,50 @@ +// run + +// Copyright 2022 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 main + +import ( + "fmt" +) + +type Printer[T ~string] struct { + PrintFn func(T) +} + +func Print[T ~string](s T) { + fmt.Println(s) +} + +func PrintWithPrinter[T ~string, S interface { + ~struct { + ID T + PrintFn_ func(T) + } + PrintFn() func(T) +}](message T, obj S) { + obj.PrintFn()(message) +} + +func main() { + PrintWithPrinter( + "Hello, world.", + StructWithPrinter{ID: "fake", PrintFn_: Print[string]}, + ) +} + +type StructWithPrinter struct { + ID string + PrintFn_ func(string) +} + +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. +// Use accessor method instead. + +func (s StructWithPrinter) PrintFn() func(string) { + return s.PrintFn_ +} diff --git a/test/typeparam/issue50690c.out b/test/typeparam/issue50690c.out new file mode 100644 index 0000000..f75ba05 --- /dev/null +++ b/test/typeparam/issue50690c.out @@ -0,0 +1 @@ +Hello, world. diff --git a/test/typeparam/issue50833.go b/test/typeparam/issue50833.go new file mode 100644 index 0000000..fe729b1 --- /dev/null +++ b/test/typeparam/issue50833.go @@ -0,0 +1,23 @@ +// run + +// Copyright 2022 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 main + +type ( + S struct{ f int } + PS *S +) + +func a() []*S { return []*S{{f: 1}} } +func b() []PS { return []PS{{f: 1}} } + +func c[P *S]() []P { return []P{{f: 1}} } +func d[P PS]() []P { return []P{{f: 1}} } + +func main() { + c[*S]() + d[PS]() +} diff --git a/test/typeparam/issue50841.dir/a.go b/test/typeparam/issue50841.dir/a.go new file mode 100644 index 0000000..37e0233 --- /dev/null +++ b/test/typeparam/issue50841.dir/a.go @@ -0,0 +1,22 @@ +// Copyright 2022 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 a + +func Marshal[foobar any]() { + _ = NewEncoder[foobar]() +} + +func NewEncoder[foobar any]() *Encoder[foobar] { + return nil +} + +type Encoder[foobar any] struct { +} + +func (e *Encoder[foobar]) EncodeToken(t Token[foobar]) { + +} + +type Token[foobar any] any diff --git a/test/typeparam/issue50841.dir/b.go b/test/typeparam/issue50841.dir/b.go new file mode 100644 index 0000000..38e3de3 --- /dev/null +++ b/test/typeparam/issue50841.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 b + +import "./a" + +func F() { + a.Marshal[int]() +} diff --git a/test/typeparam/issue50841.go b/test/typeparam/issue50841.go new file mode 100644 index 0000000..8bb5c3e --- /dev/null +++ b/test/typeparam/issue50841.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue50993.go b/test/typeparam/issue50993.go new file mode 100644 index 0000000..4d459fd --- /dev/null +++ b/test/typeparam/issue50993.go @@ -0,0 +1,35 @@ +// compile -d=checkptr + +// Copyright 2022 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 main + +import ( + "sync/atomic" + "unsafe" +) + +type Node[T any] struct { + Next *Node[T] + // Prev *Node[T] +} + +func LoadPointer[T any](addr **T) (val *T) { + return (*T)( + atomic.LoadPointer( + (*unsafe.Pointer)(unsafe.Pointer(addr)), + )) +} + +func (q *Node[T]) Pop() { + var tail, head *Node[T] + if head == LoadPointer(&tail) { + } +} + +func main() { + ch := Node[uint64]{} + ch.Pop() +} diff --git a/test/typeparam/issue51219.dir/a.go b/test/typeparam/issue51219.dir/a.go new file mode 100644 index 0000000..29670df --- /dev/null +++ b/test/typeparam/issue51219.dir/a.go @@ -0,0 +1,20 @@ +// Copyright 2022 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 a + +// Type I is the first basic test for the issue, which relates to a type that is recursive +// via a type constraint. (In this test, I -> IConstraint -> MyStruct -> I.) +type JsonRaw []byte + +type MyStruct struct { + x *I[JsonRaw] +} + +type IConstraint interface { + JsonRaw | MyStruct +} + +type I[T IConstraint] struct { +} diff --git a/test/typeparam/issue51219.dir/main.go b/test/typeparam/issue51219.dir/main.go new file mode 100644 index 0000000..14c6d17 --- /dev/null +++ b/test/typeparam/issue51219.dir/main.go @@ -0,0 +1,16 @@ +// Copyright 2022 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 main + +import ( + "./a" + "fmt" +) + +func main() { + var x a.I[a.JsonRaw] + + fmt.Printf("%v\n", x) +} diff --git a/test/typeparam/issue51219.go b/test/typeparam/issue51219.go new file mode 100644 index 0000000..aefbe67 --- /dev/null +++ b/test/typeparam/issue51219.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue51219.out b/test/typeparam/issue51219.out new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/test/typeparam/issue51219.out @@ -0,0 +1 @@ +{} diff --git a/test/typeparam/issue51219b.dir/a.go b/test/typeparam/issue51219b.dir/a.go new file mode 100644 index 0000000..1904940 --- /dev/null +++ b/test/typeparam/issue51219b.dir/a.go @@ -0,0 +1,37 @@ +// Copyright 2022 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 a + +type Interaction[DataT InteractionDataConstraint] struct { +} + +type InteractionDataConstraint interface { + []byte | + UserCommandInteractionData +} + +type UserCommandInteractionData struct { + resolvedInteractionWithOptions +} + +type resolvedInteractionWithOptions struct { + Resolved Resolved `json:"resolved,omitempty"` +} + +type Resolved struct { + Users ResolvedData[User] `json:"users,omitempty"` +} + +type ResolvedData[T ResolvedDataConstraint] map[uint64]T + +type ResolvedDataConstraint interface { + User | Message +} + +type User struct{} + +type Message struct { + Interaction *Interaction[[]byte] `json:"interaction,omitempty"` +} diff --git a/test/typeparam/issue51219b.dir/b.go b/test/typeparam/issue51219b.dir/b.go new file mode 100644 index 0000000..8413d66 --- /dev/null +++ b/test/typeparam/issue51219b.dir/b.go @@ -0,0 +1,14 @@ +// Copyright 2022 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 b + +import ( + "./a" +) + +// InteractionRequest is an incoming request Interaction +type InteractionRequest[T a.InteractionDataConstraint] struct { + a.Interaction[T] +} diff --git a/test/typeparam/issue51219b.dir/p.go b/test/typeparam/issue51219b.dir/p.go new file mode 100644 index 0000000..9f8b840 --- /dev/null +++ b/test/typeparam/issue51219b.dir/p.go @@ -0,0 +1,14 @@ +// Copyright 2022 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 ( + "./b" +) + +// ResponseWriterMock mocks corde's ResponseWriter interface +type ResponseWriterMock struct { + x b.InteractionRequest[[]byte] +} diff --git a/test/typeparam/issue51219b.go b/test/typeparam/issue51219b.go new file mode 100644 index 0000000..8bb5c3e --- /dev/null +++ b/test/typeparam/issue51219b.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue51232.go b/test/typeparam/issue51232.go new file mode 100644 index 0000000..0d25e18 --- /dev/null +++ b/test/typeparam/issue51232.go @@ -0,0 +1,31 @@ +// errorcheck + +// Copyright 2022 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 RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] // ERROR "got 1 arguments" +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn func() Fn[RCT] // ERROR "got 1 arguments" +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "got 1 arguments" + return c.makeFn() +} + +func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { // ERROR "got 1 arguments" + return &concreteF[RCT]{ // ERROR "cannot use" "got 1 arguments" + makeFn: nil, + } +} diff --git a/test/typeparam/issue51233.go b/test/typeparam/issue51233.go new file mode 100644 index 0000000..96a25dd --- /dev/null +++ b/test/typeparam/issue51233.go @@ -0,0 +1,28 @@ +// errorcheck + +// Copyright 2022 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 + +// As of issue #51527, type-type inference has been disabled. + +type RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type FFn[RCT RC[RG], RG any] func() Fn[RCT] // ERROR "got 1 arguments" + +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] // ERROR "got 1 arguments" +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn FFn[RCT] // ERROR "got 1 arguments" +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "got 1 arguments" + return c.makeFn() +} diff --git a/test/typeparam/issue51236.go b/test/typeparam/issue51236.go new file mode 100644 index 0000000..51fde1e --- /dev/null +++ b/test/typeparam/issue51236.go @@ -0,0 +1,22 @@ +// run + +// Copyright 2022 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 main + +type I interface { + []byte +} + +func F[T I]() { + var t T + explodes(t) +} + +func explodes(b []byte) {} + +func main() { + +} diff --git a/test/typeparam/issue51245.go b/test/typeparam/issue51245.go new file mode 100644 index 0000000..425d517 --- /dev/null +++ b/test/typeparam/issue51245.go @@ -0,0 +1,16 @@ +// build + +// Copyright 2022 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 main + +type T[P any] int +const C T[int] = 3 + +type T2 int +const C2 T2 = 9 + +func main() { +} diff --git a/test/typeparam/issue51250a.dir/a.go b/test/typeparam/issue51250a.dir/a.go new file mode 100644 index 0000000..12dd60a --- /dev/null +++ b/test/typeparam/issue51250a.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2022 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 a + +type G[T any] struct { + x T +} diff --git a/test/typeparam/issue51250a.dir/b.go b/test/typeparam/issue51250a.dir/b.go new file mode 100644 index 0000000..114c9f8 --- /dev/null +++ b/test/typeparam/issue51250a.dir/b.go @@ -0,0 +1,24 @@ +// Copyright 2022 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 b + +import "./a" + +type T struct { a int } + +var I interface{} = a.G[T]{} + +//go:noinline +func F(x interface{}) { + switch x.(type) { + case a.G[T]: + case int: + panic("bad") + case float64: + panic("bad") + default: + panic("bad") + } +} diff --git a/test/typeparam/issue51250a.dir/main.go b/test/typeparam/issue51250a.dir/main.go new file mode 100644 index 0000000..45288be --- /dev/null +++ b/test/typeparam/issue51250a.dir/main.go @@ -0,0 +1,24 @@ +// Copyright 2022 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 main + +import ( + "./a" + "./b" +) + +func main() { + switch b.I.(type) { + case a.G[b.T]: + case int: + panic("bad") + case float64: + panic("bad") + default: + panic("bad") + } + + b.F(a.G[b.T]{}) +} diff --git a/test/typeparam/issue51250a.go b/test/typeparam/issue51250a.go new file mode 100644 index 0000000..aefbe67 --- /dev/null +++ b/test/typeparam/issue51250a.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue51303.go b/test/typeparam/issue51303.go new file mode 100644 index 0000000..a3a7849 --- /dev/null +++ b/test/typeparam/issue51303.go @@ -0,0 +1,65 @@ +// run + +// Copyright 2022 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 main + +import ( + "fmt" +) + +func main() { + x := [][]int{{1}} + y := [][]int{{2, 3}} + IntersectSS(x, y) +} + +type list[E any] interface { + ~[]E + Equal(x, y E) bool +} + +// ss is a set of sets +type ss[E comparable, T []E] []T + +func (ss[E, T]) Equal(a, b T) bool { + return SetEq(a, b) +} + +func IntersectSS[E comparable](x, y [][]E) [][]E { + return IntersectT[[]E, ss[E, []E]](ss[E, []E](x), ss[E, []E](y)) +} + +func IntersectT[E any, L list[E]](x, y L) L { + var z L +outer: + for _, xe := range x { + fmt.Println("xe", xe) + for _, ye := range y { + fmt.Println("ye", ye) + fmt.Println("x", x) + if x.Equal(xe, ye) { + fmt.Println("appending") + z = append(z, xe) + continue outer + } + } + } + return z +} + +func SetEq[S []E, E comparable](x, y S) bool { + fmt.Println("SetEq", x, y) +outer: + for _, xe := range x { + for _, ye := range y { + if xe == ye { + continue outer + } + } + return false // xs wasn't found in y + } + return true +} diff --git a/test/typeparam/issue51303.out b/test/typeparam/issue51303.out new file mode 100644 index 0000000..34b3be3 --- /dev/null +++ b/test/typeparam/issue51303.out @@ -0,0 +1,4 @@ +xe [1] +ye [2 3] +x [[1]] +SetEq [1] [2 3] diff --git a/test/typeparam/issue51355.go b/test/typeparam/issue51355.go new file mode 100644 index 0000000..321d5ff --- /dev/null +++ b/test/typeparam/issue51355.go @@ -0,0 +1,31 @@ +// compile + +// Copyright 2022 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 main + +type Cache[E comparable] struct { + adder func(...E) +} + +func New[E comparable]() *Cache[E] { + c := &Cache[E]{} + + c.adder = func(elements ...E) { + for _, value := range elements { + value := value + go func() { + println(value) + }() + } + } + + return c +} + +func main() { + c := New[string]() + c.adder("test") +} diff --git a/test/typeparam/issue51367.dir/a.go b/test/typeparam/issue51367.dir/a.go new file mode 100644 index 0000000..be0c3b0 --- /dev/null +++ b/test/typeparam/issue51367.dir/a.go @@ -0,0 +1,14 @@ +// Copyright 2022 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 a + +type A[T any] struct{} + +func (_ A[T]) Method() {} + +func DoSomething[P any]() { + a := A[*byte]{} + a.Method() +} diff --git a/test/typeparam/issue51367.dir/main.go b/test/typeparam/issue51367.dir/main.go new file mode 100644 index 0000000..1de8793 --- /dev/null +++ b/test/typeparam/issue51367.dir/main.go @@ -0,0 +1,13 @@ +// Copyright 2022 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 main + +import ( + "./a" +) + +func main() { + a.DoSomething[byte]() +} diff --git a/test/typeparam/issue51367.go b/test/typeparam/issue51367.go new file mode 100644 index 0000000..aefbe67 --- /dev/null +++ b/test/typeparam/issue51367.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue51423.dir/a.go b/test/typeparam/issue51423.dir/a.go new file mode 100644 index 0000000..e824d0e --- /dev/null +++ b/test/typeparam/issue51423.dir/a.go @@ -0,0 +1,17 @@ +// Copyright 2022 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 a + +type Comparator[T any] func(v1, v2 T) int + +func CompareInt[T ~int](a, b T) int { + if a < b { + return -1 + } + if a == b { + return 0 + } + return 1 +} diff --git a/test/typeparam/issue51423.dir/b.go b/test/typeparam/issue51423.dir/b.go new file mode 100644 index 0000000..2bad19f --- /dev/null +++ b/test/typeparam/issue51423.dir/b.go @@ -0,0 +1,11 @@ +package b + +import "./a" + +func C() a.Comparator[int] { + return a.CompareInt[int] +} + +func main() { + _ = C()(1, 2) +} diff --git a/test/typeparam/issue51423.go b/test/typeparam/issue51423.go new file mode 100644 index 0000000..8bb5c3e --- /dev/null +++ b/test/typeparam/issue51423.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue51521.go b/test/typeparam/issue51521.go new file mode 100644 index 0000000..5eb4e35 --- /dev/null +++ b/test/typeparam/issue51521.go @@ -0,0 +1,30 @@ +// run + +// Copyright 2022 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 main + +import ( + "fmt" + "strings" +) + +type I interface{ M() } + +func F[P I](p P) { defer catch(); p.M() } +func G[T any]() { defer catch(); interface{ M() T }.M(nil) } + +func main() { + F[I](nil) + G[int]() +} + +func catch() { + err := recover() + if err, ok := err.(error); ok && strings.Contains(err.Error(), "nil pointer dereference") { + return + } + fmt.Println("FAIL", err) +} diff --git a/test/typeparam/issue51522a.go b/test/typeparam/issue51522a.go new file mode 100644 index 0000000..3f85408 --- /dev/null +++ b/test/typeparam/issue51522a.go @@ -0,0 +1,42 @@ +// run + +// Copyright 2022 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 main + + +func f[T comparable](i any) { + var t T + + if i != t { + println("FAIL: if i != t") + } +} + +type myint int + +func (m myint) foo() { +} + +type fooer interface { + foo() +} + +type comparableFoo interface { + comparable + foo() +} + +func g[T comparableFoo](i fooer) { + var t T + + if i != t { + println("FAIL: if i != t") + } +} + +func main() { + f[int](int(0)) + g[myint](myint(0)) +} diff --git a/test/typeparam/issue51522b.go b/test/typeparam/issue51522b.go new file mode 100644 index 0000000..115b6b9 --- /dev/null +++ b/test/typeparam/issue51522b.go @@ -0,0 +1,62 @@ +// run + +// Copyright 2022 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 main + +func f[T comparable](i any) { + var t T + + switch i { + case t: + // ok + default: + println("FAIL: switch i") + } + + switch t { + case i: + // ok + default: + println("FAIL: switch t") + } +} + +type myint int + +func (m myint) foo() { +} + +type fooer interface { + foo() +} + +type comparableFoo interface { + comparable + foo() +} + +func g[T comparableFoo](i fooer) { + var t T + + switch i { + case t: + // ok + default: + println("FAIL: switch i") + } + + switch t { + case i: + // ok + default: + println("FAIL: switch t") + } +} + +func main() { + f[int](0) + g[myint](myint(0)) +} diff --git a/test/typeparam/issue51700.go b/test/typeparam/issue51700.go new file mode 100644 index 0000000..bf8a1f6 --- /dev/null +++ b/test/typeparam/issue51700.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2022 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 main + +func f[B any](b B) { + if b1, ok := any(b).(interface{ m1() }); ok { + panic(1) + _ = b1.(B) + } + if b2, ok := any(b).(interface{ m2() }); ok { + panic(2) + _ = b2.(B) + } +} + +type S struct{} + +func (S) m3() {} + +func main() { + f(S{}) +} diff --git a/test/typeparam/issue51765.go b/test/typeparam/issue51765.go new file mode 100644 index 0000000..683cb0f --- /dev/null +++ b/test/typeparam/issue51765.go @@ -0,0 +1,15 @@ +// compile + +// Copyright 2022 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 empty[T any] struct{} + +func (this *empty[T]) Next() (empty T, _ error) { + return empty, nil +} + +var _ = &empty[string]{} diff --git a/test/typeparam/issue51832.go b/test/typeparam/issue51832.go new file mode 100644 index 0000000..c325ae6 --- /dev/null +++ b/test/typeparam/issue51832.go @@ -0,0 +1,25 @@ +// compile + +// Copyright 2022 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 main + +type F func() F + +func do[T any]() F { + return nil +} + +type G[T any] func() G[T] + +//go:noinline +func dog[T any]() G[T] { + return nil +} + +func main() { + do[int]() + dog[int]() +} diff --git a/test/typeparam/issue51836.dir/a.go b/test/typeparam/issue51836.dir/a.go new file mode 100644 index 0000000..e9223c9 --- /dev/null +++ b/test/typeparam/issue51836.dir/a.go @@ -0,0 +1,8 @@ +// Copyright 2022 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 a + +type T[K any] struct { +} diff --git a/test/typeparam/issue51836.dir/aa.go b/test/typeparam/issue51836.dir/aa.go new file mode 100644 index 0000000..d774be2 --- /dev/null +++ b/test/typeparam/issue51836.dir/aa.go @@ -0,0 +1,13 @@ +// Copyright 2022 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 a + +import ( + "./a" +) + +type T[K any] struct { + t a.T[K] +} diff --git a/test/typeparam/issue51836.dir/p.go b/test/typeparam/issue51836.dir/p.go new file mode 100644 index 0000000..98197ae --- /dev/null +++ b/test/typeparam/issue51836.dir/p.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 ( + a "./aa" +) + +var Foo a.T[int] diff --git a/test/typeparam/issue51836.go b/test/typeparam/issue51836.go new file mode 100644 index 0000000..c755e74 --- /dev/null +++ b/test/typeparam/issue51836.go @@ -0,0 +1,7 @@ +// compiledir -s + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue51840.go b/test/typeparam/issue51840.go new file mode 100644 index 0000000..19fa3e4 --- /dev/null +++ b/test/typeparam/issue51840.go @@ -0,0 +1,36 @@ +// compile + +// Copyright 2022 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 main + +type Addr struct { + hi uint64 + lo uint64 + z *byte +} + +func EqualMap[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool { + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || v1 != v2 { + return false + } + } + return true +} + +type Set[T comparable] map[T]struct{} + +func NewSet[T comparable](items ...T) Set[T] { + return nil +} + +func (s Set[T]) Equals(other Set[T]) bool { + return EqualMap(s, other) +} + +func main() { + NewSet[Addr](Addr{0, 0, nil}) +} diff --git a/test/typeparam/issue51909.go b/test/typeparam/issue51909.go new file mode 100644 index 0000000..5fe39ca --- /dev/null +++ b/test/typeparam/issue51909.go @@ -0,0 +1,30 @@ +// compile + +// Copyright 2022 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 main + +type None struct{} + +type Response interface { + send(ctx *struct{}) +} + +type HandlerFunc[Input any] func(Input) Response + +func Operation[Input any](method, path string, h HandlerFunc[Input]) { + var input Input + h(input) +} + +func Get[Body any](path string, h HandlerFunc[struct{ Body Body }]) { + Operation("GET", path, h) +} + +func main() { + Get("/", func(req struct{ Body None }) Response { + return nil + }) +} diff --git a/test/typeparam/issue51925.go b/test/typeparam/issue51925.go new file mode 100644 index 0000000..0a385ac --- /dev/null +++ b/test/typeparam/issue51925.go @@ -0,0 +1,52 @@ +// compile + +// Copyright 2022 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 main + +import "fmt" + +type IntLike interface { + ~int | ~int64 | ~int32 | ~int16 | ~int8 +} + +func Reduce[T any, U any, Uslice ~[]U](function func(T, U) T, sequence Uslice, initial T) T { + result := initial + for _, x := range sequence { + result = function(result, x) + } + return result +} + +func min[T IntLike](x, y T) T { + if x < y { + return x + } + return y + +} + +// Min returns the minimum element of `nums`. +func Min[T IntLike, NumSlice ~[]T](nums NumSlice) T { + if len(nums) == 0 { + return T(0) + } + return Reduce(min[T], nums, nums[0]) +} + +// VarMin is the variadic version of Min. +func VarMin[T IntLike](nums ...T) T { + return Min(nums) +} + +type myInt int + +func main() { + fmt.Println(VarMin(myInt(1), myInt(2))) + + seq := []myInt{1, 2} + fmt.Println(Min(seq)) + fmt.Println(VarMin(seq...)) +} diff --git a/test/typeparam/issue52026.go b/test/typeparam/issue52026.go new file mode 100644 index 0000000..db8999a --- /dev/null +++ b/test/typeparam/issue52026.go @@ -0,0 +1,50 @@ +// run + +// Copyright 2022 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 main + +func returnOption[T any](n int) Option[T] { + if n == 1 { + return Some[T]{} + } else { + return None{} + } +} + +type Option[T any] interface { + sealedOption() +} + +type Some[T any] struct { + val T +} + +func (s Some[T]) Value() T { + return s.val +} + +func (s Some[T]) sealedOption() {} + +type None struct{} + +func (s None) sealedOption() {} + +func main() { + s := returnOption[int](1) + _ = s.(Some[int]) + + s = returnOption[int](0) + _ = s.(None) + + switch (any)(s).(type) { + case Some[int]: + panic("s is a Some[int]") + case None: + // ok + default: + panic("oops") + } +} diff --git a/test/typeparam/issue52117.dir/a.go b/test/typeparam/issue52117.dir/a.go new file mode 100644 index 0000000..e571ea9 --- /dev/null +++ b/test/typeparam/issue52117.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2022 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 a + +func Compare[T int | uint](a, b T) int { + return 0 +} + +type Slice[T int | uint] struct{} + +func (l Slice[T]) Comparator() func(v1, v2 T) int { + return Compare[T] +} diff --git a/test/typeparam/issue52117.dir/b.go b/test/typeparam/issue52117.dir/b.go new file mode 100644 index 0000000..3d3bf4c --- /dev/null +++ b/test/typeparam/issue52117.dir/b.go @@ -0,0 +1,7 @@ +package b + +import "./a" + +func Test() { + var _ a.Slice[uint] +} diff --git a/test/typeparam/issue52117.go b/test/typeparam/issue52117.go new file mode 100644 index 0000000..8bb5c3e --- /dev/null +++ b/test/typeparam/issue52117.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2022 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 ignored diff --git a/test/typeparam/issue52124.go b/test/typeparam/issue52124.go new file mode 100644 index 0000000..07cba47 --- /dev/null +++ b/test/typeparam/issue52124.go @@ -0,0 +1,17 @@ +// compile + +// Copyright 2022 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 Any any + +type I interface{ Any | int } + +var ( + X I = 42 + Y I = "xxx" + Z I = true +) diff --git a/test/typeparam/issue52228.go b/test/typeparam/issue52228.go new file mode 100644 index 0000000..3fbbde5 --- /dev/null +++ b/test/typeparam/issue52228.go @@ -0,0 +1,30 @@ +// run + +// Copyright 2022 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 main + +type SomeInterface interface { + Whatever() +} + +func X[T any]() T { + var m T + + // for this example, this block should never run + if _, ok := any(m).(SomeInterface); ok { + var dst SomeInterface + _, _ = dst.(T) + return dst.(T) + } + + return m +} + +type holder struct{} + +func main() { + X[holder]() +} diff --git a/test/typeparam/issue52241.go b/test/typeparam/issue52241.go new file mode 100644 index 0000000..4feb97e --- /dev/null +++ b/test/typeparam/issue52241.go @@ -0,0 +1,22 @@ +// compile + +// Copyright 2022 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 main + +type Collector[T any] struct { +} + +func (c *Collector[T]) Collect() { +} + +func TestInOrderIntTree() { + collector := Collector[int]{} + _ = collector.Collect +} + +func main() { + TestInOrderIntTree() +} diff --git a/test/typeparam/issue53254.go b/test/typeparam/issue53254.go new file mode 100644 index 0000000..afc0f18 --- /dev/null +++ b/test/typeparam/issue53254.go @@ -0,0 +1,19 @@ +// compile + +// Copyright 2022 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 main + +type Interface[T any] interface { +} + +func F[T any]() Interface[T] { + var i int + return i +} + +func main() { + F[int]() +} diff --git a/test/typeparam/issue53390.go b/test/typeparam/issue53390.go new file mode 100644 index 0000000..52098c5 --- /dev/null +++ b/test/typeparam/issue53390.go @@ -0,0 +1,20 @@ +// compile + +// Copyright 2022 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 "unsafe" + +func F[T any](v T) uintptr { + return unsafe.Alignof(func() T { + func(any) {}(struct{ _ T }{}) + return v + }()) +} + +func f() { + F(0) +} diff --git a/test/typeparam/issue53406.go b/test/typeparam/issue53406.go new file mode 100644 index 0000000..90fe78f --- /dev/null +++ b/test/typeparam/issue53406.go @@ -0,0 +1,22 @@ +// compile + +// Copyright 2022 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 main + +func main() { + f[int]() +} + +func f[T1 any]() { + var x Outer[T1, int] + x.M() +} + +type Outer[T1, T2 any] struct{ Inner[T2] } + +type Inner[_ any] int + +func (Inner[_]) M() {} diff --git a/test/typeparam/issue53419.go b/test/typeparam/issue53419.go new file mode 100644 index 0000000..62a226f --- /dev/null +++ b/test/typeparam/issue53419.go @@ -0,0 +1,28 @@ +// run + +// Copyright 2022 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 main + +type T1 struct{} +type T2 struct{} +type Both struct { + T1 + T2 +} + +func (T1) m() { panic("FAIL") } +func (T2) m() { panic("FAIL") } +func (Both) m() {} + +func f[T interface{ m() }](c T) { + c.m() +} + +func main() { + var b Both + b.m() + f(b) +} diff --git a/test/typeparam/issue53477.go b/test/typeparam/issue53477.go new file mode 100644 index 0000000..d128a7e --- /dev/null +++ b/test/typeparam/issue53477.go @@ -0,0 +1,34 @@ +// run + +// Copyright 2022 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 that generic interface-interface comparisons resulting from +// value switch statements are handled correctly. + +package main + +func main() { + f[X](0) +} + +type Mer[T any] interface{ M(T) } +type MNer[T any] interface { + Mer[T] + N() +} + +type X int + +func (X) M(X) {} +func (X) N() {} + +func f[T MNer[T]](t T) { + switch Mer[T](t) { + case MNer[T](t): + // ok + default: + panic("FAIL") + } +} diff --git a/test/typeparam/issue53762.go b/test/typeparam/issue53762.go new file mode 100644 index 0000000..4d95988 --- /dev/null +++ b/test/typeparam/issue53762.go @@ -0,0 +1,18 @@ +// compile + +// Copyright 2022 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 main + +type Value[T any] interface { +} + +func use[T any](v Value[T]) { + _, _ = v.(int) +} + +func main() { + use(Value[int](1)) +} diff --git a/test/typeparam/issue54135.go b/test/typeparam/issue54135.go new file mode 100644 index 0000000..b489a51 --- /dev/null +++ b/test/typeparam/issue54135.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2022 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 main + +type Foo struct{} + +func (Foo) Blanker() {} + +type Bar[T any] interface { + Blanker() +} + +type Baz interface { + Some() +} + +func check[T comparable](p Bar[T]) { + if x, ok := p.(any); !ok || x != p { + panic("FAIL") + } + if _, ok := p.(Baz); ok { + panic("FAIL") + } +} + +func main() { + check[int](Foo{}) +} diff --git a/test/typeparam/issue54225.go b/test/typeparam/issue54225.go new file mode 100644 index 0000000..4de3efc --- /dev/null +++ b/test/typeparam/issue54225.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2022 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 main + +func main() { + One[TextValue]() +} + +func One[V Value]() { Two[Node[V]]() } + +func Two[V interface{ contentLen() int }]() { + var v V + v.contentLen() +} + +type Value interface { + Len() int +} + +type Node[V Value] struct{} + +func (Node[V]) contentLen() int { + var value V + return value.Len() +} + +type TextValue struct{} + +func (TextValue) Len() int { return 0 } diff --git a/test/typeparam/issue54302.dir/a.go b/test/typeparam/issue54302.dir/a.go new file mode 100644 index 0000000..52875ab --- /dev/null +++ b/test/typeparam/issue54302.dir/a.go @@ -0,0 +1,20 @@ +// Copyright 2022 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 a + +func A() { + B[int](new(G[int])) +} + +func B[T any](iface interface{ M(T) }) { + x, ok := iface.(*G[T]) + if !ok || iface != x { + panic("FAIL") + } +} + +type G[T any] struct{} + +func (*G[T]) M(T) {} diff --git a/test/typeparam/issue54302.dir/main.go b/test/typeparam/issue54302.dir/main.go new file mode 100644 index 0000000..b4c6cd1 --- /dev/null +++ b/test/typeparam/issue54302.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 main + +import "./a" + +func main() { + a.A() +} diff --git a/test/typeparam/issue54302.go b/test/typeparam/issue54302.go new file mode 100644 index 0000000..f132421 --- /dev/null +++ b/test/typeparam/issue54302.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2022 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 diff --git a/test/typeparam/issue54456.go b/test/typeparam/issue54456.go new file mode 100644 index 0000000..8342163 --- /dev/null +++ b/test/typeparam/issue54456.go @@ -0,0 +1,37 @@ +// run + +// Copyright 2022 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. + +// The Go 1.18 frontend failed to disambiguate instantiations of +// different, locally defined generic types with the same name. +// +// The unified frontend also exposed the scope-disambiguation mangling +// to end users in reflect data. + +package main + +import ( + "reflect" +) + +func one() any { type T[_ any] int; return T[int](0) } +func two() any { type T[_ any] int; return T[int](0) } + +func main() { + p, q := one(), two() + + // p and q have different dynamic types; this comparison should + // evaluate false. + if p == q { + panic("bad type identity") + } + + for _, x := range []any{p, q} { + // The names here should not contain "·1" or "·2". + if name := reflect.TypeOf(x).String(); name != "main.T[int]" { + panic(name) + } + } +} diff --git a/test/typeparam/issue54497.go b/test/typeparam/issue54497.go new file mode 100644 index 0000000..1b24cd9 --- /dev/null +++ b/test/typeparam/issue54497.go @@ -0,0 +1,19 @@ +// errorcheck -0 -m + +// Copyright 2022 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 that inlining works with generic functions. + +package testcase + +type C interface{ ~uint | ~uint32 | ~uint64 } + +func isAligned[T C](x, y T) bool { // ERROR "can inline isAligned\[uint\]" "can inline isAligned\[go\.shape\.uint\]" "inlining call to isAligned\[go\.shape\.uint\]" + return x%y == 0 +} + +func foo(x uint) bool { // ERROR "can inline foo" + return isAligned(x, 64) // ERROR "inlining call to isAligned\[go\.shape\.uint\]" +} diff --git a/test/typeparam/issue54535.go b/test/typeparam/issue54535.go new file mode 100644 index 0000000..574b275 --- /dev/null +++ b/test/typeparam/issue54535.go @@ -0,0 +1,37 @@ +// run + +// Copyright 2022 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 main + +type node[T any] struct { + items items[T] + children items[*node[T]] +} + +func (n *node[T]) f(i int, j int) bool { + if len(n.children[i].items) < j { + return false + } + return true +} + +type items[T any] []T + +func main() { + _ = node[int]{} + _ = f[int] +} + +type s[T, U any] struct { + a T + c U +} + +func f[T any]() { + var x s[*struct{ b T }, *struct{ d int }] + _ = x.a.b + _ = x.c.d +} diff --git a/test/typeparam/issue54537.go b/test/typeparam/issue54537.go new file mode 100644 index 0000000..614ed46 --- /dev/null +++ b/test/typeparam/issue54537.go @@ -0,0 +1,22 @@ +// run + +// Copyright 2022 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 main + +func main() { + _ = F[bool] + + var x string + _ = G(x == "foo") +} + +func F[T ~bool](x string) { + var _ T = x == "foo" +} + +func G[T any](t T) *T { + return &t +} diff --git a/test/typeparam/issue54765.go b/test/typeparam/issue54765.go new file mode 100644 index 0000000..364567d --- /dev/null +++ b/test/typeparam/issue54765.go @@ -0,0 +1,28 @@ +// errorcheck + +// Copyright 2022 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 that not-in-heap types cannot be used as type +// arguments. (pointer-to-nih types are okay though.) + +//go:build cgo +// +build cgo + +package p + +import ( + "runtime/cgo" + "sync/atomic" +) + +var _ atomic.Pointer[cgo.Incomplete] // ERROR "cannot use incomplete \(or unallocatable\) type as a type argument: runtime/cgo\.Incomplete" +var _ atomic.Pointer[*cgo.Incomplete] // ok + +func implicit(ptr *cgo.Incomplete) { + g(ptr) // ERROR "cannot use incomplete \(or unallocatable\) type as a type argument: runtime/cgo\.Incomplete" + g(&ptr) // ok +} + +func g[T any](_ *T) {} diff --git a/test/typeparam/issue55101.go b/test/typeparam/issue55101.go new file mode 100644 index 0000000..2d45c87 --- /dev/null +++ b/test/typeparam/issue55101.go @@ -0,0 +1,16 @@ +// compile + +// Copyright 2022 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 + +func F() *Cache[error] { return nil } + +type Cache[T any] struct{ l *List[entry[T]] } +type entry[T any] struct{ value T } +type List[T any] struct{ len int } + +func (c *Cache[V]) Len() int { return c.l.Len() } +func (l *List[T]) Len() int { return l.len } diff --git a/test/typeparam/issue58513.go b/test/typeparam/issue58513.go new file mode 100644 index 0000000..37cb572 --- /dev/null +++ b/test/typeparam/issue58513.go @@ -0,0 +1,60 @@ +// run + +// Copyright 2023 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. + +// Some derived-type expressions require the compiler to synthesize +// function literals to plumb sub-dictionaries appropriately. +// However, when these expressions are inlined, we were constructing +// the function literal bodies with the inline-adjusted positions +// instead of the original (inline-free) positions, which could lead +// to infinite loops when unwinding the stack. + +package main + +import "runtime" + +func assert[_ any]() { + panic(0) +} + +func Assert[To any]() func() { + return assert[To] +} + +type asserter[_ any] struct{} + +func (asserter[_]) assert() { + panic(0) +} + +func AssertMV[To any]() func() { + return asserter[To]{}.assert +} + +func AssertME[To any]() func(asserter[To]) { + return asserter[To].assert +} + +var me = AssertME[string]() + +var tests = []func(){ + Assert[int](), + AssertMV[int](), + func() { me(asserter[string]{}) }, +} + +func main() { + for _, test := range tests { + func() { + defer func() { + recover() + + // Check that we can unwind the stack without infinite looping. + runtime.Caller(1000) + }() + test() + }() + } +} diff --git a/test/typeparam/list.go b/test/typeparam/list.go new file mode 100644 index 0000000..34ad71c --- /dev/null +++ b/test/typeparam/list.go @@ -0,0 +1,103 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +// _List is a linked list of ordered values of type T. +type _List[T Ordered] struct { + next *_List[T] + val T +} + +func (l *_List[T]) Largest() T { + var max T + for p := l; p != nil; p = p.next { + if p.val > max { + max = p.val + } + } + return max +} + +type OrderedNum interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +// _ListNum is a linked _List of ordered numeric values of type T. +type _ListNum[T OrderedNum] struct { + next *_ListNum[T] + val T +} + +const Clip = 5 + +// ClippedLargest returns the largest in the list of OrderNums, but a max of 5. +// Test use of untyped constant in an expression with a generically-typed parameter +func (l *_ListNum[T]) ClippedLargest() T { + var max T + for p := l; p != nil; p = p.next { + if p.val > max && p.val < Clip { + max = p.val + } + } + return max +} + +func main() { + i3 := &_List[int]{nil, 1} + i2 := &_List[int]{i3, 3} + i1 := &_List[int]{i2, 2} + if got, want := i1.Largest(), 3; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + b3 := &_List[byte]{nil, byte(1)} + b2 := &_List[byte]{b3, byte(3)} + b1 := &_List[byte]{b2, byte(2)} + if got, want := b1.Largest(), byte(3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + f3 := &_List[float64]{nil, 13.5} + f2 := &_List[float64]{f3, 1.2} + f1 := &_List[float64]{f2, 4.5} + if got, want := f1.Largest(), 13.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } + + s3 := &_List[string]{nil, "dd"} + s2 := &_List[string]{s3, "aa"} + s1 := &_List[string]{s2, "bb"} + if got, want := s1.Largest(), "dd"; got != want { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + j3 := &_ListNum[int]{nil, 1} + j2 := &_ListNum[int]{j3, 32} + j1 := &_ListNum[int]{j2, 2} + if got, want := j1.ClippedLargest(), 2; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + g3 := &_ListNum[float64]{nil, 13.5} + g2 := &_ListNum[float64]{g3, 1.2} + g1 := &_ListNum[float64]{g2, 4.5} + if got, want := g1.ClippedLargest(), 4.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } +} diff --git a/test/typeparam/list2.go b/test/typeparam/list2.go new file mode 100644 index 0000000..111ac78 --- /dev/null +++ b/test/typeparam/list2.go @@ -0,0 +1,608 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package list provides a doubly linked list of some element type +// (generic form of the "container/list" package). + +package main + +import ( + "fmt" + "strconv" +) + +// Element is an element of a linked list. +type _Element[T any] struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *_Element[T] + + // The list to which this element belongs. + list *_List[T] + + // The value stored with this element. + Value T +} + +// Next returns the next list element or nil. +func (e *_Element[T]) Next() *_Element[T] { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// Prev returns the previous list element or nil. +func (e *_Element[T]) Prev() *_Element[T] { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// _List represents a doubly linked list. +// The zero value for _List is an empty list ready to use. +type _List[T any] struct { + root _Element[T] // sentinel list element, only &root, root.prev, and root.next are used + len int // current list length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *_List[T]) Init() *_List[T] { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// New returns an initialized list. +func _New[T any]() *_List[T] { return new(_List[T]).Init() } + +// Len returns the number of elements of list l. +// The complexity is O(1). +func (l *_List[_]) Len() int { return l.len } + +// Front returns the first element of list l or nil if the list is empty. +func (l *_List[T]) Front() *_Element[T] { + if l.len == 0 { + return nil + } + return l.root.next +} + +// Back returns the last element of list l or nil if the list is empty. +func (l *_List[T]) Back() *_Element[T] { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero _List value. +func (l *_List[_]) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *_List[T]) insert(e, at *_Element[T]) *_Element[T] { + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&_Element[T]{Value: v}, at). +func (l *_List[T]) insertValue(v T, at *_Element[T]) *_Element[T] { + return l.insert(&_Element[T]{Value: v}, at) +} + +// remove removes e from its list, decrements l.len, and returns e. +func (l *_List[T]) remove(e *_Element[T]) *_Element[T] { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + return e +} + +// move moves e to next to at and returns e. +func (l *_List[T]) move(e, at *_Element[T]) *_Element[T] { + if e == at { + return e + } + e.prev.next = e.next + e.next.prev = e.prev + + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e + + return e +} + +// Remove removes e from l if e is an element of list l. +// It returns the element value e.Value. +// The element must not be nil. +func (l *_List[T]) Remove(e *_Element[T]) T { + if e.list == l { + // if e.list == l, l must have been initialized when e was inserted + // in l or l == nil (e is a zero _Element) and l.remove will crash + l.remove(e) + } + return e.Value +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *_List[T]) PushFront(v T) *_Element[T] { + l.lazyInit() + return l.insertValue(v, &l.root) +} + +// PushBack inserts a new element e with value v at the back of list l and returns e. +func (l *_List[T]) PushBack(v T) *_Element[T] { + l.lazyInit() + return l.insertValue(v, l.root.prev) +} + +// InsertBefore inserts a new element e with value v immediately before mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *_List[T]) InsertBefore(v T, mark *_Element[T]) *_Element[T] { + if mark.list != l { + return nil + } + // see comment in _List.Remove about initialization of l + return l.insertValue(v, mark.prev) +} + +// InsertAfter inserts a new element e with value v immediately after mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *_List[T]) InsertAfter(v T, mark *_Element[T]) *_Element[T] { + if mark.list != l { + return nil + } + // see comment in _List.Remove about initialization of l + return l.insertValue(v, mark) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *_List[T]) MoveToFront(e *_Element[T]) { + if e.list != l || l.root.next == e { + return + } + // see comment in _List.Remove about initialization of l + l.move(e, &l.root) +} + +// MoveToBack moves element e to the back of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *_List[T]) MoveToBack(e *_Element[T]) { + if e.list != l || l.root.prev == e { + return + } + // see comment in _List.Remove about initialization of l + l.move(e, l.root.prev) +} + +// MoveBefore moves element e to its new position before mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *_List[T]) MoveBefore(e, mark *_Element[T]) { + if e.list != l || e == mark || mark.list != l { + return + } + l.move(e, mark.prev) +} + +// MoveAfter moves element e to its new position after mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *_List[T]) MoveAfter(e, mark *_Element[T]) { + if e.list != l || e == mark || mark.list != l { + return + } + l.move(e, mark) +} + +// PushBackList inserts a copy of an other list at the back of list l. +// The lists l and other may be the same. They must not be nil. +func (l *_List[T]) PushBackList(other *_List[T]) { + l.lazyInit() + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +// PushFrontList inserts a copy of an other list at the front of list l. +// The lists l and other may be the same. They must not be nil. +func (l *_List[T]) PushFrontList(other *_List[T]) { + l.lazyInit() + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, &l.root) + } +} + +// Transform runs a transform function on a list returning a new list. +func _Transform[TElem1, TElem2 any](lst *_List[TElem1], f func(TElem1) TElem2) *_List[TElem2] { + ret := _New[TElem2]() + for p := lst.Front(); p != nil; p = p.Next() { + ret.PushBack(f(p.Value)) + } + return ret +} + +func checkListLen[T any](l *_List[T], len int) bool { + if n := l.Len(); n != len { + panic(fmt.Sprintf("l.Len() = %d, want %d", n, len)) + return false + } + return true +} + +func checkListPointers[T any](l *_List[T], es []*_Element[T]) { + root := &l.root + + if !checkListLen(l, len(es)) { + return + } + + // zero length lists must be the zero value or properly initialized (sentinel circle) + if len(es) == 0 { + if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root { + panic(fmt.Sprintf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root)) + } + return + } + // len(es) > 0 + + // check internal and external prev/next connections + for i, e := range es { + prev := root + Prev := (*_Element[T])(nil) + if i > 0 { + prev = es[i-1] + Prev = prev + } + if p := e.prev; p != prev { + panic(fmt.Sprintf("elt[%d](%p).prev = %p, want %p", i, e, p, prev)) + } + if p := e.Prev(); p != Prev { + panic(fmt.Sprintf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev)) + } + + next := root + Next := (*_Element[T])(nil) + if i < len(es)-1 { + next = es[i+1] + Next = next + } + if n := e.next; n != next { + panic(fmt.Sprintf("elt[%d](%p).next = %p, want %p", i, e, n, next)) + } + if n := e.Next(); n != Next { + panic(fmt.Sprintf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next)) + } + } +} + +func TestList() { + l := _New[string]() + checkListPointers(l, []*(_Element[string]){}) + + // Single element list + e := l.PushFront("a") + checkListPointers(l, []*(_Element[string]){e}) + l.MoveToFront(e) + checkListPointers(l, []*(_Element[string]){e}) + l.MoveToBack(e) + checkListPointers(l, []*(_Element[string]){e}) + l.Remove(e) + checkListPointers(l, []*(_Element[string]){}) + + // Bigger list + l2 := _New[int]() + e2 := l2.PushFront(2) + e1 := l2.PushFront(1) + e3 := l2.PushBack(3) + e4 := l2.PushBack(600) + checkListPointers(l2, []*(_Element[int]){e1, e2, e3, e4}) + + l2.Remove(e2) + checkListPointers(l2, []*(_Element[int]){e1, e3, e4}) + + l2.MoveToFront(e3) // move from middle + checkListPointers(l2, []*(_Element[int]){e3, e1, e4}) + + l2.MoveToFront(e1) + l2.MoveToBack(e3) // move from middle + checkListPointers(l2, []*(_Element[int]){e1, e4, e3}) + + l2.MoveToFront(e3) // move from back + checkListPointers(l2, []*(_Element[int]){e3, e1, e4}) + l2.MoveToFront(e3) // should be no-op + checkListPointers(l2, []*(_Element[int]){e3, e1, e4}) + + l2.MoveToBack(e3) // move from front + checkListPointers(l2, []*(_Element[int]){e1, e4, e3}) + l2.MoveToBack(e3) // should be no-op + checkListPointers(l2, []*(_Element[int]){e1, e4, e3}) + + e2 = l2.InsertBefore(2, e1) // insert before front + checkListPointers(l2, []*(_Element[int]){e2, e1, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertBefore(2, e4) // insert before middle + checkListPointers(l2, []*(_Element[int]){e1, e2, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertBefore(2, e3) // insert before back + checkListPointers(l2, []*(_Element[int]){e1, e4, e2, e3}) + l2.Remove(e2) + + e2 = l2.InsertAfter(2, e1) // insert after front + checkListPointers(l2, []*(_Element[int]){e1, e2, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertAfter(2, e4) // insert after middle + checkListPointers(l2, []*(_Element[int]){e1, e4, e2, e3}) + l2.Remove(e2) + e2 = l2.InsertAfter(2, e3) // insert after back + checkListPointers(l2, []*(_Element[int]){e1, e4, e3, e2}) + l2.Remove(e2) + + // Check standard iteration. + sum := 0 + for e := l2.Front(); e != nil; e = e.Next() { + sum += e.Value + } + if sum != 604 { + panic(fmt.Sprintf("sum over l = %d, want 604", sum)) + } + + // Clear all elements by iterating + var next *_Element[int] + for e := l2.Front(); e != nil; e = next { + next = e.Next() + l2.Remove(e) + } + checkListPointers(l2, []*(_Element[int]){}) +} + +func checkList[T comparable](l *_List[T], es []interface{}) { + if !checkListLen(l, len(es)) { + return + } + + i := 0 + for e := l.Front(); e != nil; e = e.Next() { + le := e.Value + // Comparison between a generically-typed variable le and an interface. + if le != es[i] { + panic(fmt.Sprintf("elt[%d].Value = %v, want %v", i, le, es[i])) + } + i++ + } +} + +func TestExtending() { + l1 := _New[int]() + l2 := _New[int]() + + l1.PushBack(1) + l1.PushBack(2) + l1.PushBack(3) + + l2.PushBack(4) + l2.PushBack(5) + + l3 := _New[int]() + l3.PushBackList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushBackList(l2) + checkList(l3, []interface{}{1, 2, 3, 4, 5}) + + l3 = _New[int]() + l3.PushFrontList(l2) + checkList(l3, []interface{}{4, 5}) + l3.PushFrontList(l1) + checkList(l3, []interface{}{1, 2, 3, 4, 5}) + + checkList(l1, []interface{}{1, 2, 3}) + checkList(l2, []interface{}{4, 5}) + + l3 = _New[int]() + l3.PushBackList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushBackList(l3) + checkList(l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = _New[int]() + l3.PushFrontList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushFrontList(l3) + checkList(l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = _New[int]() + l1.PushBackList(l3) + checkList(l1, []interface{}{1, 2, 3}) + l1.PushFrontList(l3) + checkList(l1, []interface{}{1, 2, 3}) +} + +func TestRemove() { + l := _New[int]() + e1 := l.PushBack(1) + e2 := l.PushBack(2) + checkListPointers(l, []*(_Element[int]){e1, e2}) + e := l.Front() + l.Remove(e) + checkListPointers(l, []*(_Element[int]){e2}) + l.Remove(e) + checkListPointers(l, []*(_Element[int]){e2}) +} + +func TestIssue4103() { + l1 := _New[int]() + l1.PushBack(1) + l1.PushBack(2) + + l2 := _New[int]() + l2.PushBack(3) + l2.PushBack(4) + + e := l1.Front() + l2.Remove(e) // l2 should not change because e is not an element of l2 + if n := l2.Len(); n != 2 { + panic(fmt.Sprintf("l2.Len() = %d, want 2", n)) + } + + l1.InsertBefore(8, e) + if n := l1.Len(); n != 3 { + panic(fmt.Sprintf("l1.Len() = %d, want 3", n)) + } +} + +func TestIssue6349() { + l := _New[int]() + l.PushBack(1) + l.PushBack(2) + + e := l.Front() + l.Remove(e) + if e.Value != 1 { + panic(fmt.Sprintf("e.value = %d, want 1", e.Value)) + } + if e.Next() != nil { + panic(fmt.Sprintf("e.Next() != nil")) + } + if e.Prev() != nil { + panic(fmt.Sprintf("e.Prev() != nil")) + } +} + +func TestMove() { + l := _New[int]() + e1 := l.PushBack(1) + e2 := l.PushBack(2) + e3 := l.PushBack(3) + e4 := l.PushBack(4) + + l.MoveAfter(e3, e3) + checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4}) + l.MoveBefore(e2, e2) + checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4}) + + l.MoveAfter(e3, e2) + checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4}) + l.MoveBefore(e2, e3) + checkListPointers(l, []*(_Element[int]){e1, e2, e3, e4}) + + l.MoveBefore(e2, e4) + checkListPointers(l, []*(_Element[int]){e1, e3, e2, e4}) + e2, e3 = e3, e2 + + l.MoveBefore(e4, e1) + checkListPointers(l, []*(_Element[int]){e4, e1, e2, e3}) + e1, e2, e3, e4 = e4, e1, e2, e3 + + l.MoveAfter(e4, e1) + checkListPointers(l, []*(_Element[int]){e1, e4, e2, e3}) + e2, e3, e4 = e4, e2, e3 + + l.MoveAfter(e2, e3) + checkListPointers(l, []*(_Element[int]){e1, e3, e2, e4}) + e2, e3 = e3, e2 +} + +// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized _List +func TestZeroList() { + var l1 = new(_List[int]) + l1.PushFront(1) + checkList(l1, []interface{}{1}) + + var l2 = new(_List[int]) + l2.PushBack(1) + checkList(l2, []interface{}{1}) + + var l3 = new(_List[int]) + l3.PushFrontList(l1) + checkList(l3, []interface{}{1}) + + var l4 = new(_List[int]) + l4.PushBackList(l2) + checkList(l4, []interface{}{1}) +} + +// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l. +func TestInsertBeforeUnknownMark() { + var l _List[int] + l.PushBack(1) + l.PushBack(2) + l.PushBack(3) + l.InsertBefore(1, new(_Element[int])) + checkList(&l, []interface{}{1, 2, 3}) +} + +// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l. +func TestInsertAfterUnknownMark() { + var l _List[int] + l.PushBack(1) + l.PushBack(2) + l.PushBack(3) + l.InsertAfter(1, new(_Element[int])) + checkList(&l, []interface{}{1, 2, 3}) +} + +// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l. +func TestMoveUnknownMark() { + var l1 _List[int] + e1 := l1.PushBack(1) + + var l2 _List[int] + e2 := l2.PushBack(2) + + l1.MoveAfter(e1, e2) + checkList(&l1, []interface{}{1}) + checkList(&l2, []interface{}{2}) + + l1.MoveBefore(e1, e2) + checkList(&l1, []interface{}{1}) + checkList(&l2, []interface{}{2}) +} + +// Test the Transform function. +func TestTransform() { + l1 := _New[int]() + l1.PushBack(1) + l1.PushBack(2) + l2 := _Transform(l1, strconv.Itoa) + checkList(l2, []interface{}{"1", "2"}) +} + +func main() { + TestList() + TestExtending() + TestRemove() + TestIssue4103() + TestIssue6349() + TestMove() + TestZeroList() + TestInsertBeforeUnknownMark() + TestInsertAfterUnknownMark() + TestTransform() +} diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go new file mode 100644 index 0000000..e9c46d6 --- /dev/null +++ b/test/typeparam/listimp.dir/a.go @@ -0,0 +1,53 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +// List is a linked list of ordered values of type T. +type List[T Ordered] struct { + Next *List[T] + Val T +} + +func (l *List[T]) Largest() T { + var max T + for p := l; p != nil; p = p.Next { + if p.Val > max { + max = p.Val + } + } + return max +} + +type OrderedNum interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 +} + +// ListNum is a linked _List of ordered numeric values of type T. +type ListNum[T OrderedNum] struct { + Next *ListNum[T] + Val T +} + +const Clip = 5 + +// ClippedLargest returns the largest in the list of OrderNums, but a max of 5. +func (l *ListNum[T]) ClippedLargest() T { + var max T + for p := l; p != nil; p = p.Next { + if p.Val > max && p.Val < Clip { + max = p.Val + } + } + return max +} diff --git a/test/typeparam/listimp.dir/main.go b/test/typeparam/listimp.dir/main.go new file mode 100644 index 0000000..652a34a --- /dev/null +++ b/test/typeparam/listimp.dir/main.go @@ -0,0 +1,52 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + i3 := &a.List[int]{nil, 1} + i2 := &a.List[int]{i3, 3} + i1 := &a.List[int]{i2, 2} + if got, want := i1.Largest(), 3; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + b3 := &a.List[byte]{nil, byte(1)} + b2 := &a.List[byte]{b3, byte(3)} + b1 := &a.List[byte]{b2, byte(2)} + if got, want := b1.Largest(), byte(3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + f3 := &a.List[float64]{nil, 13.5} + f2 := &a.List[float64]{f3, 1.2} + f1 := &a.List[float64]{f2, 4.5} + if got, want := f1.Largest(), 13.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } + + s3 := &a.List[string]{nil, "dd"} + s2 := &a.List[string]{s3, "aa"} + s1 := &a.List[string]{s2, "bb"} + if got, want := s1.Largest(), "dd"; got != want { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + j3 := &a.ListNum[int]{nil, 1} + j2 := &a.ListNum[int]{j3, 32} + j1 := &a.ListNum[int]{j2, 2} + if got, want := j1.ClippedLargest(), 2; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + g3 := &a.ListNum[float64]{nil, 13.5} + g2 := &a.ListNum[float64]{g3, 1.2} + g1 := &a.ListNum[float64]{g2, 4.5} + if got, want := g1.ClippedLargest(), 4.5; got != want { + panic(fmt.Sprintf("got %f, want %f", got, want)) + } +} diff --git a/test/typeparam/listimp.go b/test/typeparam/listimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/listimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/listimp2.dir/a.go b/test/typeparam/listimp2.dir/a.go new file mode 100644 index 0000000..3a7dfc3 --- /dev/null +++ b/test/typeparam/listimp2.dir/a.go @@ -0,0 +1,298 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import ( + "fmt" +) + +// Element is an element of a linked list. +type Element[T any] struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *Element[T] + + // The list to which this element belongs. + list *List[T] + + // The value stored with this element. + Value T +} + +// Next returns the next list element or nil. +func (e *Element[T]) Next() *Element[T] { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// Prev returns the previous list element or nil. +func (e *Element[T]) Prev() *Element[T] { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// List represents a doubly linked list. +// The zero value for List is an empty list ready to use. +type List[T any] struct { + root Element[T] // sentinel list element, only &root, root.prev, and root.next are used + len int // current list length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *List[T]) Init() *List[T] { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// New returns an initialized list. +func New[T any]() *List[T] { return new(List[T]).Init() } + +// Len returns the number of elements of list l. +// The complexity is O(1). +func (l *List[_]) Len() int { return l.len } + +// Front returns the first element of list l or nil if the list is empty. +func (l *List[T]) Front() *Element[T] { + if l.len == 0 { + return nil + } + return l.root.next +} + +// Back returns the last element of list l or nil if the list is empty. +func (l *List[T]) Back() *Element[T] { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero List value. +func (l *List[_]) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *List[T]) insert(e, at *Element[T]) *Element[T] { + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&Element[T]{Value: v}, at). +func (l *List[T]) insertValue(v T, at *Element[T]) *Element[T] { + return l.insert(&Element[T]{Value: v}, at) +} + +// remove removes e from its list, decrements l.len, and returns e. +func (l *List[T]) remove(e *Element[T]) *Element[T] { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + return e +} + +// move moves e to next to at and returns e. +func (l *List[T]) move(e, at *Element[T]) *Element[T] { + if e == at { + return e + } + e.prev.next = e.next + e.next.prev = e.prev + + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e + + return e +} + +// Remove removes e from l if e is an element of list l. +// It returns the element value e.Value. +// The element must not be nil. +func (l *List[T]) Remove(e *Element[T]) T { + if e.list == l { + // if e.list == l, l must have been initialized when e was inserted + // in l or l == nil (e is a zero Element) and l.remove will crash + l.remove(e) + } + return e.Value +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *List[T]) PushFront(v T) *Element[T] { + l.lazyInit() + return l.insertValue(v, &l.root) +} + +// PushBack inserts a new element e with value v at the back of list l and returns e. +func (l *List[T]) PushBack(v T) *Element[T] { + l.lazyInit() + return l.insertValue(v, l.root.prev) +} + +// InsertBefore inserts a new element e with value v immediately before mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *List[T]) InsertBefore(v T, mark *Element[T]) *Element[T] { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark.prev) +} + +// InsertAfter inserts a new element e with value v immediately after mark and returns e. +// If mark is not an element of l, the list is not modified. +// The mark must not be nil. +func (l *List[T]) InsertAfter(v T, mark *Element[T]) *Element[T] { + if mark.list != l { + return nil + } + // see comment in List.Remove about initialization of l + return l.insertValue(v, mark) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *List[T]) MoveToFront(e *Element[T]) { + if e.list != l || l.root.next == e { + return + } + // see comment in List.Remove about initialization of l + l.move(e, &l.root) +} + +// MoveToBack moves element e to the back of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *List[T]) MoveToBack(e *Element[T]) { + if e.list != l || l.root.prev == e { + return + } + // see comment in List.Remove about initialization of l + l.move(e, l.root.prev) +} + +// MoveBefore moves element e to its new position before mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *List[T]) MoveBefore(e, mark *Element[T]) { + if e.list != l || e == mark || mark.list != l { + return + } + l.move(e, mark.prev) +} + +// MoveAfter moves element e to its new position after mark. +// If e or mark is not an element of l, or e == mark, the list is not modified. +// The element and mark must not be nil. +func (l *List[T]) MoveAfter(e, mark *Element[T]) { + if e.list != l || e == mark || mark.list != l { + return + } + l.move(e, mark) +} + +// PushBackList inserts a copy of an other list at the back of list l. +// The lists l and other may be the same. They must not be nil. +func (l *List[T]) PushBackList(other *List[T]) { + l.lazyInit() + for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { + l.insertValue(e.Value, l.root.prev) + } +} + +// PushFrontList inserts a copy of an other list at the front of list l. +// The lists l and other may be the same. They must not be nil. +func (l *List[T]) PushFrontList(other *List[T]) { + l.lazyInit() + for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { + l.insertValue(e.Value, &l.root) + } +} + +// Transform runs a transform function on a list returning a new list. +func Transform[TElem1, TElem2 any](lst *List[TElem1], f func(TElem1) TElem2) *List[TElem2] { + ret := New[TElem2]() + for p := lst.Front(); p != nil; p = p.Next() { + ret.PushBack(f(p.Value)) + } + return ret +} + +func CheckListLen[T any](l *List[T], len int) bool { + if n := l.Len(); n != len { + panic(fmt.Sprintf("l.Len() = %d, want %d", n, len)) + return false + } + return true +} + +func CheckListPointers[T any](l *List[T], es []*Element[T]) { + root := &l.root + + if !CheckListLen(l, len(es)) { + return + } + + // zero length lists must be the zero value or properly initialized (sentinel circle) + if len(es) == 0 { + if l.root.next != nil && l.root.next != root || l.root.prev != nil && l.root.prev != root { + panic(fmt.Sprintf("l.root.next = %p, l.root.prev = %p; both should both be nil or %p", l.root.next, l.root.prev, root)) + } + return + } + // len(es) > 0 + + // check internal and external prev/next connections + for i, e := range es { + prev := root + Prev := (*Element[T])(nil) + if i > 0 { + prev = es[i-1] + Prev = prev + } + if p := e.prev; p != prev { + panic(fmt.Sprintf("elt[%d](%p).prev = %p, want %p", i, e, p, prev)) + } + if p := e.Prev(); p != Prev { + panic(fmt.Sprintf("elt[%d](%p).Prev() = %p, want %p", i, e, p, Prev)) + } + + next := root + Next := (*Element[T])(nil) + if i < len(es)-1 { + next = es[i+1] + Next = next + } + if n := e.next; n != next { + panic(fmt.Sprintf("elt[%d](%p).next = %p, want %p", i, e, n, next)) + } + if n := e.Next(); n != Next { + panic(fmt.Sprintf("elt[%d](%p).Next() = %p, want %p", i, e, n, Next)) + } + } +} diff --git a/test/typeparam/listimp2.dir/main.go b/test/typeparam/listimp2.dir/main.go new file mode 100644 index 0000000..c3b936e --- /dev/null +++ b/test/typeparam/listimp2.dir/main.go @@ -0,0 +1,315 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" + "strconv" +) + +func TestList() { + l := a.New[string]() + a.CheckListPointers(l, []*(a.Element[string]){}) + + // Single element list + e := l.PushFront("a") + a.CheckListPointers(l, []*(a.Element[string]){e}) + l.MoveToFront(e) + a.CheckListPointers(l, []*(a.Element[string]){e}) + l.MoveToBack(e) + a.CheckListPointers(l, []*(a.Element[string]){e}) + l.Remove(e) + a.CheckListPointers(l, []*(a.Element[string]){}) + + // Bigger list + l2 := a.New[int]() + e2 := l2.PushFront(2) + e1 := l2.PushFront(1) + e3 := l2.PushBack(3) + e4 := l2.PushBack(600) + a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e3, e4}) + + l2.Remove(e2) + a.CheckListPointers(l2, []*(a.Element[int]){e1, e3, e4}) + + l2.MoveToFront(e3) // move from middle + a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4}) + + l2.MoveToFront(e1) + l2.MoveToBack(e3) // move from middle + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3}) + + l2.MoveToFront(e3) // move from back + a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4}) + l2.MoveToFront(e3) // should be no-op + a.CheckListPointers(l2, []*(a.Element[int]){e3, e1, e4}) + + l2.MoveToBack(e3) // move from front + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3}) + l2.MoveToBack(e3) // should be no-op + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3}) + + e2 = l2.InsertBefore(2, e1) // insert before front + a.CheckListPointers(l2, []*(a.Element[int]){e2, e1, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertBefore(2, e4) // insert before middle + a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertBefore(2, e3) // insert before back + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e2, e3}) + l2.Remove(e2) + + e2 = l2.InsertAfter(2, e1) // insert after front + a.CheckListPointers(l2, []*(a.Element[int]){e1, e2, e4, e3}) + l2.Remove(e2) + e2 = l2.InsertAfter(2, e4) // insert after middle + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e2, e3}) + l2.Remove(e2) + e2 = l2.InsertAfter(2, e3) // insert after back + a.CheckListPointers(l2, []*(a.Element[int]){e1, e4, e3, e2}) + l2.Remove(e2) + + // Check standard iteration. + sum := 0 + for e := l2.Front(); e != nil; e = e.Next() { + sum += e.Value + } + if sum != 604 { + panic(fmt.Sprintf("sum over l = %d, want 604", sum)) + } + + // Clear all elements by iterating + var next *a.Element[int] + for e := l2.Front(); e != nil; e = next { + next = e.Next() + l2.Remove(e) + } + a.CheckListPointers(l2, []*(a.Element[int]){}) +} + +func checkList[T comparable](l *a.List[T], es []interface{}) { + if !a.CheckListLen(l, len(es)) { + return + } + + i := 0 + for e := l.Front(); e != nil; e = e.Next() { + le := e.Value + // Comparison between a generically-typed variable le and an interface. + if le != es[i] { + panic(fmt.Sprintf("elt[%d].Value = %v, want %v", i, le, es[i])) + } + i++ + } +} + +func TestExtending() { + l1 := a.New[int]() + l2 := a.New[int]() + + l1.PushBack(1) + l1.PushBack(2) + l1.PushBack(3) + + l2.PushBack(4) + l2.PushBack(5) + + l3 := a.New[int]() + l3.PushBackList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushBackList(l2) + checkList(l3, []interface{}{1, 2, 3, 4, 5}) + + l3 = a.New[int]() + l3.PushFrontList(l2) + checkList(l3, []interface{}{4, 5}) + l3.PushFrontList(l1) + checkList(l3, []interface{}{1, 2, 3, 4, 5}) + + checkList(l1, []interface{}{1, 2, 3}) + checkList(l2, []interface{}{4, 5}) + + l3 = a.New[int]() + l3.PushBackList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushBackList(l3) + checkList(l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = a.New[int]() + l3.PushFrontList(l1) + checkList(l3, []interface{}{1, 2, 3}) + l3.PushFrontList(l3) + checkList(l3, []interface{}{1, 2, 3, 1, 2, 3}) + + l3 = a.New[int]() + l1.PushBackList(l3) + checkList(l1, []interface{}{1, 2, 3}) + l1.PushFrontList(l3) + checkList(l1, []interface{}{1, 2, 3}) +} + +func TestRemove() { + l := a.New[int]() + e1 := l.PushBack(1) + e2 := l.PushBack(2) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2}) + e := l.Front() + l.Remove(e) + a.CheckListPointers(l, []*(a.Element[int]){e2}) + l.Remove(e) + a.CheckListPointers(l, []*(a.Element[int]){e2}) +} + +func TestIssue4103() { + l1 := a.New[int]() + l1.PushBack(1) + l1.PushBack(2) + + l2 := a.New[int]() + l2.PushBack(3) + l2.PushBack(4) + + e := l1.Front() + l2.Remove(e) // l2 should not change because e is not an element of l2 + if n := l2.Len(); n != 2 { + panic(fmt.Sprintf("l2.Len() = %d, want 2", n)) + } + + l1.InsertBefore(8, e) + if n := l1.Len(); n != 3 { + panic(fmt.Sprintf("l1.Len() = %d, want 3", n)) + } +} + +func TestIssue6349() { + l := a.New[int]() + l.PushBack(1) + l.PushBack(2) + + e := l.Front() + l.Remove(e) + if e.Value != 1 { + panic(fmt.Sprintf("e.value = %d, want 1", e.Value)) + } + if e.Next() != nil { + panic(fmt.Sprintf("e.Next() != nil")) + } + if e.Prev() != nil { + panic(fmt.Sprintf("e.Prev() != nil")) + } +} + +func TestMove() { + l := a.New[int]() + e1 := l.PushBack(1) + e2 := l.PushBack(2) + e3 := l.PushBack(3) + e4 := l.PushBack(4) + + l.MoveAfter(e3, e3) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + l.MoveBefore(e2, e2) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + + l.MoveAfter(e3, e2) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + l.MoveBefore(e2, e3) + a.CheckListPointers(l, []*(a.Element[int]){e1, e2, e3, e4}) + + l.MoveBefore(e2, e4) + a.CheckListPointers(l, []*(a.Element[int]){e1, e3, e2, e4}) + e2, e3 = e3, e2 + + l.MoveBefore(e4, e1) + a.CheckListPointers(l, []*(a.Element[int]){e4, e1, e2, e3}) + e1, e2, e3, e4 = e4, e1, e2, e3 + + l.MoveAfter(e4, e1) + a.CheckListPointers(l, []*(a.Element[int]){e1, e4, e2, e3}) + e2, e3, e4 = e4, e2, e3 + + l.MoveAfter(e2, e3) + a.CheckListPointers(l, []*(a.Element[int]){e1, e3, e2, e4}) + e2, e3 = e3, e2 +} + +// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized a.List +func TestZeroList() { + var l1 = new(a.List[int]) + l1.PushFront(1) + checkList(l1, []interface{}{1}) + + var l2 = new(a.List[int]) + l2.PushBack(1) + checkList(l2, []interface{}{1}) + + var l3 = new(a.List[int]) + l3.PushFrontList(l1) + checkList(l3, []interface{}{1}) + + var l4 = new(a.List[int]) + l4.PushBackList(l2) + checkList(l4, []interface{}{1}) +} + +// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l. +func TestInsertBeforeUnknownMark() { + var l a.List[int] + l.PushBack(1) + l.PushBack(2) + l.PushBack(3) + l.InsertBefore(1, new(a.Element[int])) + checkList(&l, []interface{}{1, 2, 3}) +} + +// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l. +func TestInsertAfterUnknownMark() { + var l a.List[int] + l.PushBack(1) + l.PushBack(2) + l.PushBack(3) + l.InsertAfter(1, new(a.Element[int])) + checkList(&l, []interface{}{1, 2, 3}) +} + +// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l. +func TestMoveUnknownMark() { + var l1 a.List[int] + e1 := l1.PushBack(1) + + var l2 a.List[int] + e2 := l2.PushBack(2) + + l1.MoveAfter(e1, e2) + checkList(&l1, []interface{}{1}) + checkList(&l2, []interface{}{2}) + + l1.MoveBefore(e1, e2) + checkList(&l1, []interface{}{1}) + checkList(&l2, []interface{}{2}) +} + +// Test the Transform function. +func TestTransform() { + l1 := a.New[int]() + l1.PushBack(1) + l1.PushBack(2) + l2 := a.Transform(l1, strconv.Itoa) + checkList(l2, []interface{}{"1", "2"}) +} + +func main() { + TestList() + TestExtending() + TestRemove() + TestIssue4103() + TestIssue6349() + TestMove() + TestZeroList() + TestInsertBeforeUnknownMark() + TestInsertAfterUnknownMark() + TestTransform() +} diff --git a/test/typeparam/listimp2.go b/test/typeparam/listimp2.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/listimp2.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/lockable.go b/test/typeparam/lockable.go new file mode 100644 index 0000000..2b50e2c --- /dev/null +++ b/test/typeparam/lockable.go @@ -0,0 +1,50 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "sync" + +// A Lockable is a value that may be safely simultaneously accessed +// from multiple goroutines via the Get and Set methods. +type Lockable[T any] struct { + x T + mu sync.Mutex +} + +// Get returns the value stored in a Lockable. +func (l *Lockable[T]) get() T { + l.mu.Lock() + defer l.mu.Unlock() + return l.x +} + +// set sets the value in a Lockable. +func (l *Lockable[T]) set(v T) { + l.mu.Lock() + defer l.mu.Unlock() + l.x = v +} + +func main() { + sl := Lockable[string]{x: "a"} + if got := sl.get(); got != "a" { + panic(got) + } + sl.set("b") + if got := sl.get(); got != "b" { + panic(got) + } + + il := Lockable[int]{x: 1} + if got := il.get(); got != 1 { + panic(got) + } + il.set(2) + if got := il.get(); got != 2 { + panic(got) + } +} diff --git a/test/typeparam/map.go b/test/typeparam/map.go new file mode 100644 index 0000000..eb68fe5 --- /dev/null +++ b/test/typeparam/map.go @@ -0,0 +1,39 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "reflect" + "strconv" +) + +// Map calls the function f on every element of the slice s, +// returning a new slice of the results. +func mapper[F, T any](s []F, f func(F) T) []T { + r := make([]T, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} + +func main() { + got := mapper([]int{1, 2, 3}, strconv.Itoa) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + fgot := mapper([]float64{2.5, 2.3, 3.5}, func(f float64) string { + return strconv.FormatFloat(f, 'f', -1, 64) + }) + fwant := []string{"2.5", "2.3", "3.5"} + if !reflect.DeepEqual(fgot, fwant) { + panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) + } +} diff --git a/test/typeparam/mapimp.dir/a.go b/test/typeparam/mapimp.dir/a.go new file mode 100644 index 0000000..cbfa80a --- /dev/null +++ b/test/typeparam/mapimp.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +// Map calls the function f on every element of the slice s, +// returning a new slice of the results. +func Mapper[F, T any](s []F, f func(F) T) []T { + r := make([]T, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} diff --git a/test/typeparam/mapimp.dir/main.go b/test/typeparam/mapimp.dir/main.go new file mode 100644 index 0000000..8a56ce2 --- /dev/null +++ b/test/typeparam/mapimp.dir/main.go @@ -0,0 +1,28 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" + "reflect" + "strconv" +) + +func main() { + got := a.Mapper([]int{1, 2, 3}, strconv.Itoa) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + fgot := a.Mapper([]float64{2.5, 2.3, 3.5}, func(f float64) string { + return strconv.FormatFloat(f, 'f', -1, 64) + }) + fwant := []string{"2.5", "2.3", "3.5"} + if !reflect.DeepEqual(fgot, fwant) { + panic(fmt.Sprintf("got %s, want %s", fgot, fwant)) + } +} diff --git a/test/typeparam/mapimp.go b/test/typeparam/mapimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/mapimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/maps.go b/test/typeparam/maps.go new file mode 100644 index 0000000..d4be5dd --- /dev/null +++ b/test/typeparam/maps.go @@ -0,0 +1,260 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "math" + "sort" +) + +// _Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func _SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// _Keys returns the keys of the map m. +// The keys will be an indeterminate order. +func _Keys[K comparable, V any](m map[K]V) []K { + r := make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} + +// _Values returns the values of the map m. +// The values will be in an indeterminate order. +func _Values[K comparable, V any](m map[K]V) []V { + r := make([]V, 0, len(m)) + for _, v := range m { + r = append(r, v) + } + return r +} + +// _Equal reports whether two maps contain the same key/value pairs. +// _Values are compared using ==. +func _Equal[K, V comparable](m1, m2 map[K]V) bool { + if len(m1) != len(m2) { + return false + } + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || v1 != v2 { + return false + } + } + return true +} + +// _Copy returns a copy of m. +func _Copy[K comparable, V any](m map[K]V) map[K]V { + r := make(map[K]V, len(m)) + for k, v := range m { + r[k] = v + } + return r +} + +// _Add adds all key/value pairs in m2 to m1. _Keys in m2 that are already +// present in m1 will be overwritten with the value in m2. +func _Add[K comparable, V any](m1, m2 map[K]V) { + for k, v := range m2 { + m1[k] = v + } +} + +// _Sub removes all keys in m2 from m1. _Keys in m2 that are not present +// in m1 are ignored. The values in m2 are ignored. +func _Sub[K comparable, V any](m1, m2 map[K]V) { + for k := range m2 { + delete(m1, k) + } +} + +// _Intersect removes all keys from m1 that are not present in m2. +// _Keys in m2 that are not in m1 are ignored. The values in m2 are ignored. +func _Intersect[K comparable, V any](m1, m2 map[K]V) { + for k := range m1 { + if _, ok := m2[k]; !ok { + delete(m1, k) + } + } +} + +// _Filter deletes any key/value pairs from m for which f returns false. +func _Filter[K comparable, V any](m map[K]V, f func(K, V) bool) { + for k, v := range m { + if !f(k, v) { + delete(m, k) + } + } +} + +// _TransformValues applies f to each value in m. The keys remain unchanged. +func _TransformValues[K comparable, V any](m map[K]V, f func(V) V) { + for k, v := range m { + m[k] = f(v) + } +} + +var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16} +var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"} + +func TestKeys() { + want := []int{1, 2, 4, 8} + + got1 := _Keys(m1) + sort.Ints(got1) + if !_SliceEqual(got1, want) { + panic(fmt.Sprintf("_Keys(%v) = %v, want %v", m1, got1, want)) + } + + got2 := _Keys(m2) + sort.Ints(got2) + if !_SliceEqual(got2, want) { + panic(fmt.Sprintf("_Keys(%v) = %v, want %v", m2, got2, want)) + } +} + +func TestValues() { + got1 := _Values(m1) + want1 := []int{2, 4, 8, 16} + sort.Ints(got1) + if !_SliceEqual(got1, want1) { + panic(fmt.Sprintf("_Values(%v) = %v, want %v", m1, got1, want1)) + } + + got2 := _Values(m2) + want2 := []string{"16", "2", "4", "8"} + sort.Strings(got2) + if !_SliceEqual(got2, want2) { + panic(fmt.Sprintf("_Values(%v) = %v, want %v", m2, got2, want2)) + } +} + +func TestEqual() { + if !_Equal(m1, m1) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", m1, m1)) + } + if _Equal(m1, nil) { + panic(fmt.Sprintf("_Equal(%v, nil) = true, want false", m1)) + } + if _Equal(nil, m1) { + panic(fmt.Sprintf("_Equal(nil, %v) = true, want false", m1)) + } + if !_Equal[int, int](nil, nil) { + panic("_Equal(nil, nil) = false, want true") + } + if ms := map[int]int{1: 2}; _Equal(m1, ms) { + panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", m1, ms)) + } + + // Comparing NaN for equality is expected to fail. + mf := map[int]float64{1: 0, 2: math.NaN()} + if _Equal(mf, mf) { + panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", mf, mf)) + } +} + +func TestCopy() { + m2 := _Copy(m1) + if !_Equal(m1, m2) { + panic(fmt.Sprintf("_Copy(%v) = %v, want %v", m1, m2, m1)) + } + m2[16] = 32 + if _Equal(m1, m2) { + panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", m1, m2)) + } +} + +func TestAdd() { + mc := _Copy(m1) + _Add(mc, mc) + if !_Equal(mc, m1) { + panic(fmt.Sprintf("_Add(%v, %v) = %v, want %v", m1, m1, mc, m1)) + } + _Add(mc, map[int]int{16: 32}) + want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32} + if !_Equal(mc, want) { + panic(fmt.Sprintf("_Add result = %v, want %v", mc, want)) + } +} + +func TestSub() { + mc := _Copy(m1) + _Sub(mc, mc) + if len(mc) > 0 { + panic(fmt.Sprintf("_Sub(%v, %v) = %v, want empty map", m1, m1, mc)) + } + mc = _Copy(m1) + _Sub(mc, map[int]int{1: 0}) + want := map[int]int{2: 4, 4: 8, 8: 16} + if !_Equal(mc, want) { + panic(fmt.Sprintf("_Sub result = %v, want %v", mc, want)) + } +} + +func TestIntersect() { + mc := _Copy(m1) + _Intersect(mc, mc) + if !_Equal(mc, m1) { + panic(fmt.Sprintf("_Intersect(%v, %v) = %v, want %v", m1, m1, mc, m1)) + } + _Intersect(mc, map[int]int{1: 0, 2: 0}) + want := map[int]int{1: 2, 2: 4} + if !_Equal(mc, want) { + panic(fmt.Sprintf("_Intersect result = %v, want %v", mc, want)) + } +} + +func TestFilter() { + mc := _Copy(m1) + _Filter(mc, func(int, int) bool { return true }) + if !_Equal(mc, m1) { + panic(fmt.Sprintf("_Filter(%v, true) = %v, want %v", m1, mc, m1)) + } + _Filter(mc, func(k, v int) bool { return k < 3 }) + want := map[int]int{1: 2, 2: 4} + if !_Equal(mc, want) { + panic(fmt.Sprintf("_Filter result = %v, want %v", mc, want)) + } +} + +func TestTransformValues() { + mc := _Copy(m1) + _TransformValues(mc, func(i int) int { return i / 2 }) + want := map[int]int{1: 1, 2: 2, 4: 4, 8: 8} + if !_Equal(mc, want) { + panic(fmt.Sprintf("_TransformValues result = %v, want %v", mc, want)) + } +} + +func main() { + TestKeys() + TestValues() + TestEqual() + TestCopy() + TestAdd() + TestSub() + TestIntersect() + TestFilter() + TestTransformValues() +} diff --git a/test/typeparam/mapsimp.dir/a.go b/test/typeparam/mapsimp.dir/a.go new file mode 100644 index 0000000..696e2a5 --- /dev/null +++ b/test/typeparam/mapsimp.dir/a.go @@ -0,0 +1,108 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +// SliceEqual reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// Keys returns the keys of the map m. +// The keys will be an indeterminate order. +func Keys[K comparable, V any](m map[K]V) []K { + r := make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} + +// Values returns the values of the map m. +// The values will be in an indeterminate order. +func Values[K comparable, V any](m map[K]V) []V { + r := make([]V, 0, len(m)) + for _, v := range m { + r = append(r, v) + } + return r +} + +// Equal reports whether two maps contain the same key/value pairs. +// Values are compared using ==. +func Equal[K, V comparable](m1, m2 map[K]V) bool { + if len(m1) != len(m2) { + return false + } + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || v1 != v2 { + return false + } + } + return true +} + +// Copy returns a copy of m. +func Copy[K comparable, V any](m map[K]V) map[K]V { + r := make(map[K]V, len(m)) + for k, v := range m { + r[k] = v + } + return r +} + +// Add adds all key/value pairs in m2 to m1. Keys in m2 that are already +// present in m1 will be overwritten with the value in m2. +func Add[K comparable, V any](m1, m2 map[K]V) { + for k, v := range m2 { + m1[k] = v + } +} + +// Sub removes all keys in m2 from m1. Keys in m2 that are not present +// in m1 are ignored. The values in m2 are ignored. +func Sub[K comparable, V any](m1, m2 map[K]V) { + for k := range m2 { + delete(m1, k) + } +} + +// Intersect removes all keys from m1 that are not present in m2. +// Keys in m2 that are not in m1 are ignored. The values in m2 are ignored. +func Intersect[K comparable, V any](m1, m2 map[K]V) { + for k := range m1 { + if _, ok := m2[k]; !ok { + delete(m1, k) + } + } +} + +// Filter deletes any key/value pairs from m for which f returns false. +func Filter[K comparable, V any](m map[K]V, f func(K, V) bool) { + for k, v := range m { + if !f(k, v) { + delete(m, k) + } + } +} + +// TransformValues applies f to each value in m. The keys remain unchanged. +func TransformValues[K comparable, V any](m map[K]V, f func(V) V) { + for k, v := range m { + m[k] = f(v) + } +} diff --git a/test/typeparam/mapsimp.dir/main.go b/test/typeparam/mapsimp.dir/main.go new file mode 100644 index 0000000..45f7d39 --- /dev/null +++ b/test/typeparam/mapsimp.dir/main.go @@ -0,0 +1,156 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" + "math" + "sort" +) + +var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16} +var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"} + +func TestKeys() { + want := []int{1, 2, 4, 8} + + got1 := a.Keys(m1) + sort.Ints(got1) + if !a.SliceEqual(got1, want) { + panic(fmt.Sprintf("a.Keys(%v) = %v, want %v", m1, got1, want)) + } + + got2 := a.Keys(m2) + sort.Ints(got2) + if !a.SliceEqual(got2, want) { + panic(fmt.Sprintf("a.Keys(%v) = %v, want %v", m2, got2, want)) + } +} + +func TestValues() { + got1 := a.Values(m1) + want1 := []int{2, 4, 8, 16} + sort.Ints(got1) + if !a.SliceEqual(got1, want1) { + panic(fmt.Sprintf("a.Values(%v) = %v, want %v", m1, got1, want1)) + } + + got2 := a.Values(m2) + want2 := []string{"16", "2", "4", "8"} + sort.Strings(got2) + if !a.SliceEqual(got2, want2) { + panic(fmt.Sprintf("a.Values(%v) = %v, want %v", m2, got2, want2)) + } +} + +func TestEqual() { + if !a.Equal(m1, m1) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", m1, m1)) + } + if a.Equal(m1, nil) { + panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", m1)) + } + if a.Equal(nil, m1) { + panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", m1)) + } + if !a.Equal[int, int](nil, nil) { + panic("a.Equal(nil, nil) = false, want true") + } + if ms := map[int]int{1: 2}; a.Equal(m1, ms) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", m1, ms)) + } + + // Comparing NaN for equality is expected to fail. + mf := map[int]float64{1: 0, 2: math.NaN()} + if a.Equal(mf, mf) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", mf, mf)) + } +} + +func TestCopy() { + m2 := a.Copy(m1) + if !a.Equal(m1, m2) { + panic(fmt.Sprintf("a.Copy(%v) = %v, want %v", m1, m2, m1)) + } + m2[16] = 32 + if a.Equal(m1, m2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", m1, m2)) + } +} + +func TestAdd() { + mc := a.Copy(m1) + a.Add(mc, mc) + if !a.Equal(mc, m1) { + panic(fmt.Sprintf("a.Add(%v, %v) = %v, want %v", m1, m1, mc, m1)) + } + a.Add(mc, map[int]int{16: 32}) + want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Add result = %v, want %v", mc, want)) + } +} + +func TestSub() { + mc := a.Copy(m1) + a.Sub(mc, mc) + if len(mc) > 0 { + panic(fmt.Sprintf("a.Sub(%v, %v) = %v, want empty map", m1, m1, mc)) + } + mc = a.Copy(m1) + a.Sub(mc, map[int]int{1: 0}) + want := map[int]int{2: 4, 4: 8, 8: 16} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Sub result = %v, want %v", mc, want)) + } +} + +func TestIntersect() { + mc := a.Copy(m1) + a.Intersect(mc, mc) + if !a.Equal(mc, m1) { + panic(fmt.Sprintf("a.Intersect(%v, %v) = %v, want %v", m1, m1, mc, m1)) + } + a.Intersect(mc, map[int]int{1: 0, 2: 0}) + want := map[int]int{1: 2, 2: 4} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Intersect result = %v, want %v", mc, want)) + } +} + +func TestFilter() { + mc := a.Copy(m1) + a.Filter(mc, func(int, int) bool { return true }) + if !a.Equal(mc, m1) { + panic(fmt.Sprintf("a.Filter(%v, true) = %v, want %v", m1, mc, m1)) + } + a.Filter(mc, func(k, v int) bool { return k < 3 }) + want := map[int]int{1: 2, 2: 4} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.Filter result = %v, want %v", mc, want)) + } +} + +func TestTransformValues() { + mc := a.Copy(m1) + a.TransformValues(mc, func(i int) int { return i / 2 }) + want := map[int]int{1: 1, 2: 2, 4: 4, 8: 8} + if !a.Equal(mc, want) { + panic(fmt.Sprintf("a.TransformValues result = %v, want %v", mc, want)) + } +} + +func main() { + TestKeys() + TestValues() + TestEqual() + TestCopy() + TestAdd() + TestSub() + TestIntersect() + TestFilter() + TestTransformValues() +} diff --git a/test/typeparam/mapsimp.go b/test/typeparam/mapsimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/mapsimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mdempsky/1.dir/a.go b/test/typeparam/mdempsky/1.dir/a.go new file mode 100644 index 0000000..a668eb5 --- /dev/null +++ b/test/typeparam/mdempsky/1.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type T[_ any] int + +func F() { _ = new(T[int]) } diff --git a/test/typeparam/mdempsky/1.dir/b.go b/test/typeparam/mdempsky/1.dir/b.go new file mode 100644 index 0000000..af6fef3 --- /dev/null +++ b/test/typeparam/mdempsky/1.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { a.F() } diff --git a/test/typeparam/mdempsky/1.go b/test/typeparam/mdempsky/1.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/mdempsky/1.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mdempsky/10.dir/a.go b/test/typeparam/mdempsky/10.dir/a.go new file mode 100644 index 0000000..95e111d --- /dev/null +++ b/test/typeparam/mdempsky/10.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type I[T any] interface{ M() T } diff --git a/test/typeparam/mdempsky/10.dir/b.go b/test/typeparam/mdempsky/10.dir/b.go new file mode 100644 index 0000000..0ef28fd --- /dev/null +++ b/test/typeparam/mdempsky/10.dir/b.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +var m = a.I[int].M + +var never bool + +func main() { + if never { + m(nil) + } +} diff --git a/test/typeparam/mdempsky/10.go b/test/typeparam/mdempsky/10.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/mdempsky/10.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mdempsky/12.dir/a.go b/test/typeparam/mdempsky/12.dir/a.go new file mode 100644 index 0000000..ee8be93 --- /dev/null +++ b/test/typeparam/mdempsky/12.dir/a.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type S[T any] struct { + F T +} + +var X = S[int]{} diff --git a/test/typeparam/mdempsky/12.dir/main.go b/test/typeparam/mdempsky/12.dir/main.go new file mode 100644 index 0000000..2891322 --- /dev/null +++ b/test/typeparam/mdempsky/12.dir/main.go @@ -0,0 +1,13 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" +) + +func main() { + _ = a.X +} diff --git a/test/typeparam/mdempsky/12.go b/test/typeparam/mdempsky/12.go new file mode 100644 index 0000000..0316402 --- /dev/null +++ b/test/typeparam/mdempsky/12.go @@ -0,0 +1,9 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Reported by Cuong Manh Le. + +package ignored diff --git a/test/typeparam/mdempsky/13.go b/test/typeparam/mdempsky/13.go new file mode 100644 index 0000000..8e11352 --- /dev/null +++ b/test/typeparam/mdempsky/13.go @@ -0,0 +1,84 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Interface which will be used as a regular interface type and as a type bound. +type Mer interface{ + M() +} + +// Interface that is a superset of Mer. +type Mer2 interface { + M() + String() string +} + +func F[T Mer](t T) { + T.M(t) + t.M() +} + +type MyMer int + +func (MyMer) M() {} +func (MyMer) String() string { + return "aa" +} + +// Parameterized interface +type Abs[T any] interface { + Abs() T +} + +func G[T Abs[U], U any](t T) { + T.Abs(t) + t.Abs() +} + +type MyInt int +func (m MyInt) Abs() MyInt { + if m < 0 { + return -m + } + return m +} + +type Abs2 interface { + Abs() MyInt +} + + +func main() { + mm := MyMer(3) + ms := struct{ Mer }{Mer: mm } + + // Testing F with an interface type arg: Mer and Mer2 + F[Mer](mm) + F[Mer2](mm) + F[struct{ Mer }](ms) + F[*struct{ Mer }](&ms) + + ms2 := struct { MyMer }{MyMer: mm} + ms3 := struct { *MyMer }{MyMer: &mm} + + // Testing F with a concrete type arg + F[MyMer](mm) + F[*MyMer](&mm) + F[struct{ MyMer }](ms2) + F[struct{ *MyMer }](ms3) + F[*struct{ MyMer }](&ms2) + F[*struct{ *MyMer }](&ms3) + + // Testing G with a concrete type args + mi := MyInt(-3) + G[MyInt,MyInt](mi) + + // Interface Abs[MyInt] holding an mi. + intMi := Abs[MyInt](mi) + // First type arg here is Abs[MyInt], an interface type. + G[Abs[MyInt],MyInt](intMi) +} diff --git a/test/typeparam/mdempsky/14.go b/test/typeparam/mdempsky/14.go new file mode 100644 index 0000000..4af990c --- /dev/null +++ b/test/typeparam/mdempsky/14.go @@ -0,0 +1,40 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Zero returns the zero value of T +func Zero[T any]() (_ T) { + return +} + +type AnyInt[X any] int + +func (AnyInt[X]) M() { + var have interface{} = Zero[X]() + var want interface{} = Zero[MyInt]() + + if have != want { + println("FAIL") + } +} + +type I interface{ M() } + +type MyInt int +type U = AnyInt[MyInt] + +var x = U(0) +var i I = x + +func main() { + x.M() + U.M(x) + (*U).M(&x) + + i.M() + I.M(x) +} diff --git a/test/typeparam/mdempsky/15.go b/test/typeparam/mdempsky/15.go new file mode 100644 index 0000000..b03ad6f --- /dev/null +++ b/test/typeparam/mdempsky/15.go @@ -0,0 +1,69 @@ +// run -goexperiment fieldtrack + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that generics, promoted methods, and //go:nointerface +// interoperate as expected. + +package main + +import ( + "reflect" +) + +func TypeString[T any]() string { + return reflect.TypeOf(new(T)).Elem().String() +} + +func Test[T, Bad, Good any]() { + switch interface{}(new(T)).(type) { + case Bad: + println("FAIL:", TypeString[T](), "matched", TypeString[Bad]()) + case Good: + // ok + default: + println("FAIL:", TypeString[T](), "did not match", TypeString[Good]()) + } +} + +func TestE[T any]() { Test[T, interface{ EBad() }, interface{ EGood() }]() } +func TestX[T any]() { Test[T, interface{ XBad() }, interface{ XGood() }]() } + +type E struct{} + +//go:nointerface +func (E) EBad() {} +func (E) EGood() {} + +type X[T any] struct{ E } + +//go:nointerface +func (X[T]) XBad() {} +func (X[T]) XGood() {} + +type W struct{ X[int] } + +func main() { + _ = E.EGood + _ = E.EBad + + TestE[E]() + + _ = X[int].EGood + _ = X[int].EBad + _ = X[int].XGood + _ = X[int].XBad + + TestE[X[int]]() + TestX[X[int]]() + + _ = W.EGood + _ = W.EBad + _ = W.XGood + _ = W.XBad + + TestE[W]() + TestX[W]() +} diff --git a/test/typeparam/mdempsky/16.go b/test/typeparam/mdempsky/16.go new file mode 100644 index 0000000..f4f79b9 --- /dev/null +++ b/test/typeparam/mdempsky/16.go @@ -0,0 +1,34 @@ +// run + +// Copyright 2022 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 that type assertion panics mention the real interface type, +// not their shape type. + +package main + +import ( + "fmt" + "runtime" + "strings" +) + +func main() { + // The exact error message isn't important, but it should mention + // `main.T`, not `go.shape.int_0`. + if have := F[T](); !strings.Contains(have, "interface { T() main.T }") { + fmt.Printf("FAIL: unexpected panic message: %q\n", have) + } +} + +type T int + +func F[T any]() (res string) { + defer func() { + res = recover().(runtime.Error).Error() + }() + _ = interface{ T() T }(nil).(T) + return +} diff --git a/test/typeparam/mdempsky/17.go b/test/typeparam/mdempsky/17.go new file mode 100644 index 0000000..12385c3 --- /dev/null +++ b/test/typeparam/mdempsky/17.go @@ -0,0 +1,110 @@ +// run + +// Copyright 2022 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 that implicit conversions of derived types to interface type +// in range loops work correctly. + +package main + +import ( + "fmt" + "reflect" +) + +func main() { + test{"int", "V"}.match(RangeArrayAny[V]()) + test{"int", "V"}.match(RangeArrayIface[V]()) + test{"V"}.match(RangeChanAny[V]()) + test{"V"}.match(RangeChanIface[V]()) + test{"K", "V"}.match(RangeMapAny[K, V]()) + test{"K", "V"}.match(RangeMapIface[K, V]()) + test{"int", "V"}.match(RangeSliceAny[V]()) + test{"int", "V"}.match(RangeSliceIface[V]()) +} + +type test []string + +func (t test) match(args ...any) { + if len(t) != len(args) { + fmt.Printf("FAIL: want %v values, have %v\n", len(t), len(args)) + return + } + for i, want := range t { + if have := reflect.TypeOf(args[i]).Name(); want != have { + fmt.Printf("FAIL: %v: want type %v, have %v\n", i, want, have) + } + } +} + +type iface interface{ M() int } + +type K int +type V int + +func (K) M() int { return 0 } +func (V) M() int { return 0 } + +func RangeArrayAny[V any]() (k, v any) { + for k, v = range [...]V{zero[V]()} { + } + return +} + +func RangeArrayIface[V iface]() (k any, v iface) { + for k, v = range [...]V{zero[V]()} { + } + return +} + +func RangeChanAny[V any]() (v any) { + for v = range chanOf(zero[V]()) { + } + return +} + +func RangeChanIface[V iface]() (v iface) { + for v = range chanOf(zero[V]()) { + } + return +} + +func RangeMapAny[K comparable, V any]() (k, v any) { + for k, v = range map[K]V{zero[K](): zero[V]()} { + } + return +} + +func RangeMapIface[K interface { + iface + comparable +}, V iface]() (k, v iface) { + for k, v = range map[K]V{zero[K](): zero[V]()} { + } + return +} + +func RangeSliceAny[V any]() (k, v any) { + for k, v = range []V{zero[V]()} { + } + return +} + +func RangeSliceIface[V iface]() (k any, v iface) { + for k, v = range []V{zero[V]()} { + } + return +} + +func chanOf[T any](elems ...T) chan T { + c := make(chan T, len(elems)) + for _, elem := range elems { + c <- elem + } + close(c) + return c +} + +func zero[T any]() (_ T) { return } diff --git a/test/typeparam/mdempsky/18.go b/test/typeparam/mdempsky/18.go new file mode 100644 index 0000000..f4a4ec7 --- /dev/null +++ b/test/typeparam/mdempsky/18.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2022 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 that implicit conversions to interface type in a select/case +// clause are compiled correctly. + +package main + +import "fmt" + +func main() { f[int]() } + +func f[T any]() { + ch := make(chan T) + close(ch) + + var i, ok any + select { + case i, ok = <-ch: + } + + fmt.Printf("%T %T\n", i, ok) +} diff --git a/test/typeparam/mdempsky/18.out b/test/typeparam/mdempsky/18.out new file mode 100644 index 0000000..19f1c39 --- /dev/null +++ b/test/typeparam/mdempsky/18.out @@ -0,0 +1 @@ +int bool diff --git a/test/typeparam/mdempsky/19.go b/test/typeparam/mdempsky/19.go new file mode 100644 index 0000000..53d979a --- /dev/null +++ b/test/typeparam/mdempsky/19.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2022 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 that type parameter methods are handled correctly, even when +// the instantiating type argument has additional methods. + +package main + +func main() { + F(X(0)) +} + +type I interface{ B() } + +func F[T I](t T) { + CallMethod(t) + MethodExpr[T]()(t) + MethodVal(t)() +} + +func CallMethod[T I](t T) { t.B() } +func MethodExpr[T I]() func(T) { return T.B } +func MethodVal[T I](t T) func() { return t.B } + +type X int + +func (X) A() { panic("FAIL") } +func (X) B() {} +func (X) C() { panic("FAIL") } diff --git a/test/typeparam/mdempsky/2.go b/test/typeparam/mdempsky/2.go new file mode 100644 index 0000000..ad548e6 --- /dev/null +++ b/test/typeparam/mdempsky/2.go @@ -0,0 +1,20 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type T[A, B, C any] int + +func (T[A, B, C]) m(x int) { + if x <= 0 { + return + } + T[B, C, A](0).m(x - 1) +} + +func main() { + T[int8, int16, int32](0).m(3) +} diff --git a/test/typeparam/mdempsky/20.go b/test/typeparam/mdempsky/20.go new file mode 100644 index 0000000..6b97ca1 --- /dev/null +++ b/test/typeparam/mdempsky/20.go @@ -0,0 +1,38 @@ +// run + +// Copyright 2022 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 that method expressions with a derived receiver type and +// promoted methods work correctly. + +package main + +func main() { + F[int]() + F[string]() +} + +func F[X any]() { + call(T[X].M, T[X].N) +} + +func call[X any](fns ...func(T[X]) int) { + for want, fn := range fns { + if have := fn(T[X]{}); have != want { + println("FAIL:", have, "!=", want) + } + } +} + +type T[X any] struct { + E1 + *E2[*X] +} + +type E1 struct{} +type E2[_ any] struct{} + +func (E1) M() int { return 0 } +func (*E2[_]) N() int { return 1 } diff --git a/test/typeparam/mdempsky/21.go b/test/typeparam/mdempsky/21.go new file mode 100644 index 0000000..da10ae3 --- /dev/null +++ b/test/typeparam/mdempsky/21.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2022 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 that devirtualization doesn't introduce spurious type +// assertion failures due to shaped and non-shaped interfaces having +// distinct itabs. + +package main + +func main() { + F[int]() +} + +func F[T any]() { + var i I[T] = X(0) + i.M() +} + +type I[T any] interface{ M() } + +type X int + +func (X) M() {} diff --git a/test/typeparam/mdempsky/3.dir/a.go b/test/typeparam/mdempsky/3.dir/a.go new file mode 100644 index 0000000..cf456e8 --- /dev/null +++ b/test/typeparam/mdempsky/3.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F[T interface{ chan int }](c T) {} diff --git a/test/typeparam/mdempsky/3.dir/b.go b/test/typeparam/mdempsky/3.dir/b.go new file mode 100644 index 0000000..0cfd142 --- /dev/null +++ b/test/typeparam/mdempsky/3.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func g() { a.F(make(chan int)) } diff --git a/test/typeparam/mdempsky/3.go b/test/typeparam/mdempsky/3.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/mdempsky/3.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mdempsky/4.dir/a.go b/test/typeparam/mdempsky/4.dir/a.go new file mode 100644 index 0000000..cb67294 --- /dev/null +++ b/test/typeparam/mdempsky/4.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F[T any](T) { +Loop: + for { + break Loop + } +} diff --git a/test/typeparam/mdempsky/4.dir/b.go b/test/typeparam/mdempsky/4.dir/b.go new file mode 100644 index 0000000..e1fb0e7 --- /dev/null +++ b/test/typeparam/mdempsky/4.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func f() { a.F(0) } diff --git a/test/typeparam/mdempsky/4.go b/test/typeparam/mdempsky/4.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/mdempsky/4.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mdempsky/5.go b/test/typeparam/mdempsky/5.go new file mode 100644 index 0000000..00d3b71 --- /dev/null +++ b/test/typeparam/mdempsky/5.go @@ -0,0 +1,15 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type X[T any] int + +func (X[T]) F(T) {} + +func x() { + X[interface{}](0).F(0) +} diff --git a/test/typeparam/mdempsky/6.go b/test/typeparam/mdempsky/6.go new file mode 100644 index 0000000..ed57009 --- /dev/null +++ b/test/typeparam/mdempsky/6.go @@ -0,0 +1,11 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type I[T any] interface{ M() T } + +var _ = I[int].M diff --git a/test/typeparam/mdempsky/7.dir/a.go b/test/typeparam/mdempsky/7.dir/a.go new file mode 100644 index 0000000..59c5995 --- /dev/null +++ b/test/typeparam/mdempsky/7.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type I[T any] interface{ M() T } + +var X I[int] diff --git a/test/typeparam/mdempsky/7.dir/b.go b/test/typeparam/mdempsky/7.dir/b.go new file mode 100644 index 0000000..9f70530 --- /dev/null +++ b/test/typeparam/mdempsky/7.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +var _ = a.X diff --git a/test/typeparam/mdempsky/7.go b/test/typeparam/mdempsky/7.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/mdempsky/7.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mdempsky/8.dir/a.go b/test/typeparam/mdempsky/8.dir/a.go new file mode 100644 index 0000000..607fe5e --- /dev/null +++ b/test/typeparam/mdempsky/8.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F[T interface{ comparable }]() {} diff --git a/test/typeparam/mdempsky/8.dir/b.go b/test/typeparam/mdempsky/8.dir/b.go new file mode 100644 index 0000000..ef2637b --- /dev/null +++ b/test/typeparam/mdempsky/8.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func init() { + a.F[func()]() // ERROR "does not satisfy comparable" +} diff --git a/test/typeparam/mdempsky/8.go b/test/typeparam/mdempsky/8.go new file mode 100644 index 0000000..e3a470b --- /dev/null +++ b/test/typeparam/mdempsky/8.go @@ -0,0 +1,7 @@ +// errorcheckdir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mdempsky/9.go b/test/typeparam/mdempsky/9.go new file mode 100644 index 0000000..948a9e5 --- /dev/null +++ b/test/typeparam/mdempsky/9.go @@ -0,0 +1,11 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func f[V any]() []V { return []V{0: *new(V)} } + +func g() { f[int]() } diff --git a/test/typeparam/metrics.go b/test/typeparam/metrics.go new file mode 100644 index 0000000..dcc5737 --- /dev/null +++ b/test/typeparam/metrics.go @@ -0,0 +1,196 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package metrics provides tracking arbitrary metrics composed of +// values of comparable types. +package main + +import ( + "fmt" + "sort" + "sync" +) + +// _Metric1 tracks metrics of values of some type. +type _Metric1[T comparable] struct { + mu sync.Mutex + m map[T]int +} + +// Add adds another instance of some value. +func (m *_Metric1[T]) Add(v T) { + m.mu.Lock() + defer m.mu.Unlock() + if m.m == nil { + m.m = make(map[T]int) + } + m.m[v]++ +} + +// Count returns the number of instances we've seen of v. +func (m *_Metric1[T]) Count(v T) int { + m.mu.Lock() + defer m.mu.Unlock() + return m.m[v] +} + +// Metrics returns all the values we've seen, in an indeterminate order. +func (m *_Metric1[T]) Metrics() []T { + return _Keys(m.m) +} + +type key2[T1, T2 comparable] struct { + f1 T1 + f2 T2 +} + +// _Metric2 tracks metrics of pairs of values. +type _Metric2[T1, T2 comparable] struct { + mu sync.Mutex + m map[key2[T1, T2]]int +} + +// Add adds another instance of some pair of values. +func (m *_Metric2[T1, T2]) Add(v1 T1, v2 T2) { + m.mu.Lock() + defer m.mu.Unlock() + if m.m == nil { + m.m = make(map[key2[T1, T2]]int) + } + m.m[key2[T1, T2]{v1, v2}]++ +} + +// Count returns the number of instances we've seen of v1/v2. +func (m *_Metric2[T1, T2]) Count(v1 T1, v2 T2) int { + m.mu.Lock() + defer m.mu.Unlock() + return m.m[key2[T1, T2]{v1, v2}] +} + +// Metrics returns all the values we've seen, in an indeterminate order. +func (m *_Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) { + for _, k := range _Keys(m.m) { + r1 = append(r1, k.f1) + r2 = append(r2, k.f2) + } + return r1, r2 +} + +type key3[T1, T2, T3 comparable] struct { + f1 T1 + f2 T2 + f3 T3 +} + +// _Metric3 tracks metrics of triplets of values. +type _Metric3[T1, T2, T3 comparable] struct { + mu sync.Mutex + m map[key3[T1, T2, T3]]int +} + +// Add adds another instance of some triplet of values. +func (m *_Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) { + m.mu.Lock() + defer m.mu.Unlock() + if m.m == nil { + m.m = make(map[key3[T1, T2, T3]]int) + } + m.m[key3[T1, T2, T3]{v1, v2, v3}]++ +} + +// Count returns the number of instances we've seen of v1/v2/v3. +func (m *_Metric3[T1, T2, T3]) Count(v1 T1, v2 T2, v3 T3) int { + m.mu.Lock() + defer m.mu.Unlock() + return m.m[key3[T1, T2, T3]{v1, v2, v3}] +} + +// Metrics returns all the values we've seen, in an indeterminate order. +func (m *_Metric3[T1, T2, T3]) Metrics() (r1 []T1, r2 []T2, r3 []T3) { + for k := range m.m { + r1 = append(r1, k.f1) + r2 = append(r2, k.f2) + r3 = append(r3, k.f3) + } + return r1, r2, r3 +} + +type S struct{ a, b, c string } + +func TestMetrics() { + m1 := _Metric1[string]{} + if got := m1.Count("a"); got != 0 { + panic(fmt.Sprintf("Count(%q) = %d, want 0", "a", got)) + } + m1.Add("a") + m1.Add("a") + if got := m1.Count("a"); got != 2 { + panic(fmt.Sprintf("Count(%q) = %d, want 2", "a", got)) + } + if got, want := m1.Metrics(), []string{"a"}; !_SlicesEqual(got, want) { + panic(fmt.Sprintf("Metrics = %v, want %v", got, want)) + } + + m2 := _Metric2[int, float64]{} + m2.Add(1, 1) + m2.Add(2, 2) + m2.Add(3, 3) + m2.Add(3, 3) + k1, k2 := m2.Metrics() + + sort.Ints(k1) + w1 := []int{1, 2, 3} + if !_SlicesEqual(k1, w1) { + panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k1, w1)) + } + + sort.Float64s(k2) + w2 := []float64{1, 2, 3} + if !_SlicesEqual(k2, w2) { + panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k2, w2)) + } + + m3 := _Metric3[string, S, S]{} + m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"}) + m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"}) + m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"}) + m3.Add("b", S{"d", "e", "f"}, S{"g", "h", "i"}) + if got := m3.Count("a", S{"d", "e", "f"}, S{"g", "h", "i"}); got != 3 { + panic(fmt.Sprintf("Count(%v, %v, %v) = %d, want 3", "a", S{"d", "e", "f"}, S{"g", "h", "i"}, got)) + } +} + +func main() { + TestMetrics() +} + +// _Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func _SlicesEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// _Keys returns the keys of the map m. +// The keys will be an indeterminate order. +func _Keys[K comparable, V any](m map[K]V) []K { + r := make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} diff --git a/test/typeparam/min.go b/test/typeparam/min.go new file mode 100644 index 0000000..a922450 --- /dev/null +++ b/test/typeparam/min.go @@ -0,0 +1,50 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type Ordered interface { + ~int | ~int64 | ~float64 | ~string +} + +func min[T Ordered](x, y T) T { + if x < y { + return x + } + return y +} + +func main() { + const want = 2 + if got := min[int](2, 3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := min(2, 3); got != want { + panic(fmt.Sprintf("want %d, got %d", want, got)) + } + + if got := min[float64](3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := min(3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + const want2 = "ay" + if got := min[string]("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } + + if got := min("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } +} diff --git a/test/typeparam/mincheck.dir/a.go b/test/typeparam/mincheck.dir/a.go new file mode 100644 index 0000000..fa0f249 --- /dev/null +++ b/test/typeparam/mincheck.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Ordered interface { + int | int64 | float64 +} + +func Min[T Ordered](x, y T) T { + if x < y { + return x + } + return y +} diff --git a/test/typeparam/mincheck.dir/main.go b/test/typeparam/mincheck.dir/main.go new file mode 100644 index 0000000..6f85f9e --- /dev/null +++ b/test/typeparam/mincheck.dir/main.go @@ -0,0 +1,38 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + const want = 2 + if got := a.Min[int](2, 3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(2, 3); got != want { + panic(fmt.Sprintf("want %d, got %d", want, got)) + } + + if got := a.Min[float64](3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + const want2 = "ay" + if got := a.Min[string]("bb", "ay"); got != want2 { // ERROR "string does not satisfy" + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } + + if got := a.Min("bb", "ay"); got != want2 { // ERROR "string does not satisfy" + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } +} diff --git a/test/typeparam/mincheck.go b/test/typeparam/mincheck.go new file mode 100644 index 0000000..e3a470b --- /dev/null +++ b/test/typeparam/mincheck.go @@ -0,0 +1,7 @@ +// errorcheckdir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/minimp.dir/a.go b/test/typeparam/minimp.dir/a.go new file mode 100644 index 0000000..fabde62 --- /dev/null +++ b/test/typeparam/minimp.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Ordered interface { + ~int | ~int64 | ~float64 | ~string +} + +func Min[T Ordered](x, y T) T { + if x < y { + return x + } + return y +} diff --git a/test/typeparam/minimp.dir/main.go b/test/typeparam/minimp.dir/main.go new file mode 100644 index 0000000..36bec0f --- /dev/null +++ b/test/typeparam/minimp.dir/main.go @@ -0,0 +1,38 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + const want = 2 + if got := a.Min[int](2, 3); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(2, 3); got != want { + panic(fmt.Sprintf("want %d, got %d", want, got)) + } + + if got := a.Min[float64](3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + if got := a.Min(3.5, 2.0); got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + const want2 = "ay" + if got := a.Min[string]("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } + + if got := a.Min("bb", "ay"); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } +} diff --git a/test/typeparam/minimp.go b/test/typeparam/minimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/minimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/mutualimp.dir/a.go b/test/typeparam/mutualimp.dir/a.go new file mode 100644 index 0000000..5b924d3 --- /dev/null +++ b/test/typeparam/mutualimp.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type X int + +func (x X) M() X { return x } + +func F[T interface{ M() U }, U interface{ M() T }]() {} +func G() { F[X, X]() } diff --git a/test/typeparam/mutualimp.dir/b.go b/test/typeparam/mutualimp.dir/b.go new file mode 100644 index 0000000..83cc3af --- /dev/null +++ b/test/typeparam/mutualimp.dir/b.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func H() { + a.F[a.X, a.X]() + a.G() +} diff --git a/test/typeparam/mutualimp.go b/test/typeparam/mutualimp.go new file mode 100644 index 0000000..b83fbd7 --- /dev/null +++ b/test/typeparam/mutualimp.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/nested.go b/test/typeparam/nested.go new file mode 100644 index 0000000..cdb8bfb --- /dev/null +++ b/test/typeparam/nested.go @@ -0,0 +1,134 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This test case stress tests a number of subtle cases involving +// nested type-parameterized declarations. At a high-level, it +// declares a generic function that contains a generic type +// declaration: +// +// func F[A intish]() { +// type T[B intish] struct{} +// +// // store reflect.Type tuple (A, B, F[A].T[B]) in tests +// } +// +// It then instantiates this function with a variety of type arguments +// for A and B. Particularly tricky things like shadowed types. +// +// From this data it tests two things: +// +// 1. Given tuples (A, B, F[A].T[B]) and (A', B', F[A'].T[B']), +// F[A].T[B] should be identical to F[A'].T[B'] iff (A, B) is +// identical to (A', B'). +// +// 2. A few of the instantiations are constructed to be identical, and +// it tests that exactly these pairs are duplicated (by golden +// output comparison to nested.out). +// +// In both cases, we're effectively using the compiler's existing +// runtime.Type handling (which is well tested) of type identity of A +// and B as a way to help bootstrap testing and validate its new +// runtime.Type handling of F[A].T[B]. +// +// This isn't perfect, but it smoked out a handful of issues in +// gotypes2 and unified IR. + +package main + +import ( + "fmt" + "reflect" +) + +type test struct { + TArgs [2]reflect.Type + Instance reflect.Type +} + +var tests []test + +type intish interface{ ~int } + +type Int int +type GlobalInt = Int // allow access to global Int, even when shadowed + +func F[A intish]() { + add := func(B, T interface{}) { + tests = append(tests, test{ + TArgs: [2]reflect.Type{ + reflect.TypeOf(A(0)), + reflect.TypeOf(B), + }, + Instance: reflect.TypeOf(T), + }) + } + + type Int int + + type T[B intish] struct{} + + add(int(0), T[int]{}) + add(Int(0), T[Int]{}) + add(GlobalInt(0), T[GlobalInt]{}) + add(A(0), T[A]{}) // NOTE: intentionally dups with int and GlobalInt + + type U[_ any] int + type V U[int] + type W V + + add(U[int](0), T[U[int]]{}) + add(U[Int](0), T[U[Int]]{}) + add(U[GlobalInt](0), T[U[GlobalInt]]{}) + add(U[A](0), T[U[A]]{}) // NOTE: intentionally dups with U[int] and U[GlobalInt] + add(V(0), T[V]{}) + add(W(0), T[W]{}) +} + +func main() { + type Int int + + F[int]() + F[Int]() + F[GlobalInt]() + + type U[_ any] int + type V U[int] + type W V + + F[U[int]]() + F[U[Int]]() + F[U[GlobalInt]]() + F[V]() + F[W]() + + type X[A any] U[X[A]] + + F[X[int]]() + F[X[Int]]() + F[X[GlobalInt]]() + + for j, tj := range tests { + for i, ti := range tests[:j+1] { + if (ti.TArgs == tj.TArgs) != (ti.Instance == tj.Instance) { + fmt.Printf("FAIL: %d,%d: %s, but %s\n", i, j, eq(ti.TArgs, tj.TArgs), eq(ti.Instance, tj.Instance)) + } + + // The test is constructed so we should see a few identical types. + // See "NOTE" comments above. + if i != j && ti.Instance == tj.Instance { + fmt.Printf("%d,%d: %v\n", i, j, ti.Instance) + } + } + } +} + +func eq(a, b interface{}) string { + op := "==" + if a != b { + op = "!=" + } + return fmt.Sprintf("%v %s %v", a, op, b) +} diff --git a/test/typeparam/nested.out b/test/typeparam/nested.out new file mode 100644 index 0000000..0836d9b --- /dev/null +++ b/test/typeparam/nested.out @@ -0,0 +1,4 @@ +0,3: main.T[int;int] +4,7: main.T[int;main.U[int;int]·3] +22,23: main.T[main.Int;main.Int] +26,27: main.T[main.Int;main.U[main.Int;main.Int]·3] diff --git a/test/typeparam/ordered.go b/test/typeparam/ordered.go new file mode 100644 index 0000000..d304298 --- /dev/null +++ b/test/typeparam/ordered.go @@ -0,0 +1,95 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "math" + "sort" +) + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +type orderedSlice[Elem Ordered] []Elem + +func (s orderedSlice[Elem]) Len() int { return len(s) } +func (s orderedSlice[Elem]) Less(i, j int) bool { + if s[i] < s[j] { + return true + } + isNaN := func(f Elem) bool { return f != f } + if isNaN(s[i]) && !isNaN(s[j]) { + return true + } + return false +} +func (s orderedSlice[Elem]) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func _OrderedSlice[Elem Ordered](s []Elem) { + sort.Sort(orderedSlice[Elem](s)) +} + +var ints = []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} +var float64s = []float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8} +var strings = []string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} + +func TestSortOrderedInts() bool { + return testOrdered("ints", ints, sort.Ints) +} + +func TestSortOrderedFloat64s() bool { + return testOrdered("float64s", float64s, sort.Float64s) +} + +func TestSortOrderedStrings() bool { + return testOrdered("strings", strings, sort.Strings) +} + +func testOrdered[Elem Ordered](name string, s []Elem, sorter func([]Elem)) bool { + s1 := make([]Elem, len(s)) + copy(s1, s) + s2 := make([]Elem, len(s)) + copy(s2, s) + _OrderedSlice(s1) + sorter(s2) + ok := true + if !sliceEq(s1, s2) { + fmt.Printf("%s: got %v, want %v", name, s1, s2) + ok = false + } + for i := len(s1) - 1; i > 0; i-- { + if s1[i] < s1[i-1] { + fmt.Printf("%s: element %d (%v) < element %d (%v)", name, i, s1[i], i-1, s1[i-1]) + ok = false + } + } + return ok +} + +func sliceEq[Elem Ordered](s1, s2 []Elem) bool { + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +func main() { + if !TestSortOrderedInts() || !TestSortOrderedFloat64s() || !TestSortOrderedStrings() { + panic("failure") + } +} diff --git a/test/typeparam/orderedmap.go b/test/typeparam/orderedmap.go new file mode 100644 index 0000000..1245669 --- /dev/null +++ b/test/typeparam/orderedmap.go @@ -0,0 +1,286 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package orderedmap provides an ordered map, implemented as a binary tree. +package main + +import ( + "bytes" + "context" + "fmt" + "runtime" +) + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +// _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. It takes a comparison function that compares two +// keys and returns < 0 if the first is less, == 0 if they are equal, +// > 0 if the first is greater. +func _New[K, V any](compare func(K, K) int) *_Map[K, V] { + return &_Map[K, V]{compare: compare} +} + +// _NewOrdered returns a new map whose key is an ordered type. +// This is like _New, but does not require providing a compare function. +// The map compare function uses the obvious key ordering. +func _NewOrdered[K Ordered, V any]() *_Map[K, V] { + return _New[K, V](func(k1, k2 K) int { + switch { + case k1 < k2: + return -1 + case k1 == k2: + return 0 + default: + return 1 + } + }) +} + +// find looks up key in the map, returning either a pointer to the slot of the +// node holding key, or a pointer to the slot where should 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. +// Reports whether this is a new key. +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 the zero value +// 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 + return zero, false + } + return (*pn).val, true +} + +// keyValue is a pair of key and value used while iterating. +type keyValue[K, V any] struct { + key K + val V +} + +// iterate returns an iterator that traverses the map. +func (m *_Map[K, V]) Iterate() *_Iterator[K, V] { + sender, receiver := _Ranger[keyValue[K, V]]() + var f func(*node[K, V]) bool + f = func(n *node[K, V]) bool { + if n == nil { + return true + } + // Stop the traversal if Send fails, which means that + // nothing is listening to the receiver. + return f(n.left) && + sender.Send(context.Background(), 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 *_Receiver[keyValue[K, V]] +} + +// Next returns the next key and value pair, and a boolean that reports +// whether they are valid. If not valid, we have reached the end of the map. +func (it *_Iterator[K, V]) Next() (K, V, bool) { + keyval, ok := it.r.Next(context.Background()) + if !ok { + var zerok K + var zerov V + return zerok, zerov, false + } + return keyval.key, keyval.val, true +} + +func TestMap() { + m := _New[[]byte, int](bytes.Compare) + + if _, found := m.Find([]byte("a")); found { + panic(fmt.Sprintf("unexpectedly found %q in empty map", []byte("a"))) + } + if !m.Insert([]byte("a"), 'a') { + panic(fmt.Sprintf("key %q unexpectedly already present", []byte("a"))) + } + if !m.Insert([]byte("c"), 'c') { + panic(fmt.Sprintf("key %q unexpectedly already present", []byte("c"))) + } + if !m.Insert([]byte("b"), 'b') { + panic(fmt.Sprintf("key %q unexpectedly already present", []byte("b"))) + } + if m.Insert([]byte("c"), 'x') { + panic(fmt.Sprintf("key %q unexpectedly not present", []byte("c"))) + } + + if v, found := m.Find([]byte("a")); !found { + panic(fmt.Sprintf("did not find %q", []byte("a"))) + } else if v != 'a' { + panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("a"), v, 'a')) + } + if v, found := m.Find([]byte("c")); !found { + panic(fmt.Sprintf("did not find %q", []byte("c"))) + } else if v != 'x' { + panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("c"), v, 'x')) + } + + if _, found := m.Find([]byte("d")); found { + panic(fmt.Sprintf("unexpectedly found %q", []byte("d"))) + } + + gather := func(it *_Iterator[[]byte, int]) []int { + var r []int + for { + _, v, ok := it.Next() + if !ok { + return r + } + r = append(r, v) + } + } + got := gather(m.Iterate()) + want := []int{'a', 'b', 'x'} + if !_SliceEqual(got, want) { + panic(fmt.Sprintf("Iterate returned %v, want %v", got, want)) + } +} + +func main() { + TestMap() +} + +// _Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func _SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// 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[Elem any]() (*_Sender[Elem], *_Receiver[Elem]) { + c := make(chan Elem) + d := make(chan struct{}) + s := &_Sender[Elem]{ + values: c, + done: d, + } + r := &_Receiver[Elem]{ + values: c, + done: d, + } + runtime.SetFinalizer(r, (*_Receiver[Elem]).finalize) + return s, r +} + +// A _Sender is used to send values to a Receiver. +type _Sender[Elem any] struct { + values chan<- Elem + done <-chan struct{} +} + +// Send sends a value to the receiver. It reports whether the value was sent. +// The value will not be sent if the context is closed or the receiver +// is freed. +func (s *_Sender[Elem]) Send(ctx context.Context, v Elem) bool { + select { + case <-ctx.Done(): + return false + 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[Elem]) Close() { + close(s.values) +} + +// A _Receiver receives values from a _Sender. +type _Receiver[Elem any] struct { + values <-chan Elem + done chan<- struct{} +} + +// Next returns the next value from the channel. The bool result indicates +// whether the value is valid. +func (r *_Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) { + select { + case <-ctx.Done(): + case v, ok = <-r.values: + } + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *_Receiver[Elem]) finalize() { + close(r.done) +} diff --git a/test/typeparam/orderedmapsimp.dir/a.go b/test/typeparam/orderedmapsimp.dir/a.go new file mode 100644 index 0000000..d6a2de5 --- /dev/null +++ b/test/typeparam/orderedmapsimp.dir/a.go @@ -0,0 +1,226 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import ( + "context" + "runtime" +) + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +// 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. It takes a comparison function that compares two +// keys and returns < 0 if the first is less, == 0 if they are equal, +// > 0 if the first is greater. +func New[K, V any](compare func(K, K) int) *Map[K, V] { + return &Map[K, V]{compare: compare} +} + +// NewOrdered returns a new map whose key is an ordered type. +// This is like New, but does not require providing a compare function. +// The map compare function uses the obvious key ordering. +func NewOrdered[K Ordered, V any]() *Map[K, V] { + return New[K, V](func(k1, k2 K) int { + switch { + case k1 < k2: + return -1 + case k1 > k2: + return 1 + default: + return 0 + } + }) +} + +// find looks up key in the map, returning either a pointer to the slot of the +// node holding key, or a pointer to the slot where 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. +// Reports whether this is a new key. +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 the zero value +// if not present. The second 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 + return zero, false + } + return (*pn).val, true +} + +// keyValue is a pair of key and value used while iterating. +type keyValue[K, V any] struct { + key K + val V +} + +// iterate returns an iterator that traverses the map. +func (m *Map[K, V]) Iterate() *Iterator[K, V] { + sender, receiver := Ranger[keyValue[K, V]]() + var f func(*node[K, V]) bool + f = func(n *node[K, V]) bool { + if n == nil { + return true + } + // Stop the traversal if Send fails, which means that + // nothing is listening to the receiver. + return f(n.left) && + sender.Send(context.Background(), 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 *Receiver[keyValue[K, V]] +} + +// Next returns the next key and value pair, and a boolean that reports +// whether they are valid. If not valid, we have reached the end of the map. +func (it *Iterator[K, V]) Next() (K, V, bool) { + keyval, ok := it.r.Next(context.Background()) + if !ok { + var zerok K + var zerov V + return zerok, zerov, false + } + return keyval.key, keyval.val, true +} + +// Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// 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[Elem any]() (*Sender[Elem], *Receiver[Elem]) { + c := make(chan Elem) + d := make(chan struct{}) + s := &Sender[Elem]{ + values: c, + done: d, + } + r := &Receiver[Elem]{ + values: c, + done: d, + } + runtime.SetFinalizer(r, (*Receiver[Elem]).finalize) + return s, r +} + +// A Sender is used to send values to a Receiver. +type Sender[Elem any] struct { + values chan<- Elem + done <-chan struct{} +} + +// Send sends a value to the receiver. It reports whether the value was sent. +// The value will not be sent if the context is closed or the receiver +// is freed. +func (s *Sender[Elem]) Send(ctx context.Context, v Elem) bool { + select { + case <-ctx.Done(): + return false + 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[Elem]) Close() { + close(s.values) +} + +// A Receiver receives values from a Sender. +type Receiver[Elem any] struct { + values <-chan Elem + done chan<- struct{} +} + +// Next returns the next value from the channel. The bool result indicates +// whether the value is valid. +func (r *Receiver[Elem]) Next(ctx context.Context) (v Elem, ok bool) { + select { + case <-ctx.Done(): + case v, ok = <-r.values: + } + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *Receiver[Elem]) finalize() { + close(r.done) +} diff --git a/test/typeparam/orderedmapsimp.dir/main.go b/test/typeparam/orderedmapsimp.dir/main.go new file mode 100644 index 0000000..7758a75 --- /dev/null +++ b/test/typeparam/orderedmapsimp.dir/main.go @@ -0,0 +1,64 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "bytes" + "fmt" +) + +func TestMap() { + m := a.New[[]byte, int](bytes.Compare) + + if _, found := m.Find([]byte("a")); found { + panic(fmt.Sprintf("unexpectedly found %q in empty map", []byte("a"))) + } + + for _, c := range []int{'a', 'c', 'b'} { + if !m.Insert([]byte(string(c)), c) { + panic(fmt.Sprintf("key %q unexpectedly already present", []byte(string(c)))) + } + } + if m.Insert([]byte("c"), 'x') { + panic(fmt.Sprintf("key %q unexpectedly not present", []byte("c"))) + } + + if v, found := m.Find([]byte("a")); !found { + panic(fmt.Sprintf("did not find %q", []byte("a"))) + } else if v != 'a' { + panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("a"), v, 'a')) + } + if v, found := m.Find([]byte("c")); !found { + panic(fmt.Sprintf("did not find %q", []byte("c"))) + } else if v != 'x' { + panic(fmt.Sprintf("key %q returned wrong value %c, expected %c", []byte("c"), v, 'x')) + } + + if _, found := m.Find([]byte("d")); found { + panic(fmt.Sprintf("unexpectedly found %q", []byte("d"))) + } + + gather := func(it *a.Iterator[[]byte, int]) []int { + var r []int + for { + _, v, ok := it.Next() + if !ok { + return r + } + r = append(r, v) + } + } + got := gather(m.Iterate()) + want := []int{'a', 'b', 'x'} + if !a.SliceEqual(got, want) { + panic(fmt.Sprintf("Iterate returned %v, want %v", got, want)) + } + +} + +func main() { + TestMap() +} diff --git a/test/typeparam/orderedmapsimp.go b/test/typeparam/orderedmapsimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/orderedmapsimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/pair.go b/test/typeparam/pair.go new file mode 100644 index 0000000..dd0adb1 --- /dev/null +++ b/test/typeparam/pair.go @@ -0,0 +1,36 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "unsafe" +) + +type pair[F1, F2 any] struct { + f1 F1 + f2 F2 +} + +func main() { + p := pair[int32, int64]{1, 2} + if got, want := unsafe.Sizeof(p.f1), uintptr(4); got != want { + panic(fmt.Sprintf("unexpected f1 size == %d, want %d", got, want)) + } + if got, want := unsafe.Sizeof(p.f2), uintptr(8); got != want { + panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want)) + } + + type mypair struct { + f1 int32 + f2 int64 + } + mp := mypair(p) + if mp.f1 != 1 || mp.f2 != 2 { + panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2})) + } +} diff --git a/test/typeparam/pairimp.dir/a.go b/test/typeparam/pairimp.dir/a.go new file mode 100644 index 0000000..a984fba --- /dev/null +++ b/test/typeparam/pairimp.dir/a.go @@ -0,0 +1,10 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Pair[F1, F2 any] struct { + Field1 F1 + Field2 F2 +} diff --git a/test/typeparam/pairimp.dir/main.go b/test/typeparam/pairimp.dir/main.go new file mode 100644 index 0000000..f76da43 --- /dev/null +++ b/test/typeparam/pairimp.dir/main.go @@ -0,0 +1,30 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" + "unsafe" +) + +func main() { + p := a.Pair[int32, int64]{1, 2} + if got, want := unsafe.Sizeof(p.Field1), uintptr(4); got != want { + panic(fmt.Sprintf("unexpected f1 size == %d, want %d", got, want)) + } + if got, want := unsafe.Sizeof(p.Field2), uintptr(8); got != want { + panic(fmt.Sprintf("unexpected f2 size == %d, want %d", got, want)) + } + + type mypair struct { + Field1 int32 + Field2 int64 + } + mp := mypair(p) + if mp.Field1 != 1 || mp.Field2 != 2 { + panic(fmt.Sprintf("mp == %#v, want %#v", mp, mypair{1, 2})) + } +} diff --git a/test/typeparam/pairimp.go b/test/typeparam/pairimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/pairimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/pragma.go b/test/typeparam/pragma.go new file mode 100644 index 0000000..59411ab --- /dev/null +++ b/test/typeparam/pragma.go @@ -0,0 +1,19 @@ +// errorcheck -0 -m + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Make sure the go:noinline pragma makes it from a +// generic function to any of its stenciled instances. + +package main + +//go:noinline +func f[T any](x T) T { + return x +} + +func main() { // ERROR "can inline main" + println(f(5)) +} diff --git a/test/typeparam/recoverimp.dir/a.go b/test/typeparam/recoverimp.dir/a.go new file mode 100644 index 0000000..a465fd1 --- /dev/null +++ b/test/typeparam/recoverimp.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import "fmt" + +func F[T any](a T) { + defer func() { + if x := recover(); x != nil { + fmt.Printf("panic: %v\n", x) + } + }() + panic(a) +} diff --git a/test/typeparam/recoverimp.dir/main.go b/test/typeparam/recoverimp.dir/main.go new file mode 100644 index 0000000..d8cfa38 --- /dev/null +++ b/test/typeparam/recoverimp.dir/main.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + a.F(5.3) + a.F("hello") +} diff --git a/test/typeparam/recoverimp.go b/test/typeparam/recoverimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/recoverimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/recoverimp.out b/test/typeparam/recoverimp.out new file mode 100644 index 0000000..3c8b38c --- /dev/null +++ b/test/typeparam/recoverimp.out @@ -0,0 +1,2 @@ +panic: 5.3 +panic: hello diff --git a/test/typeparam/select.dir/a.go b/test/typeparam/select.dir/a.go new file mode 100644 index 0000000..983e4b1 --- /dev/null +++ b/test/typeparam/select.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F[T any](c, d chan T) T { + select { + case x := <- c: + return x + case x := <- d: + return x + } +} + diff --git a/test/typeparam/select.dir/main.go b/test/typeparam/select.dir/main.go new file mode 100644 index 0000000..6ea3fe2 --- /dev/null +++ b/test/typeparam/select.dir/main.go @@ -0,0 +1,28 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "sort" + + "./a" +) + +func main() { + c := make(chan int, 1) + d := make(chan int, 1) + + c <- 5 + d <- 6 + + var r [2]int + r[0] = a.F(c, d) + r[1] = a.F(c, d) + sort.Ints(r[:]) + + if r != [2]int{5, 6} { + panic("incorrect results") + } +} diff --git a/test/typeparam/select.go b/test/typeparam/select.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/select.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/sets.go b/test/typeparam/sets.go new file mode 100644 index 0000000..bd08ad7 --- /dev/null +++ b/test/typeparam/sets.go @@ -0,0 +1,280 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "sort" +) + +// _Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func _SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// A _Set is a set of elements of some type. +type _Set[Elem comparable] struct { + m map[Elem]struct{} +} + +// _Make makes a new set. +func _Make[Elem comparable]() _Set[Elem] { + return _Set[Elem]{m: make(map[Elem]struct{})} +} + +// Add adds an element to a set. +func (s _Set[Elem]) Add(v Elem) { + s.m[v] = struct{}{} +} + +// Delete removes an element from a set. If the element is not present +// in the set, this does nothing. +func (s _Set[Elem]) Delete(v Elem) { + delete(s.m, v) +} + +// Contains reports whether v is in the set. +func (s _Set[Elem]) Contains(v Elem) bool { + _, ok := s.m[v] + return ok +} + +// Len returns the number of elements in the set. +func (s _Set[Elem]) Len() int { + return len(s.m) +} + +// Values returns the values in the set. +// The values will be in an indeterminate order. +func (s _Set[Elem]) Values() []Elem { + r := make([]Elem, 0, len(s.m)) + for v := range s.m { + r = append(r, v) + } + return r +} + +// _Equal reports whether two sets contain the same elements. +func _Equal[Elem comparable](s1, s2 _Set[Elem]) bool { + if len(s1.m) != len(s2.m) { + return false + } + for v1 := range s1.m { + if !s2.Contains(v1) { + return false + } + } + return true +} + +// Copy returns a copy of s. +func (s _Set[Elem]) Copy() _Set[Elem] { + r := _Set[Elem]{m: make(map[Elem]struct{}, len(s.m))} + for v := range s.m { + r.m[v] = struct{}{} + } + return r +} + +// AddSet adds all the elements of s2 to s. +func (s _Set[Elem]) AddSet(s2 _Set[Elem]) { + for v := range s2.m { + s.m[v] = struct{}{} + } +} + +// SubSet removes all elements in s2 from s. +// Values in s2 that are not in s are ignored. +func (s _Set[Elem]) SubSet(s2 _Set[Elem]) { + for v := range s2.m { + delete(s.m, v) + } +} + +// Intersect removes all elements from s that are not present in s2. +// Values in s2 that are not in s are ignored. +func (s _Set[Elem]) Intersect(s2 _Set[Elem]) { + for v := range s.m { + if !s2.Contains(v) { + delete(s.m, v) + } + } +} + +// Iterate calls f on every element in the set. +func (s _Set[Elem]) Iterate(f func(Elem)) { + for v := range s.m { + f(v) + } +} + +// Filter deletes any elements from s for which f returns false. +func (s _Set[Elem]) Filter(f func(Elem) bool) { + for v := range s.m { + if !f(v) { + delete(s.m, v) + } + } +} + +func TestSet() { + s1 := _Make[int]() + if got := s1.Len(); got != 0 { + panic(fmt.Sprintf("Len of empty set = %d, want 0", got)) + } + s1.Add(1) + s1.Add(1) + s1.Add(1) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + s1.Add(2) + s1.Add(3) + s1.Add(4) + if got := s1.Len(); got != 4 { + panic(fmt.Sprintf("(%v).Len() == %d, want 4", s1, got)) + } + if !s1.Contains(1) { + panic(fmt.Sprintf("(%v).Contains(1) == false, want true", s1)) + } + if s1.Contains(5) { + panic(fmt.Sprintf("(%v).Contains(5) == true, want false", s1)) + } + vals := s1.Values() + sort.Ints(vals) + w1 := []int{1, 2, 3, 4} + if !_SliceEqual(vals, w1) { + panic(fmt.Sprintf("(%v).Values() == %v, want %v", s1, vals, w1)) + } +} + +func TestEqual() { + s1 := _Make[string]() + s2 := _Make[string]() + if !_Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2)) + } + s1.Add("hello") + s1.Add("world") + if got := s1.Len(); got != 2 { + panic(fmt.Sprintf("(%v).Len() == %d, want 2", s1, got)) + } + if _Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2)) + } +} + +func TestCopy() { + s1 := _Make[float64]() + s1.Add(0) + s2 := s1.Copy() + if !_Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2)) + } + s1.Add(1) + if _Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2)) + } +} + +func TestAddSet() { + s1 := _Make[int]() + s1.Add(1) + s1.Add(2) + s2 := _Make[int]() + s2.Add(2) + s2.Add(3) + s1.AddSet(s2) + if got := s1.Len(); got != 3 { + panic(fmt.Sprintf("(%v).Len() == %d, want 3", s1, got)) + } + s2.Add(1) + if !_Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2)) + } +} + +func TestSubSet() { + s1 := _Make[int]() + s1.Add(1) + s1.Add(2) + s2 := _Make[int]() + s2.Add(2) + s2.Add(3) + s1.SubSet(s2) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + if vals, want := s1.Values(), []int{1}; !_SliceEqual(vals, want) { + panic(fmt.Sprintf("after SubSet got %v, want %v", vals, want)) + } +} + +func TestIntersect() { + s1 := _Make[int]() + s1.Add(1) + s1.Add(2) + s2 := _Make[int]() + s2.Add(2) + s2.Add(3) + s1.Intersect(s2) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + if vals, want := s1.Values(), []int{2}; !_SliceEqual(vals, want) { + panic(fmt.Sprintf("after Intersect got %v, want %v", vals, want)) + } +} + +func TestIterate() { + s1 := _Make[int]() + s1.Add(1) + s1.Add(2) + s1.Add(3) + s1.Add(4) + tot := 0 + s1.Iterate(func(i int) { tot += i }) + if tot != 10 { + panic(fmt.Sprintf("total of %v == %d, want 10", s1, tot)) + } +} + +func TestFilter() { + s1 := _Make[int]() + s1.Add(1) + s1.Add(2) + s1.Add(3) + s1.Filter(func(v int) bool { return v%2 == 0 }) + if vals, want := s1.Values(), []int{2}; !_SliceEqual(vals, want) { + panic(fmt.Sprintf("after Filter got %v, want %v", vals, want)) + } + +} + +func main() { + TestSet() + TestEqual() + TestCopy() + TestAddSet() + TestSubSet() + TestIntersect() + TestIterate() + TestFilter() +} diff --git a/test/typeparam/setsimp.dir/a.go b/test/typeparam/setsimp.dir/a.go new file mode 100644 index 0000000..92449ce --- /dev/null +++ b/test/typeparam/setsimp.dir/a.go @@ -0,0 +1,128 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +// SliceEqual reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func SliceEqual[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// A Set is a set of elements of some type. +type Set[Elem comparable] struct { + m map[Elem]struct{} +} + +// Make makes a new set. +func Make[Elem comparable]() Set[Elem] { + return Set[Elem]{m: make(map[Elem]struct{})} +} + +// Add adds an element to a set. +func (s Set[Elem]) Add(v Elem) { + s.m[v] = struct{}{} +} + +// Delete removes an element from a set. If the element is not present +// in the set, this does nothing. +func (s Set[Elem]) Delete(v Elem) { + delete(s.m, v) +} + +// Contains reports whether v is in the set. +func (s Set[Elem]) Contains(v Elem) bool { + _, ok := s.m[v] + return ok +} + +// Len returns the number of elements in the set. +func (s Set[Elem]) Len() int { + return len(s.m) +} + +// Values returns the values in the set. +// The values will be in an indeterminate order. +func (s Set[Elem]) Values() []Elem { + r := make([]Elem, 0, len(s.m)) + for v := range s.m { + r = append(r, v) + } + return r +} + +// Equal reports whether two sets contain the same elements. +func Equal[Elem comparable](s1, s2 Set[Elem]) bool { + if len(s1.m) != len(s2.m) { + return false + } + for v1 := range s1.m { + if !s2.Contains(v1) { + return false + } + } + return true +} + +// Copy returns a copy of s. +func (s Set[Elem]) Copy() Set[Elem] { + r := Set[Elem]{m: make(map[Elem]struct{}, len(s.m))} + for v := range s.m { + r.m[v] = struct{}{} + } + return r +} + +// AddSet adds all the elements of s2 to s. +func (s Set[Elem]) AddSet(s2 Set[Elem]) { + for v := range s2.m { + s.m[v] = struct{}{} + } +} + +// SubSet removes all elements in s2 from s. +// Values in s2 that are not in s are ignored. +func (s Set[Elem]) SubSet(s2 Set[Elem]) { + for v := range s2.m { + delete(s.m, v) + } +} + +// Intersect removes all elements from s that are not present in s2. +// Values in s2 that are not in s are ignored. +func (s Set[Elem]) Intersect(s2 Set[Elem]) { + for v := range s.m { + if !s2.Contains(v) { + delete(s.m, v) + } + } +} + +// Iterate calls f on every element in the set. +func (s Set[Elem]) Iterate(f func(Elem)) { + for v := range s.m { + f(v) + } +} + +// Filter deletes any elements from s for which f returns false. +func (s Set[Elem]) Filter(f func(Elem) bool) { + for v := range s.m { + if !f(v) { + delete(s.m, v) + } + } +} diff --git a/test/typeparam/setsimp.dir/main.go b/test/typeparam/setsimp.dir/main.go new file mode 100644 index 0000000..e1ec86a --- /dev/null +++ b/test/typeparam/setsimp.dir/main.go @@ -0,0 +1,156 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" + "sort" +) + +func TestSet() { + s1 := a.Make[int]() + if got := s1.Len(); got != 0 { + panic(fmt.Sprintf("Len of empty set = %d, want 0", got)) + } + s1.Add(1) + s1.Add(1) + s1.Add(1) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + s1.Add(2) + s1.Add(3) + s1.Add(4) + if got := s1.Len(); got != 4 { + panic(fmt.Sprintf("(%v).Len() == %d, want 4", s1, got)) + } + if !s1.Contains(1) { + panic(fmt.Sprintf("(%v).Contains(1) == false, want true", s1)) + } + if s1.Contains(5) { + panic(fmt.Sprintf("(%v).Contains(5) == true, want false", s1)) + } + vals := s1.Values() + sort.Ints(vals) + w1 := []int{1, 2, 3, 4} + if !a.SliceEqual(vals, w1) { + panic(fmt.Sprintf("(%v).Values() == %v, want %v", s1, vals, w1)) + } +} + +func TestEqual() { + s1 := a.Make[string]() + s2 := a.Make[string]() + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } + s1.Add("hello") + s1.Add("world") + if got := s1.Len(); got != 2 { + panic(fmt.Sprintf("(%v).Len() == %d, want 2", s1, got)) + } + if a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) + } +} + +func TestCopy() { + s1 := a.Make[float64]() + s1.Add(0) + s2 := s1.Copy() + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } + s1.Add(1) + if a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) + } +} + +func TestAddSet() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s2 := a.Make[int]() + s2.Add(2) + s2.Add(3) + s1.AddSet(s2) + if got := s1.Len(); got != 3 { + panic(fmt.Sprintf("(%v).Len() == %d, want 3", s1, got)) + } + s2.Add(1) + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } +} + +func TestSubSet() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s2 := a.Make[int]() + s2.Add(2) + s2.Add(3) + s1.SubSet(s2) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + if vals, want := s1.Values(), []int{1}; !a.SliceEqual(vals, want) { + panic(fmt.Sprintf("after SubSet got %v, want %v", vals, want)) + } +} + +func TestIntersect() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s2 := a.Make[int]() + s2.Add(2) + s2.Add(3) + s1.Intersect(s2) + if got := s1.Len(); got != 1 { + panic(fmt.Sprintf("(%v).Len() == %d, want 1", s1, got)) + } + if vals, want := s1.Values(), []int{2}; !a.SliceEqual(vals, want) { + panic(fmt.Sprintf("after Intersect got %v, want %v", vals, want)) + } +} + +func TestIterate() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s1.Add(3) + s1.Add(4) + tot := 0 + s1.Iterate(func(i int) { tot += i }) + if tot != 10 { + panic(fmt.Sprintf("total of %v == %d, want 10", s1, tot)) + } +} + +func TestFilter() { + s1 := a.Make[int]() + s1.Add(1) + s1.Add(2) + s1.Add(3) + s1.Filter(func(v int) bool { return v%2 == 0 }) + if vals, want := s1.Values(), []int{2}; !a.SliceEqual(vals, want) { + panic(fmt.Sprintf("after Filter got %v, want %v", vals, want)) + } + +} + +func main() { + TestSet() + TestEqual() + TestCopy() + TestAddSet() + TestSubSet() + TestIntersect() + TestIterate() + TestFilter() +} diff --git a/test/typeparam/setsimp.go b/test/typeparam/setsimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/setsimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go new file mode 100644 index 0000000..56cf367 --- /dev/null +++ b/test/typeparam/settable.go @@ -0,0 +1,123 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "strconv" +) + +// Various implementations of fromStrings(). + +type Setter[B any] interface { + Set(string) + *B +} + +// Takes two type parameters where PT = *T +func fromStrings1[T any, 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 + // of Setter, so we can convert it to PT. + p := PT(&result[i]) + // PT has a Set method. + p.Set(v) + } + return result +} + +func fromStrings1a[T any, PT Setter[T]](s []string) []PT { + result := make([]PT, len(s)) + for i, v := range s { + // The type new(T) is *T which is in the type list + // of Setter, so we can convert it to PT. + result[i] = PT(new(T)) + p := result[i] + // PT has a Set method. + p.Set(v) + } + return result +} + +// Takes one type parameter and a set function +func fromStrings2[T any](s []string, set func(*T, string)) []T { + results := make([]T, len(s)) + for i, v := range s { + set(&results[i], v) + } + return results +} + +type Setter2 interface { + Set(string) +} + +// Takes only one type parameter, but causes a panic (see below) +func fromStrings3[T Setter2](s []string) []T { + results := make([]T, len(s)) + for i, v := range s { + // Panics if T is a pointer type because receiver is T(nil). + results[i].Set(v) + } + return results +} + +// Two concrete types with the appropriate Set method. + +type SettableInt int + +func (p *SettableInt) Set(s string) { + i, err := strconv.Atoi(s) + if err != nil { + panic(err) + } + *p = SettableInt(i) +} + +type SettableString struct { + s string +} + +func (x *SettableString) Set(s string) { + x.s = s +} + +func main() { + s := fromStrings1[SettableInt, *SettableInt]([]string{"1"}) + if len(s) != 1 || s[0] != 1 { + panic(fmt.Sprintf("got %v, want %v", s, []int{1})) + } + + s2 := fromStrings1a[SettableInt, *SettableInt]([]string{"1"}) + if len(s2) != 1 || *s2[0] != 1 { + x := 1 + panic(fmt.Sprintf("got %v, want %v", s2, []*int{&x})) + } + + // Test out constraint type inference, which should determine that the second + // type param is *SettableString. + ps := fromStrings1[SettableString]([]string{"x", "y"}) + if len(ps) != 2 || ps[0] != (SettableString{"x"}) || ps[1] != (SettableString{"y"}) { + panic(s) + } + + s = fromStrings2([]string{"1"}, func(p *SettableInt, s string) { p.Set(s) }) + if len(s) != 1 || s[0] != 1 { + panic(fmt.Sprintf("got %v, want %v", s, []int{1})) + } + + defer func() { + if recover() == nil { + panic("did not panic as expected") + } + }() + // This should type check but should panic at run time, + // because it will make a slice of *SettableInt and then call + // Set on a nil value. + fromStrings3[*SettableInt]([]string{"1"}) +} diff --git a/test/typeparam/shape1.go b/test/typeparam/shape1.go new file mode 100644 index 0000000..2400f1c --- /dev/null +++ b/test/typeparam/shape1.go @@ -0,0 +1,50 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I interface { + foo() int +} + +// There should be one instantiation of f for both squarer and doubler. +// Similarly, there should be one instantiation of f for both *incrementer and *decrementer. +func f[T I](x T) int { + return x.foo() +} + +type squarer int + +func (x squarer) foo() int { + return int(x*x) +} + +type doubler int + +func (x doubler) foo() int { + return int(2*x) +} + +type incrementer int16 + +func (x *incrementer) foo() int { + return int(*x+1) +} + +type decrementer int32 + +func (x *decrementer) foo() int{ + return int(*x-1) +} + +func main() { + println(f(squarer(5))) + println(f(doubler(5))) + var i incrementer = 5 + println(f(&i)) + var d decrementer = 5 + println(f(&d)) +} diff --git a/test/typeparam/shape1.out b/test/typeparam/shape1.out new file mode 100644 index 0000000..da9a12d --- /dev/null +++ b/test/typeparam/shape1.out @@ -0,0 +1,4 @@ +25 +10 +6 +4 diff --git a/test/typeparam/sliceimp.dir/a.go b/test/typeparam/sliceimp.dir/a.go new file mode 100644 index 0000000..dbcfae8 --- /dev/null +++ b/test/typeparam/sliceimp.dir/a.go @@ -0,0 +1,141 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +// Max returns the maximum of two values of some ordered type. +func Max[T Ordered](a, b T) T { + if a > b { + return a + } + return b +} + +// Min returns the minimum of two values of some ordered type. +func Min[T Ordered](a, b T) T { + if a < b { + return a + } + return b +} + +// Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func Equal[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// EqualFn reports whether two slices are equal using a comparison +// function on each element. +func EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if !eq(v1, v2) { + return false + } + } + return true +} + +// Map turns a []Elem1 to a []Elem2 using a mapping function. +func Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 { + r := make([]Elem2, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} + +// Reduce reduces a []Elem1 to a single value of type Elem2 using +// a reduction function. +func Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 { + r := initializer + for _, v := range s { + r = f(r, v) + } + return r +} + +// Filter filters values from a slice using a filter function. +func Filter[Elem any](s []Elem, f func(Elem) bool) []Elem { + var r []Elem + for _, v := range s { + if f(v) { + r = append(r, v) + } + } + return r +} + +// Max returns the maximum element in a slice of some ordered type. +// If the slice is empty it returns the zero value of the element type. +func SliceMax[Elem Ordered](s []Elem) Elem { + if len(s) == 0 { + var zero Elem + return zero + } + return Reduce(s[1:], s[0], Max[Elem]) +} + +// Min returns the minimum element in a slice of some ordered type. +// If the slice is empty it returns the zero value of the element type. +func SliceMin[Elem Ordered](s []Elem) Elem { + if len(s) == 0 { + var zero Elem + return zero + } + return Reduce(s[1:], s[0], Min[Elem]) +} + +// Append adds values to the end of a slice, returning a new slice. +// This is like the predeclared append function; it's an example +// of how to write it using generics. We used to write code like +// this before append was added to the language, but we had to write +// a separate copy for each type. +func Append[T any](s []T, t ...T) []T { + lens := len(s) + tot := lens + len(t) + if tot <= cap(s) { + s = s[:tot] + } else { + news := make([]T, tot, tot+tot/2) + Copy(news, s) + s = news + } + Copy(s[lens:tot], t) + return s +} + +// Copy copies values from t to s, stopping when either slice is full, +// returning the number of values copied. This is like the predeclared +// copy function; it's an example of how to write it using generics. +func Copy[T any](s, t []T) int { + i := 0 + for ; i < len(s) && i < len(t); i++ { + s[i] = t[i] + } + return i +} diff --git a/test/typeparam/sliceimp.dir/main.go b/test/typeparam/sliceimp.dir/main.go new file mode 100644 index 0000000..ec13188 --- /dev/null +++ b/test/typeparam/sliceimp.dir/main.go @@ -0,0 +1,179 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" + "math" + "strings" +) + +type Integer interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +func TestEqual() { + s1 := []int{1, 2, 3} + if !a.Equal(s1, s1) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s1)) + } + s2 := []int{1, 2, 3} + if !a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s1, s2)) + } + s2 = append(s2, 4) + if a.Equal(s1, s2) { + panic(fmt.Sprintf("a.Equal(%v, %v) = true, want false", s1, s2)) + } + + s3 := []float64{1, 2, math.NaN()} + if !a.Equal(s3, s3) { + panic(fmt.Sprintf("a.Equal(%v, %v) = false, want true", s3, s3)) + } + + if a.Equal(s1, nil) { + panic(fmt.Sprintf("a.Equal(%v, nil) = true, want false", s1)) + } + if a.Equal(nil, s1) { + panic(fmt.Sprintf("a.Equal(nil, %v) = true, want false", s1)) + } + if !a.Equal(s1[:0], nil) { + panic(fmt.Sprintf("a.Equal(%v, nil = false, want true", s1[:0])) + } +} + +func offByOne[Elem Integer](a, b Elem) bool { + return a == b+1 || a == b-1 +} + +func TestEqualFn() { + s1 := []int{1, 2, 3} + s2 := []int{2, 3, 4} + if a.EqualFn(s1, s1, offByOne[int]) { + panic(fmt.Sprintf("a.EqualFn(%v, %v, offByOne) = true, want false", s1, s1)) + } + if !a.EqualFn(s1, s2, offByOne[int]) { + panic(fmt.Sprintf("a.EqualFn(%v, %v, offByOne) = false, want true", s1, s2)) + } + + if !a.EqualFn(s1[:0], nil, offByOne[int]) { + panic(fmt.Sprintf("a.EqualFn(%v, nil, offByOne) = false, want true", s1[:0])) + } + + s3 := []string{"a", "b", "c"} + s4 := []string{"A", "B", "C"} + if !a.EqualFn(s3, s4, strings.EqualFold) { + panic(fmt.Sprintf("a.EqualFn(%v, %v, strings.EqualFold) = false, want true", s3, s4)) + } +} + +func TestMap() { + s1 := []int{1, 2, 3} + s2 := a.Map(s1, func(i int) float64 { return float64(i) * 2.5 }) + if want := []float64{2.5, 5, 7.5}; !a.Equal(s2, want) { + panic(fmt.Sprintf("a.Map(%v, ...) = %v, want %v", s1, s2, want)) + } + + s3 := []string{"Hello", "World"} + s4 := a.Map(s3, strings.ToLower) + if want := []string{"hello", "world"}; !a.Equal(s4, want) { + panic(fmt.Sprintf("a.Map(%v, strings.ToLower) = %v, want %v", s3, s4, want)) + } + + s5 := a.Map(nil, func(i int) int { return i }) + if len(s5) != 0 { + panic(fmt.Sprintf("a.Map(nil, identity) = %v, want empty slice", s5)) + } +} + +func TestReduce() { + s1 := []int{1, 2, 3} + r := a.Reduce(s1, 0, func(f float64, i int) float64 { return float64(i)*2.5 + f }) + if want := 15.0; r != want { + panic(fmt.Sprintf("a.Reduce(%v, 0, ...) = %v, want %v", s1, r, want)) + } + + if got := a.Reduce(nil, 0, func(i, j int) int { return i + j }); got != 0 { + panic(fmt.Sprintf("a.Reduce(nil, 0, add) = %v, want 0", got)) + } +} + +func TestFilter() { + s1 := []int{1, 2, 3} + s2 := a.Filter(s1, func(i int) bool { return i%2 == 0 }) + if want := []int{2}; !a.Equal(s2, want) { + panic(fmt.Sprintf("a.Filter(%v, even) = %v, want %v", s1, s2, want)) + } + + if s3 := a.Filter(s1[:0], func(i int) bool { return true }); len(s3) > 0 { + panic(fmt.Sprintf("a.Filter(%v, identity) = %v, want empty slice", s1[:0], s3)) + } +} + +func TestMax() { + s1 := []int{1, 2, 3, -5} + if got, want := a.SliceMax(s1), 3; got != want { + panic(fmt.Sprintf("a.Max(%v) = %d, want %d", s1, got, want)) + } + + s2 := []string{"aaa", "a", "aa", "aaaa"} + if got, want := a.SliceMax(s2), "aaaa"; got != want { + panic(fmt.Sprintf("a.Max(%v) = %q, want %q", s2, got, want)) + } + + if got, want := a.SliceMax(s2[:0]), ""; got != want { + panic(fmt.Sprintf("a.Max(%v) = %q, want %q", s2[:0], got, want)) + } +} + +func TestMin() { + s1 := []int{1, 2, 3, -5} + if got, want := a.SliceMin(s1), -5; got != want { + panic(fmt.Sprintf("a.Min(%v) = %d, want %d", s1, got, want)) + } + + s2 := []string{"aaa", "a", "aa", "aaaa"} + if got, want := a.SliceMin(s2), "a"; got != want { + panic(fmt.Sprintf("a.Min(%v) = %q, want %q", s2, got, want)) + } + + if got, want := a.SliceMin(s2[:0]), ""; got != want { + panic(fmt.Sprintf("a.Min(%v) = %q, want %q", s2[:0], got, want)) + } +} + +func TestAppend() { + s := []int{1, 2, 3} + s = a.Append(s, 4, 5, 6) + want := []int{1, 2, 3, 4, 5, 6} + if !a.Equal(s, want) { + panic(fmt.Sprintf("after a.Append got %v, want %v", s, want)) + } +} + +func TestCopy() { + s1 := []int{1, 2, 3} + s2 := []int{4, 5} + if got := a.Copy(s1, s2); got != 2 { + panic(fmt.Sprintf("a.Copy returned %d, want 2", got)) + } + want := []int{4, 5, 3} + if !a.Equal(s1, want) { + panic(fmt.Sprintf("after a.Copy got %v, want %v", s1, want)) + } +} +func main() { + TestEqual() + TestEqualFn() + TestMap() + TestReduce() + TestFilter() + TestMax() + TestMin() + TestAppend() + TestCopy() +} diff --git a/test/typeparam/sliceimp.go b/test/typeparam/sliceimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/sliceimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/slices.go b/test/typeparam/slices.go new file mode 100644 index 0000000..b24817d --- /dev/null +++ b/test/typeparam/slices.go @@ -0,0 +1,318 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package slices provides functions for basic operations on +// slices of any element type. +package main + +import ( + "fmt" + "math" + "strings" +) + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +type Integer interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +// Max returns the maximum of two values of some ordered type. +func _Max[T Ordered](a, b T) T { + if a > b { + return a + } + return b +} + +// Min returns the minimum of two values of some ordered type. +func _Min[T Ordered](a, b T) T { + if a < b { + return a + } + return b +} + +// _Equal reports whether two slices are equal: the same length and all +// elements equal. All floating point NaNs are considered equal. +func _Equal[Elem comparable](s1, s2 []Elem) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +// _EqualFn reports whether two slices are equal using a comparison +// function on each element. +func _EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if !eq(v1, v2) { + return false + } + } + return true +} + +// _Map turns a []Elem1 to a []Elem2 using a mapping function. +func _Map[Elem1, Elem2 any](s []Elem1, f func(Elem1) Elem2) []Elem2 { + r := make([]Elem2, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} + +// _Reduce reduces a []Elem1 to a single value of type Elem2 using +// a reduction function. +func _Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 { + r := initializer + for _, v := range s { + r = f(r, v) + } + return r +} + +// _Filter filters values from a slice using a filter function. +func _Filter[Elem any](s []Elem, f func(Elem) bool) []Elem { + var r []Elem + for _, v := range s { + if f(v) { + r = append(r, v) + } + } + return r +} + +// _Max returns the maximum element in a slice of some ordered type. +// If the slice is empty it returns the zero value of the element type. +func _SliceMax[Elem Ordered](s []Elem) Elem { + if len(s) == 0 { + var zero Elem + return zero + } + return _Reduce(s[1:], s[0], _Max[Elem]) +} + +// _Min returns the minimum element in a slice of some ordered type. +// If the slice is empty it returns the zero value of the element type. +func _SliceMin[Elem Ordered](s []Elem) Elem { + if len(s) == 0 { + var zero Elem + return zero + } + return _Reduce(s[1:], s[0], _Min[Elem]) +} + +// _Append adds values to the end of a slice, returning a new slice. +// This is like the predeclared append function; it's an example +// of how to write it using generics. We used to write code like +// this before append was added to the language, but we had to write +// a separate copy for each type. +func _Append[T any](s []T, t ...T) []T { + lens := len(s) + tot := lens + len(t) + if tot <= cap(s) { + s = s[:tot] + } else { + news := make([]T, tot, tot+tot/2) + _Copy(news, s) + s = news + } + _Copy(s[lens:tot], t) + return s +} + +// _Copy copies values from t to s, stopping when either slice is full, +// returning the number of values copied. This is like the predeclared +// copy function; it's an example of how to write it using generics. +func _Copy[T any](s, t []T) int { + i := 0 + for ; i < len(s) && i < len(t); i++ { + s[i] = t[i] + } + return i +} + +func TestEqual() { + s1 := []int{1, 2, 3} + if !_Equal(s1, s1) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s1)) + } + s2 := []int{1, 2, 3} + if !_Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s1, s2)) + } + s2 = append(s2, 4) + if _Equal(s1, s2) { + panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", s1, s2)) + } + + s3 := []float64{1, 2, math.NaN()} + if !_Equal(s3, s3) { + panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", s3, s3)) + } + + if _Equal(s1, nil) { + panic(fmt.Sprintf("_Equal(%v, nil) = true, want false", s1)) + } + if _Equal(nil, s1) { + panic(fmt.Sprintf("_Equal(nil, %v) = true, want false", s1)) + } + if !_Equal(s1[:0], nil) { + panic(fmt.Sprintf("_Equal(%v, nil = false, want true", s1[:0])) + } +} + +func offByOne[Elem Integer](a, b Elem) bool { + return a == b+1 || a == b-1 +} + +func TestEqualFn() { + s1 := []int{1, 2, 3} + s2 := []int{2, 3, 4} + if _EqualFn(s1, s1, offByOne[int]) { + panic(fmt.Sprintf("_EqualFn(%v, %v, offByOne) = true, want false", s1, s1)) + } + if !_EqualFn(s1, s2, offByOne[int]) { + panic(fmt.Sprintf("_EqualFn(%v, %v, offByOne) = false, want true", s1, s2)) + } + + if !_EqualFn(s1[:0], nil, offByOne[int]) { + panic(fmt.Sprintf("_EqualFn(%v, nil, offByOne) = false, want true", s1[:0])) + } + + s3 := []string{"a", "b", "c"} + s4 := []string{"A", "B", "C"} + if !_EqualFn(s3, s4, strings.EqualFold) { + panic(fmt.Sprintf("_EqualFn(%v, %v, strings.EqualFold) = false, want true", s3, s4)) + } +} + +func TestMap() { + s1 := []int{1, 2, 3} + s2 := _Map(s1, func(i int) float64 { return float64(i) * 2.5 }) + if want := []float64{2.5, 5, 7.5}; !_Equal(s2, want) { + panic(fmt.Sprintf("_Map(%v, ...) = %v, want %v", s1, s2, want)) + } + + s3 := []string{"Hello", "World"} + s4 := _Map(s3, strings.ToLower) + if want := []string{"hello", "world"}; !_Equal(s4, want) { + panic(fmt.Sprintf("_Map(%v, strings.ToLower) = %v, want %v", s3, s4, want)) + } + + s5 := _Map(nil, func(i int) int { return i }) + if len(s5) != 0 { + panic(fmt.Sprintf("_Map(nil, identity) = %v, want empty slice", s5)) + } +} + +func TestReduce() { + s1 := []int{1, 2, 3} + r := _Reduce(s1, 0, func(f float64, i int) float64 { return float64(i)*2.5 + f }) + if want := 15.0; r != want { + panic(fmt.Sprintf("_Reduce(%v, 0, ...) = %v, want %v", s1, r, want)) + } + + if got := _Reduce(nil, 0, func(i, j int) int { return i + j }); got != 0 { + panic(fmt.Sprintf("_Reduce(nil, 0, add) = %v, want 0", got)) + } +} + +func TestFilter() { + s1 := []int{1, 2, 3} + s2 := _Filter(s1, func(i int) bool { return i%2 == 0 }) + if want := []int{2}; !_Equal(s2, want) { + panic(fmt.Sprintf("_Filter(%v, even) = %v, want %v", s1, s2, want)) + } + + if s3 := _Filter(s1[:0], func(i int) bool { return true }); len(s3) > 0 { + panic(fmt.Sprintf("_Filter(%v, identity) = %v, want empty slice", s1[:0], s3)) + } +} + +func TestMax() { + s1 := []int{1, 2, 3, -5} + if got, want := _SliceMax(s1), 3; got != want { + panic(fmt.Sprintf("_Max(%v) = %d, want %d", s1, got, want)) + } + + s2 := []string{"aaa", "a", "aa", "aaaa"} + if got, want := _SliceMax(s2), "aaaa"; got != want { + panic(fmt.Sprintf("_Max(%v) = %q, want %q", s2, got, want)) + } + + if got, want := _SliceMax(s2[:0]), ""; got != want { + panic(fmt.Sprintf("_Max(%v) = %q, want %q", s2[:0], got, want)) + } +} + +func TestMin() { + s1 := []int{1, 2, 3, -5} + if got, want := _SliceMin(s1), -5; got != want { + panic(fmt.Sprintf("_Min(%v) = %d, want %d", s1, got, want)) + } + + s2 := []string{"aaa", "a", "aa", "aaaa"} + if got, want := _SliceMin(s2), "a"; got != want { + panic(fmt.Sprintf("_Min(%v) = %q, want %q", s2, got, want)) + } + + if got, want := _SliceMin(s2[:0]), ""; got != want { + panic(fmt.Sprintf("_Min(%v) = %q, want %q", s2[:0], got, want)) + } +} + +func TestAppend() { + s := []int{1, 2, 3} + s = _Append(s, 4, 5, 6) + want := []int{1, 2, 3, 4, 5, 6} + if !_Equal(s, want) { + panic(fmt.Sprintf("after _Append got %v, want %v", s, want)) + } +} + +func TestCopy() { + s1 := []int{1, 2, 3} + s2 := []int{4, 5} + if got := _Copy(s1, s2); got != 2 { + panic(fmt.Sprintf("_Copy returned %d, want 2", got)) + } + want := []int{4, 5, 3} + if !_Equal(s1, want) { + panic(fmt.Sprintf("after _Copy got %v, want %v", s1, want)) + } +} +func main() { + TestEqual() + TestEqualFn() + TestMap() + TestReduce() + TestFilter() + TestMax() + TestMin() + TestAppend() + TestCopy() +} diff --git a/test/typeparam/smallest.go b/test/typeparam/smallest.go new file mode 100644 index 0000000..0ebd10e --- /dev/null +++ b/test/typeparam/smallest.go @@ -0,0 +1,42 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type Ordered interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + ~string +} + +func Smallest[T Ordered](s []T) T { + r := s[0] // panics if slice is empty + for _, v := range s[1:] { + if v < r { + r = v + } + } + return r +} + +func main() { + vec1 := []float64{5.3, 1.2, 32.8} + vec2 := []string{"abc", "def", "aaa"} + + want1 := 1.2 + if got := Smallest(vec1); got != want1 { + panic(fmt.Sprintf("got %d, want %d", got, want1)) + } + want2 := "aaa" + if got := Smallest(vec2); got != want2 { + panic(fmt.Sprintf("got %d, want %d", got, want2)) + } +} diff --git a/test/typeparam/smoketest.go b/test/typeparam/smoketest.go new file mode 100644 index 0000000..b720e04 --- /dev/null +++ b/test/typeparam/smoketest.go @@ -0,0 +1,56 @@ +// compile + +// 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 checks simple code using type parameters. + +package smoketest + +// type parameters for functions +func f1[P any]() {} +func f2[P1, P2 any, P3 any]() {} +func f3[P interface{}](x P, y T1[int]) {} + +// function instantiations +var _ = f1[int] +var _ = f2[int, string, struct{}] +var _ = f3[bool] + +// type parameters for types +type T1[P any] struct{} +type T2[P1, P2 any, P3 any] struct{} +type T3[P interface{}] interface{} + +// type instantiations +type _ T1[int] +type _ T2[int, string, struct{}] +type _ T3[bool] + +// methods +func (T1[P]) m1() {} +func (T1[_]) m2() {} +func (x T2[P1, P2, P3]) m() {} + +// type lists +type _ interface { + m1() + m2() + int | float32 | string + m3() +} + +// embedded instantiated types +type _ struct { + f1, f2 int + T1[int] + T2[int, string, struct{}] + T3[bool] +} + +type _ interface { + m1() + m2() + T3[bool] +} diff --git a/test/typeparam/stringable.go b/test/typeparam/stringable.go new file mode 100644 index 0000000..791b670 --- /dev/null +++ b/test/typeparam/stringable.go @@ -0,0 +1,46 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "strconv" + "strings" +) + +type Stringer interface { + String() string +} + +// StringableList is a slice of some type, where the type +// must have a String method. +type StringableList[T Stringer] []T + +func (s StringableList[T]) String() string { + var sb strings.Builder + for i, v := range s { + if i > 0 { + sb.WriteString(", ") + } + sb.WriteString(v.String()) + } + return sb.String() +} + +type myint int + +func (a myint) String() string { + return strconv.Itoa(int(a)) +} + +func main() { + v := StringableList[myint]{myint(1), myint(2)} + + if got, want := v.String(), "1, 2"; got != want { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } +} diff --git a/test/typeparam/stringer.go b/test/typeparam/stringer.go new file mode 100644 index 0000000..0892cd8 --- /dev/null +++ b/test/typeparam/stringer.go @@ -0,0 +1,88 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test method calls on type parameters + +package main + +import ( + "fmt" + "reflect" + "strconv" +) + +// Simple constraint +type Stringer interface { + String() string +} + +func stringify[T Stringer](s []T) (ret []string) { + for _, v := range s { + ret = append(ret, v.String()) + } + return ret +} + +type myint int + +func (i myint) String() string { + return strconv.Itoa(int(i)) +} + +// Constraint with an embedded interface, but still only requires String() +type Stringer2 interface { + CanBeStringer2() int + SubStringer2 +} + +type SubStringer2 interface { + CanBeSubStringer2() int + String() string +} + +func stringify2[T Stringer2](s []T) (ret []string) { + for _, v := range s { + ret = append(ret, v.String()) + } + return ret +} + +func (myint) CanBeStringer2() int { + return 0 +} + +func (myint) CanBeSubStringer2() int { + return 0 +} + +// Test use of method values that are not called +func stringify3[T Stringer](s []T) (ret []string) { + for _, v := range s { + f := v.String + ret = append(ret, f()) + } + return ret +} + +func main() { + x := []myint{myint(1), myint(2), myint(3)} + + got := stringify(x) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + got = stringify2(x) + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + got = stringify3(x) + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } +} diff --git a/test/typeparam/stringerimp.dir/a.go b/test/typeparam/stringerimp.dir/a.go new file mode 100644 index 0000000..3f70937 --- /dev/null +++ b/test/typeparam/stringerimp.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Stringer interface { + String() string +} + +func Stringify[T Stringer](s []T) (ret []string) { + for _, v := range s { + ret = append(ret, v.String()) + } + return ret +} diff --git a/test/typeparam/stringerimp.dir/main.go b/test/typeparam/stringerimp.dir/main.go new file mode 100644 index 0000000..9b41d3b --- /dev/null +++ b/test/typeparam/stringerimp.dir/main.go @@ -0,0 +1,38 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" + "reflect" + "strconv" +) + +type myint int + +func (i myint) String() string { + return strconv.Itoa(int(i)) +} + +func main() { + x := []myint{myint(1), myint(2), myint(3)} + + got := a.Stringify(x) + want := []string{"1", "2", "3"} + if !reflect.DeepEqual(got, want) { + panic(fmt.Sprintf("got %s, want %s", got, want)) + } + + m1 := myint(1) + m2 := myint(2) + m3 := myint(3) + y := []*myint{&m1, &m2, &m3} + got2 := a.Stringify(y) + want2 := []string{"1", "2", "3"} + if !reflect.DeepEqual(got2, want2) { + panic(fmt.Sprintf("got %s, want %s", got2, want2)) + } +} diff --git a/test/typeparam/stringerimp.go b/test/typeparam/stringerimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/stringerimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/struct.go b/test/typeparam/struct.go new file mode 100644 index 0000000..2dad908 --- /dev/null +++ b/test/typeparam/struct.go @@ -0,0 +1,49 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +type E[T any] struct { + v T +} + +type S1 struct { + E[int] + v string +} + +type Eint = E[int] +type Ebool = E[bool] + +type S2 struct { + Eint + Ebool + v string +} + +type S3 struct { + *E[int] +} + +func main() { + s1 := S1{Eint{2}, "foo"} + if got, want := s1.E.v, 2; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + s2 := S2{Eint{3}, Ebool{true}, "foo"} + if got, want := s2.Eint.v, 3; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + var s3 S3 + s3.E = &Eint{4} + if got, want := s3.E.v, 4; got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } +} diff --git a/test/typeparam/structinit.dir/a.go b/test/typeparam/structinit.dir/a.go new file mode 100644 index 0000000..c76d155 --- /dev/null +++ b/test/typeparam/structinit.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type S[T any] struct { +} + +func (b *S[T]) build() *X[T] { + return &X[T]{f:0} +} +type X[T any] struct { + f int +} diff --git a/test/typeparam/structinit.dir/b.go b/test/typeparam/structinit.dir/b.go new file mode 100644 index 0000000..40a929b --- /dev/null +++ b/test/typeparam/structinit.dir/b.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func B() { + var x a.S[int] + _ = x +} diff --git a/test/typeparam/structinit.dir/main.go b/test/typeparam/structinit.dir/main.go new file mode 100644 index 0000000..c564171 --- /dev/null +++ b/test/typeparam/structinit.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./b" + +func main() { + b.B() +} diff --git a/test/typeparam/structinit.go b/test/typeparam/structinit.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/structinit.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/subdict.go b/test/typeparam/subdict.go new file mode 100644 index 0000000..463c510 --- /dev/null +++ b/test/typeparam/subdict.go @@ -0,0 +1,43 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test cases where a main dictionary is needed inside a generic function/method, because +// we are calling a method on a fully-instantiated type or a fully-instantiated function. +// (probably not common situations, of course) + +package main + +import ( + "fmt" +) + +type C comparable + +type value[T C] struct { + val T +} + +func (v *value[T]) test(def T) bool { + return (v.val == def) +} + +func (v *value[T]) get(def T) T { + var c value[int] + if c.test(32) { + return def + } else if v.test(def) { + return def + } else { + return v.val + } +} + +func main() { + var s value[string] + if got, want := s.get("ab"), ""; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } +} diff --git a/test/typeparam/sum.go b/test/typeparam/sum.go new file mode 100644 index 0000000..25bac18 --- /dev/null +++ b/test/typeparam/sum.go @@ -0,0 +1,50 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +func Sum[T interface{ int | float64 }](vec []T) T { + var sum T + for _, elt := range vec { + sum = sum + elt + } + return sum +} + +func Abs(f float64) float64 { + if f < 0.0 { + return -f + } + return f +} + +func main() { + vec1 := []int{3, 4} + vec2 := []float64{5.8, 9.6} + got := Sum[int](vec1) + want := vec1[0] + vec1[1] + if got != want { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + got = Sum(vec1) + if want != got { + panic(fmt.Sprintf("got %d, want %d", got, want)) + } + + fwant := vec2[0] + vec2[1] + fgot := Sum[float64](vec2) + if Abs(fgot-fwant) > 1e-10 { + panic(fmt.Sprintf("got %f, want %f", fgot, fwant)) + } + fgot = Sum(vec2) + if Abs(fgot-fwant) > 1e-10 { + panic(fmt.Sprintf("got %f, want %f", fgot, fwant)) + } +} diff --git a/test/typeparam/tparam1.go b/test/typeparam/tparam1.go new file mode 100644 index 0000000..a05f542 --- /dev/null +++ b/test/typeparam/tparam1.go @@ -0,0 +1,43 @@ +// errorcheck + +// 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. + +// Basic type parameter list type-checking (not syntax) errors. + +package tparam1 + +// The predeclared identifier "any" may be used in place of interface{}. +var _ any + +func _(_ any) + +type _[_ any] struct{} + +const N = 10 + +type ( + _ []struct{} // slice + _ [N]struct{} // array + _[T any] struct{} + _[T, T any] struct{} // ERROR "T redeclared" + _[T1, T2 any, T3 any] struct{} +) + +func _[T any]() {} +func _[T, T any]() {} // ERROR "T redeclared" +func _[T1, T2 any](x T1) T2 { panic(0) } + +// Type parameters are visible from opening [ to end of function. +type C interface{} + +func _[T interface{}]() {} +func _[T C]() {} +func _[T struct{}]() {} // ok if #48424 is accepted +func _[T interface{ m() T }]() {} +func _[T1 interface{ m() T2 }, T2 interface{ m() T1 }]() { + var _ T1 +} + +// TODO(gri) expand this diff --git a/test/typeparam/typelist.go b/test/typeparam/typelist.go new file mode 100644 index 0000000..7c71321 --- /dev/null +++ b/test/typeparam/typelist.go @@ -0,0 +1,138 @@ +// compile + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file tests type lists & constraints with core types. + +// Note: This test has been adjusted to use the new +// type set notation rather than type lists. + +package p + +// Assignability of an unnamed pointer type to a type parameter that +// has a matching underlying type. +func _[T interface{}, PT interface{ ~*T }](x T) PT { + return &x +} + +// Indexing of generic types containing type parameters in their type list: +func at[T interface{ ~[]E }, E any](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 _[T interface{ ~int }](x T) { + var _ int = int(x) + var _ T = 42 + var _ T = T(myint(42)) +} + +// TODO: put this type declaration back inside the above function when issue 47631 is fixed. +type myint int + +// Indexing a generic type which has a an array as core type. +func _[T interface{ ~[10]int }](x T) { + _ = x[9] // ok +} + +// Dereference of a generic type which has a pointer as core type. +func _[T interface{ ~*int }](p T) int { + return *p +} + +// Channel send and receive on a generic type which has a channel as core type. +func _[T interface{ ~chan int }](ch T) int { + // This would deadlock if executed (but ok for a compile test) + ch <- 0 + return <-ch +} + +// Calling of a generic type which has a function as core type. +func _[T interface{ ~func() }](f T) { + f() + go f() +} + +// Same, but function has a parameter and return value. +func _[T interface{ ~func(string) int }](f T) int { + return f("hello") +} + +// Map access of a generic type which has a map as core type. +func _[V any, T interface{ ~map[string]V }](p T) V { + return p["test"] +} + +// Testing partial and full type inference, including the case where the types can +// be inferred without needing the types of the function arguments. + +// Cannot embed stand-alone type parameters. Disabled for now. +/* +func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) +func f0x() { + f := f0[string] + f("a", "b", "c", "d") + f0("a", "b", "c", "d") +} + +func f1[A any, B interface{type A}](A, B) +func f1x() { + f := f1[int] + f(int(0), int(0)) + f1(int(0), int(0)) + f(0, 0) + f1(0, 0) +} +*/ + +func f2[A any, B interface{ []A }](_ A, _ B) {} +func f2x() { + f := f2[byte] + f(byte(0), []byte{}) + f2(byte(0), []byte{}) + f(0, []byte{}) + // f2(0, []byte{}) - this one doesn't work +} + +// Cannot embed stand-alone type parameters. Disabled for now. +/* +func f3[A any, B interface{type C}, C interface{type *A}](a A, _ B, c C) +func f3x() { + f := f3[int] + var x int + f(x, &x, &x) + f3(x, &x, &x) +} +*/ + +func f4[A any, B interface{ []C }, C interface{ *A }](_ A, _ B, c C) {} +func f4x() { + f := f4[int] + var x int + f(x, []*int{}, &x) + f4(x, []*int{}, &x) +} + +func f5[A interface { + struct { + b B + c C + } +}, B any, C interface{ *B }](x B) A { + panic(0) +} +func f5x() { + x := f5(1.2) + var _ float64 = x.b + var _ float64 = *x.c +} + +func f6[A any, B interface{ ~struct{ f []A } }](B) A { panic(0) } +func f6x() { + x := f6(struct{ f []string }{}) + var _ string = x +} diff --git a/test/typeparam/typeswitch1.go b/test/typeparam/typeswitch1.go new file mode 100644 index 0000000..a0468d3 --- /dev/null +++ b/test/typeparam/typeswitch1.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T any](i interface{}) { + switch i.(type) { + case T: + println("T") + case int: + println("int") + case int32, int16: + println("int32/int16") + case struct{ a, b T }: + println("struct{T,T}") + default: + println("other") + } +} +func main() { + f[float64](float64(6)) + f[float64](int(7)) + f[float64](int32(8)) + f[float64](struct{ a, b float64 }{a: 1, b: 2}) + f[float64](int8(9)) + f[int32](int32(7)) + f[int](int32(7)) + f[any](int(10)) + f[interface{ M() }](int(11)) +} diff --git a/test/typeparam/typeswitch1.out b/test/typeparam/typeswitch1.out new file mode 100644 index 0000000..6b8a33c --- /dev/null +++ b/test/typeparam/typeswitch1.out @@ -0,0 +1,9 @@ +T +int +int32/int16 +struct{T,T} +other +T +int32/int16 +T +int diff --git a/test/typeparam/typeswitch2.go b/test/typeparam/typeswitch2.go new file mode 100644 index 0000000..286002a --- /dev/null +++ b/test/typeparam/typeswitch2.go @@ -0,0 +1,35 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +func f[T any](i interface{}) { + switch x := i.(type) { + case T: + fmt.Println("T", x) + case int: + fmt.Println("int", x) + case int32, int16: + fmt.Println("int32/int16", x) + case struct{ a, b T }: + fmt.Println("struct{T,T}", x.a, x.b) + default: + fmt.Println("other", x) + } +} +func main() { + f[float64](float64(6)) + f[float64](int(7)) + f[float64](int32(8)) + f[float64](struct{ a, b float64 }{a: 1, b: 2}) + f[float64](int8(9)) + f[int32](int32(7)) + f[int](int32(7)) + f[any](int(10)) + f[interface{ M() }](int(11)) +} diff --git a/test/typeparam/typeswitch2.out b/test/typeparam/typeswitch2.out new file mode 100644 index 0000000..6d4df54 --- /dev/null +++ b/test/typeparam/typeswitch2.out @@ -0,0 +1,9 @@ +T 6 +int 7 +int32/int16 8 +struct{T,T} 1 2 +other 9 +T 7 +int32/int16 7 +T 10 +int 11 diff --git a/test/typeparam/typeswitch3.go b/test/typeparam/typeswitch3.go new file mode 100644 index 0000000..b84fdd0 --- /dev/null +++ b/test/typeparam/typeswitch3.go @@ -0,0 +1,48 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I interface{ foo() int } +type J interface { + I + bar() +} + +type myint int + +func (x myint) foo() int { return int(x) } + +type myfloat float64 + +func (x myfloat) foo() int { return int(x) } + +type myint32 int32 + +func (x myint32) foo() int { return int(x) } +func (x myint32) bar() {} + +func f[T I](i I) { + switch x := i.(type) { + case T: + println("T", x.foo()) + case myint: + println("myint", x.foo()) + default: + println("other", x.foo()) + } +} +func main() { + f[myfloat](myint(6)) + f[myfloat](myfloat(7)) + f[myfloat](myint32(8)) + f[myint32](myint32(8)) + f[myint32](myfloat(7)) + f[myint](myint32(9)) + f[I](myint(10)) + f[J](myint(11)) + f[J](myint32(12)) +} diff --git a/test/typeparam/typeswitch3.out b/test/typeparam/typeswitch3.out new file mode 100644 index 0000000..05ed533 --- /dev/null +++ b/test/typeparam/typeswitch3.out @@ -0,0 +1,9 @@ +myint 6 +T 7 +other 8 +T 8 +other 7 +other 9 +T 10 +myint 11 +T 12 diff --git a/test/typeparam/typeswitch4.go b/test/typeparam/typeswitch4.go new file mode 100644 index 0000000..3fdf552 --- /dev/null +++ b/test/typeparam/typeswitch4.go @@ -0,0 +1,46 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I interface{ foo() int } +type J interface { + I + bar() +} + +type myint int + +func (x myint) foo() int { return int(x) } + +type myfloat float64 + +func (x myfloat) foo() int { return int(x) } + +type myint32 int32 + +func (x myint32) foo() int { return int(x) } +func (x myint32) bar() {} + +func f[T I](i I) { + switch x := i.(type) { + case T, myint32: + println("T/myint32", x.foo()) + default: + println("other", x.foo()) + } +} +func main() { + f[myfloat](myint(6)) + f[myfloat](myfloat(7)) + f[myfloat](myint32(8)) + f[myint32](myint32(9)) + f[myint](myint32(10)) + f[myint](myfloat(42)) + f[I](myint(10)) + f[J](myint(11)) + f[J](myint32(12)) +} diff --git a/test/typeparam/typeswitch4.out b/test/typeparam/typeswitch4.out new file mode 100644 index 0000000..b98f074 --- /dev/null +++ b/test/typeparam/typeswitch4.out @@ -0,0 +1,9 @@ +other 6 +T/myint32 7 +T/myint32 8 +T/myint32 9 +T/myint32 10 +other 42 +T/myint32 10 +other 11 +T/myint32 12 diff --git a/test/typeparam/typeswitch5.go b/test/typeparam/typeswitch5.go new file mode 100644 index 0000000..ac52adb --- /dev/null +++ b/test/typeparam/typeswitch5.go @@ -0,0 +1,28 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type myint int +func (x myint) foo() int {return int(x)} + +type myfloat float64 +func (x myfloat) foo() float64 {return float64(x) } + +func f[T any](i interface{}) { + switch x := i.(type) { + case interface { foo() T }: + println("fooer", x.foo()) + default: + println("other") + } +} +func main() { + f[int](myint(6)) + f[int](myfloat(7)) + f[float64](myint(8)) + f[float64](myfloat(9)) +} diff --git a/test/typeparam/typeswitch5.out b/test/typeparam/typeswitch5.out new file mode 100644 index 0000000..6b4cb44 --- /dev/null +++ b/test/typeparam/typeswitch5.out @@ -0,0 +1,4 @@ +fooer 6 +other +other +fooer +9.000000e+000 diff --git a/test/typeparam/typeswitch6.go b/test/typeparam/typeswitch6.go new file mode 100644 index 0000000..81d4f20 --- /dev/null +++ b/test/typeparam/typeswitch6.go @@ -0,0 +1,30 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T any](i interface{}) { + switch i.(type) { + case T: + println("T") + case int: + println("int") + default: + println("other") + } +} + +type myint int +func (myint) foo() { +} + +func main() { + f[interface{}](nil) + f[interface{}](6) + f[interface{foo()}](nil) + f[interface{foo()}](7) + f[interface{foo()}](myint(8)) +} diff --git a/test/typeparam/typeswitch6.out b/test/typeparam/typeswitch6.out new file mode 100644 index 0000000..441add5 --- /dev/null +++ b/test/typeparam/typeswitch6.out @@ -0,0 +1,5 @@ +other +T +other +int +T diff --git a/test/typeparam/typeswitch7.go b/test/typeparam/typeswitch7.go new file mode 100644 index 0000000..067bed7 --- /dev/null +++ b/test/typeparam/typeswitch7.go @@ -0,0 +1,37 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f[T any](i interface{foo()}) { + switch i.(type) { + case interface{bar() T}: + println("barT") + case myint: + println("myint") + case myfloat: + println("myfloat") + default: + println("other") + } +} + +type myint int +func (myint) foo() { +} +func (x myint) bar() int { + return int(x) +} + +type myfloat float64 +func (myfloat) foo() { +} + +func main() { + f[int](nil) + f[int](myint(6)) + f[int](myfloat(7)) +} diff --git a/test/typeparam/typeswitch7.out b/test/typeparam/typeswitch7.out new file mode 100644 index 0000000..d7fcad4 --- /dev/null +++ b/test/typeparam/typeswitch7.out @@ -0,0 +1,3 @@ +other +barT +myfloat diff --git a/test/typeparam/valimp.dir/a.go b/test/typeparam/valimp.dir/a.go new file mode 100644 index 0000000..2ed0063 --- /dev/null +++ b/test/typeparam/valimp.dir/a.go @@ -0,0 +1,32 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Value[T any] struct { + val T +} + +// The noinline directive should survive across import, and prevent instantiations +// of these functions from being inlined. + +//go:noinline +func Get[T any](v *Value[T]) T { + return v.val +} + +//go:noinline +func Set[T any](v *Value[T], val T) { + v.val = val +} + +//go:noinline +func (v *Value[T]) Set(val T) { + v.val = val +} + +//go:noinline +func (v *Value[T]) Get() T { + return v.val +} diff --git a/test/typeparam/valimp.dir/main.go b/test/typeparam/valimp.dir/main.go new file mode 100644 index 0000000..e357af4 --- /dev/null +++ b/test/typeparam/valimp.dir/main.go @@ -0,0 +1,55 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + "fmt" +) + +func main() { + var v1 a.Value[int] + + a.Set(&v1, 1) + if got, want := a.Get(&v1), 1; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + v1.Set(2) + if got, want := v1.Get(), 2; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + v1p := new(a.Value[int]) + a.Set(v1p, 3) + if got, want := a.Get(v1p), 3; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + + v1p.Set(4) + if got, want := v1p.Get(), 4; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + + var v2 a.Value[string] + a.Set(&v2, "a") + if got, want := a.Get(&v2), "a"; got != want { + panic(fmt.Sprintf("Get() == %q, want %q", got, want)) + } + + v2.Set("b") + if got, want := a.Get(&v2), "b"; got != want { + panic(fmt.Sprintf("Get() == %q, want %q", got, want)) + } + + v2p := new(a.Value[string]) + a.Set(v2p, "c") + if got, want := a.Get(v2p), "c"; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } + + v2p.Set("d") + if got, want := v2p.Get(), "d"; got != want { + panic(fmt.Sprintf("Get() == %d, want %d", got, want)) + } +} diff --git a/test/typeparam/valimp.go b/test/typeparam/valimp.go new file mode 100644 index 0000000..40df49f --- /dev/null +++ b/test/typeparam/valimp.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/value.go b/test/typeparam/value.go new file mode 100644 index 0000000..be25dce --- /dev/null +++ b/test/typeparam/value.go @@ -0,0 +1,75 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "fmt" + +type value[T any] struct { + val T +} + +func get[T any](v *value[T]) T { + return v.val +} + +func set[T any](v *value[T], val T) { + v.val = val +} + +func (v *value[T]) set(val T) { + v.val = val +} + +func (v *value[T]) get() T { + return v.val +} + +func main() { + var v1 value[int] + set(&v1, 1) + if got, want := get(&v1), 1; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } + + v1.set(2) + if got, want := v1.get(), 2; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } + + v1p := new(value[int]) + set(v1p, 3) + if got, want := get(v1p), 3; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } + + v1p.set(4) + if got, want := v1p.get(), 4; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } + + var v2 value[string] + set(&v2, "a") + if got, want := get(&v2), "a"; got != want { + panic(fmt.Sprintf("get() == %q, want %q", got, want)) + } + + v2.set("b") + if got, want := get(&v2), "b"; got != want { + panic(fmt.Sprintf("get() == %q, want %q", got, want)) + } + + v2p := new(value[string]) + set(v2p, "c") + if got, want := get(v2p), "c"; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } + + v2p.set("d") + if got, want := v2p.get(), "d"; got != want { + panic(fmt.Sprintf("get() == %d, want %d", got, want)) + } +} |