1
2
3
4
5 package ssa
6
7 import (
8 "go/ast"
9 "go/parser"
10 "go/token"
11 "go/types"
12 "testing"
13 )
14
15 func TestSubst(t *testing.T) {
16 const source = `
17 package P
18
19 type t0 int
20 func (t0) f()
21 type t1 interface{ f() }
22 type t2 interface{ g() }
23 type t3 interface{ ~int }
24
25 func Fn0[T t1](x T) T {
26 x.f()
27 return x
28 }
29
30 type A[T any] [4]T
31 type B[T any] []T
32 type C[T, S any] []struct{s S; t T}
33 type D[T, S any] *struct{s S; t *T}
34 type E[T, S any] interface{ F() (T, S) }
35 type F[K comparable, V any] map[K]V
36 type G[T any] chan *T
37 type H[T any] func() T
38 type I[T any] struct{x, y, z int; t T}
39 type J[T any] interface{ t1 }
40 type K[T any] interface{ t1; F() T }
41 type L[T any] interface{ F() T; J[T] }
42
43 var _ L[int] = Fn0[L[int]](nil)
44 `
45
46 fset := token.NewFileSet()
47 f, err := parser.ParseFile(fset, "hello.go", source, 0)
48 if err != nil {
49 t.Fatal(err)
50 }
51
52 var conf types.Config
53 pkg, err := conf.Check("P", fset, []*ast.File{f}, nil)
54 if err != nil {
55 t.Fatal(err)
56 }
57
58 for _, test := range []struct {
59 expr string
60 args []string
61 want string
62 }{
63 {"A", []string{"string"}, "[4]string"},
64 {"A", []string{"int"}, "[4]int"},
65 {"B", []string{"int"}, "[]int"},
66 {"B", []string{"int8"}, "[]int8"},
67 {"C", []string{"int8", "string"}, "[]struct{s string; t int8}"},
68 {"C", []string{"string", "int8"}, "[]struct{s int8; t string}"},
69 {"D", []string{"int16", "string"}, "*struct{s string; t *int16}"},
70 {"E", []string{"int32", "string"}, "interface{F() (int32, string)}"},
71 {"F", []string{"int64", "string"}, "map[int64]string"},
72 {"G", []string{"uint64"}, "chan *uint64"},
73 {"H", []string{"uintptr"}, "func() uintptr"},
74 {"I", []string{"t0"}, "struct{x int; y int; z int; t P.t0}"},
75 {"J", []string{"t0"}, "interface{P.t1}"},
76 {"K", []string{"t0"}, "interface{F() P.t0; P.t1}"},
77 {"L", []string{"t0"}, "interface{F() P.t0; P.J[P.t0]}"},
78 {"L", []string{"L[t0]"}, "interface{F() P.L[P.t0]; P.J[P.L[P.t0]]}"},
79 } {
80
81 tv, err := types.Eval(fset, pkg, 0, test.expr)
82 if err != nil {
83 t.Fatalf("Eval(%s) failed: %v", test.expr, err)
84 }
85
86 var targs []types.Type
87 for _, astr := range test.args {
88 tv, err := types.Eval(fset, pkg, 0, astr)
89 if err != nil {
90 t.Fatalf("Eval(%s) failed: %v", astr, err)
91 }
92 targs = append(targs, tv.Type)
93 }
94
95 T := tv.Type.(*types.Named)
96
97 subst := makeSubster(types.NewContext(), nil, T.TypeParams(), targs, true)
98 sub := subst.typ(T.Underlying())
99 if got := sub.String(); got != test.want {
100 t.Errorf("subst{%v->%v}.typ(%s) = %v, want %v", test.expr, test.args, T.Underlying(), got, test.want)
101 }
102 }
103 }
104
View as plain text