// skip // Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Verify that generic methods order type arguments correctly. package main import ( "fmt" "strings" ) type S[A, B any] struct { a A b B } func (s S[A, B]) m() string { return typeStr(s.a, s.b) } func (s S[A, B]) n[C, D any]() string { var c C var d D return typeStr(s.a, s.b, c, d) } func typeStr(args ...any) string { s := "" for i, arg := range args { if i > 0 { s += "->" } s += strings.TrimPrefix(fmt.Sprintf("%T", arg), "main.") // trim for brevity } return s } func main() { type T1 int8 type T2 int16 type T3 int32 type T4 int64 // method calls // static dictionary on type check(S[T1, T2]{}.m(), "T1->T2") check(S[T2, T1]{}.m(), "T2->T1") // static dictionary on method check(S[T1, T2]{}.n[T3, T4](), "T1->T2->T3->T4") check(S[T4, T1]{}.n[T2, T3](), "T4->T1->T2->T3") check(S[T3, T4]{}.n[T1, T2](), "T3->T4->T1->T2") check(S[T2, T3]{}.n[T4, T1](), "T2->T3->T4->T1") // dynamic dictionary on type check(mCal[T1, T2](), "T1->T2") check(mCal[T2, T1](), "T2->T1") // dynamic dictionary on method check(nCal[T1, T2, T3, T4](), "T1->T2->T3->T4") check(nCal[T4, T1, T2, T3](), "T4->T1->T2->T3") check(nCal[T3, T4, T1, T2](), "T3->T4->T1->T2") check(nCal[T2, T3, T4, T1](), "T2->T3->T4->T1") // method values // static dictionary on type mv1 := S[T1, T2]{}.m check(mv1(), "T1->T2") mv2 := S[T2, T1]{}.m check(mv2(), "T2->T1") // static dictionary on method mv3 := S[T1, T2]{}.n[T3, T4] check(mv3(), "T1->T2->T3->T4") mv4 := S[T4, T1]{}.n[T2, T3] check(mv4(), "T4->T1->T2->T3") mv5 := S[T3, T4]{}.n[T1, T2] check(mv5(), "T3->T4->T1->T2") mv6 := S[T2, T3]{}.n[T4, T1] check(mv6(), "T2->T3->T4->T1") // dynamic dictionary on type check(mVal[T1, T2]()(), "T1->T2") check(mVal[T2, T1]()(), "T2->T1") // dynamic dictionary on method check(nVal[T1, T2, T3, T4]()(), "T1->T2->T3->T4") check(nVal[T4, T1, T2, T3]()(), "T4->T1->T2->T3") check(nVal[T3, T4, T1, T2]()(), "T3->T4->T1->T2") check(nVal[T2, T3, T4, T1]()(), "T2->T3->T4->T1") // method expressions // static dictionary on type me1 := S[T1, T2].m check(me1(S[T1, T2]{}), "T1->T2") me2 := S[T2, T1].m check(me2(S[T2, T1]{}), "T2->T1") // static dictionary on method me3 := S[T1, T2].n[T3, T4] check(me3(S[T1, T2]{}), "T1->T2->T3->T4") me4 := S[T4, T1].n[T2, T3] check(me4(S[T4, T1]{}), "T4->T1->T2->T3") me5 := S[T3, T4].n[T1, T2] check(me5(S[T3, T4]{}), "T3->T4->T1->T2") me6 := S[T2, T3].n[T4, T1] check(me6(S[T2, T3]{}), "T2->T3->T4->T1") // dynamic dictionary on type check(mExp[T1, T2]()(S[T1, T2]{}), "T1->T2") check(mExp[T2, T1]()(S[T2, T1]{}), "T2->T1") // dynamic dictionary on method check(nExp[T1, T2, T3, T4]()(S[T1, T2]{}), "T1->T2->T3->T4") check(nExp[T4, T1, T2, T3]()(S[T4, T1]{}), "T4->T1->T2->T3") check(nExp[T3, T4, T1, T2]()(S[T3, T4]{}), "T3->T4->T1->T2") check(nExp[T2, T3, T4, T1]()(S[T2, T3]{}), "T2->T3->T4->T1") } func check(got, want string) { if got != want { panic(fmt.Sprintf("got %s, want %s", got, want)) } } // piping type arguments via type parameters for dynamic dictionaries func mCal[A, B any]() string { return S[A, B]{}.m() } func mVal[A, B any]() func() string { return S[A, B]{}.m } func mExp[A, B any]() func(S[A, B]) string { return S[A, B].m } func nCal[A, B, C, D any]() string { return S[A, B]{}.n[C, D]() } func nVal[A, B, C, D any]() func() string { return S[A, B]{}.n[C, D] } func nExp[A, B, C, D any]() func(S[A, B]) string { return S[A, B].n[C, D] }