| // 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) |