| // Copyright 2021 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build go1.18 |
| // +build go1.18 |
| |
| package typeparams |
| |
| import "fmt" |
| |
| func TestBasicTypeParams[T interface{ ~int }, E error, F fmt.Formatter, S fmt.Stringer, A any](t T, e E, f F, s S, a A) { |
| fmt.Printf("%d", t) |
| fmt.Printf("%s", t) // want "wrong type.*contains ~int" |
| fmt.Printf("%v", t) |
| fmt.Printf("%d", e) // want "wrong type" |
| fmt.Printf("%s", e) |
| fmt.Errorf("%w", e) |
| fmt.Printf("%a", f) |
| fmt.Printf("%d", f) |
| fmt.Printf("%T", f.Format) |
| fmt.Printf("%p", f.Format) |
| fmt.Printf("%s", s) |
| fmt.Errorf("%w", s) // want "wrong type" |
| fmt.Printf("%d", a) // want "wrong type" |
| fmt.Printf("%s", a) // want "wrong type" |
| fmt.Printf("%v", a) |
| fmt.Printf("%T", a) |
| } |
| |
| type Constraint interface { |
| ~int |
| } |
| |
| func TestNamedConstraints_Issue49597[T Constraint](t T) { |
| fmt.Printf("%d", t) |
| fmt.Printf("%s", t) // want "wrong type.*contains ~int" |
| } |
| |
| func TestNestedTypeParams[T interface{ ~int }, S interface{ ~string }]() { |
| var x struct { |
| f int |
| t T |
| } |
| fmt.Printf("%d", x) |
| fmt.Printf("%s", x) // want "wrong type" |
| var y struct { |
| f string |
| t S |
| } |
| fmt.Printf("%d", y) // want "wrong type" |
| fmt.Printf("%s", y) |
| var m1 map[T]T |
| fmt.Printf("%d", m1) |
| fmt.Printf("%s", m1) // want "wrong type" |
| var m2 map[S]S |
| fmt.Printf("%d", m2) // want "wrong type" |
| fmt.Printf("%s", m2) |
| } |
| |
| type R struct { |
| F []R |
| } |
| |
| func TestRecursiveTypeDefinition() { |
| var r []R |
| fmt.Printf("%d", r) // No error: avoids infinite recursion. |
| } |
| |
| func TestRecursiveTypeParams[T1 ~[]T2, T2 ~[]T1 | string, T3 ~struct{ F T3 }](t1 T1, t2 T2, t3 T3) { |
| // No error is reported on the following lines to avoid infinite recursion. |
| fmt.Printf("%s", t1) |
| fmt.Printf("%s", t2) |
| fmt.Printf("%s", t3) |
| } |
| |
| func TestRecusivePointers[T1 ~*T2, T2 ~*T1](t1 T1, t2 T2) { |
| // No error: we can't determine if pointer rules apply. |
| fmt.Printf("%s", t1) |
| fmt.Printf("%s", t2) |
| } |
| |
| func TestEmptyTypeSet[T interface { |
| int | string |
| float64 |
| }](t T) { |
| fmt.Printf("%s", t) // No error: empty type set. |
| } |
| |
| func TestPointerRules[T ~*[]int | *[2]int](t T) { |
| var slicePtr *[]int |
| var arrayPtr *[2]int |
| fmt.Printf("%d", slicePtr) |
| fmt.Printf("%d", arrayPtr) |
| fmt.Printf("%d", t) |
| } |
| |
| func TestInterfacePromotion[E interface { |
| ~int |
| Error() string |
| }, S interface { |
| float64 |
| String() string |
| }](e E, s S) { |
| fmt.Printf("%d", e) |
| fmt.Printf("%s", e) |
| fmt.Errorf("%w", e) |
| fmt.Printf("%d", s) // want "wrong type.*contains float64" |
| fmt.Printf("%s", s) |
| fmt.Errorf("%w", s) // want "wrong type" |
| } |
| |
| type myInt int |
| |
| func TestTermReduction[T1 interface{ ~int | string }, T2 interface { |
| ~int | string |
| myInt |
| }](t1 T1, t2 T2) { |
| fmt.Printf("%d", t1) // want "wrong type.*contains string" |
| fmt.Printf("%s", t1) // want "wrong type.*contains ~int" |
| fmt.Printf("%d", t2) |
| fmt.Printf("%s", t2) // want "wrong type.*contains typeparams.myInt" |
| } |
| |
| type U[T any] struct{} |
| |
| func (u U[T]) String() string { |
| fmt.Println(u) // want `fmt.Println arg u causes recursive call to \(typeparams.U\[T\]\).String method` |
| return "" |
| } |
| |
| type S[T comparable] struct { |
| t T |
| } |
| |
| func (s S[T]) String() T { |
| fmt.Println(s) // Not flagged. We currently do not consider String() T to implement fmt.Stringer (see #55928). |
| return s.t |
| } |
| |
| func TestInstanceStringer() { |
| // Tests String method with nil Scope (#55350) |
| fmt.Println(&S[string]{}) |
| fmt.Println(&U[string]{}) |
| } |