| // run -goexperiment genericmethods |
| |
| // 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] |
| } |