blob: 8994164eacf5f9cd4bf2838b2b47442c2bc3ae6e [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains regression tests for bugs found.
package p
import "io"
import "context"
// Interfaces are always comparable (though the comparison may panic at runtime).
func eql[T comparable](x, y T) bool {
return x == y
}
func _() {
var x interface{}
var y interface{ m() }
eql(x, y /* ERROR does not match */ ) // interfaces of different types
eql(x, x)
eql(y, y)
eql(y, nil)
eql[io.Reader](nil, nil)
}
// If we have a receiver of pointer type (below: *T) we must ignore
// the pointer in the implementation of the method lookup because
// the type bound of T is an interface and pointer to interface types
// have no methods and then the lookup would fail.
type C[T any] interface {
m()
}
// using type bound C
func _[T C[T]](x *T) {
x.m()
}
// using an interface literal as bound
func _[T interface{ m() }](x *T) {
x.m()
}
// In a generic function body all method calls will be pointer method calls.
// If necessary, the function body will insert temporary variables, not seen
// by the user, in order to get an addressable variable to use to call the method.
// Thus, assume an argument type for a generic function to be the type of addressable
// values in the generic function when checking if the argument type satisfies the
// generic function's type bound.
func f2[_ interface{ m1(); m2() }]()
type T struct{}
func (T) m1()
func (*T) m2()
func _() {
// TODO(rFindley) this error should be positioned on the 'T'.
f2 /* ERROR wrong method signature */ [T]()
f2[*T]()
}
// When a type parameter is used as an argument to instantiate a parameterized
// type with a type list constraint, all of the type argument's types in its
// bound, but at least one (!), must be in the type list of the bound of the
// corresponding parameterized type's type parameter.
type T1[P interface{type uint}] struct{}
func _[P any]() {
_ = T1[P /* ERROR P has no type constraints */ ]{}
}
// This is the original (simplified) program causing the same issue.
type Unsigned interface {
type uint
}
type T2[U Unsigned] struct {
s U
}
func (u T2[U]) Add1() U {
return u.s + 1
}
func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] {
return T2[U /* ERROR U has no type constraints */ ]{}
}
func _() {
u := NewT2[string]()
_ = u.Add1()
}
// When we encounter an instantiated type such as Elem[T] we must
// not "expand" the instantiation when the type to be instantiated
// (Elem in this case) is not yet fully set up.
type Elem[T any] struct {
next *Elem[T]
list *List[T]
}
type List[T any] struct {
root Elem[T]
}
func (l *List[T]) Init() {
l.root.next = &l.root
}
// This is the original program causing the same issue.
type Element2[TElem any] struct {
next, prev *Element2[TElem]
list *List2[TElem]
Value TElem
}
type List2[TElem any] struct {
root Element2[TElem]
len int
}
func (l *List2[TElem]) Init() *List2[TElem] {
l.root.next = &l.root
l.root.prev = &l.root
l.len = 0
return l
}
// Self-recursive instantiations must work correctly.
type A[P any] struct { _ *A[P] }
type AB[P any] struct { _ *BA[P] }
type BA[P any] struct { _ *AB[P] }
// And a variation that also caused a problem with an
// unresolved underlying type.
type Element3[TElem any] struct {
next, prev *Element3[TElem]
list *List3[TElem]
Value TElem
}
func (e *Element3[TElem]) Next() *Element3[TElem] {
if p := e.next; e.list != nil && p != &e.list.root {
return p
}
return nil
}
type List3[TElem any] struct {
root Element3[TElem]
len int
}
// Infinite generic type declarations must lead to an error.
type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] }
type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] }
// The implementation of conversions T(x) between integers and floating-point
// numbers checks that both T and x have either integer or floating-point
// type. When the type of T or x is a type parameter, the respective simple
// predicate disjunction in the implementation was wrong because if a type list
// contains both an integer and a floating-point type, the type parameter is
// neither an integer or a floating-point number.
func convert[T1, T2 interface{type int, uint, float32}](v T1) T2 {
return T2(v)
}
func _() {
convert[int, uint](5)
}
// When testing binary operators, for +, the operand types must either be
// both numeric, or both strings. The implementation had the same problem
// with this check as the conversion issue above (issue #39623).
func issue39623[T interface{type int, string}](x, y T) T {
return x + y
}
// Simplified, from https://go2goplay.golang.org/p/efS6x6s-9NI:
func Sum[T interface{type int, string}](s []T) (sum T) {
for _, v := range s {
sum += v
}
return
}
// Assignability of an unnamed pointer type to a type parameter that
// has a matching underlying type.
func _[T interface{}, PT interface{type *T}] (x T) PT {
return &x
}
// Indexing of generic types containing type parameters in their type list:
func at[T interface{ type []E }, E interface{}](x T, i int) E {
return x[i]
}
// A generic type inside a function acts like a named type. Its underlying
// type is itself, its "operational type" is defined by the type list in
// the tybe bound, if any.
func _[T interface{type int}](x T) {
type myint int
var _ int = int(x)
var _ T = 42
var _ T = T(myint(42))
}
// Indexing a generic type with an array type bound checks length.
// (Example by mdempsky@.)
func _[T interface { type [10]int }](x T) {
_ = x[9] // ok
_ = x[20 /* ERROR out of bounds */ ]
}
// Pointer indirection of a generic type.
func _[T interface{ type *int }](p T) int {
return *p
}
// Channel sends and receives on generic types.
func _[T interface{ type chan int }](ch T) int {
ch <- 0
return <- ch
}
// Calling of a generic variable.
func _[T interface{ type func() }](f T) {
f()
go f()
}
// We must compare against the underlying type of type list entries
// when checking if a constraint is satisfied by a type. The under-
// lying type of each type list entry must be computed after the
// interface has been instantiated as its typelist may contain a
// type parameter that was substituted with a defined type.
// Test case from an (originally) failing example.
type sliceOf[E any] interface{ type []E }
func append[T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S
var f func()
var cancelSlice []context.CancelFunc
var _ = append[context.CancelFunc, []context.CancelFunc, context.CancelFunc](cancelSlice, f)
// A generic function must be instantiated with a type, not a value.
func g[T any](T) T
var _ = g[int]
var _ = g[nil /* ERROR is not a type */ ]
var _ = g(0)