github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/subst_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 import ( 8 "go/ast" 9 "go/parser" 10 "go/token" 11 "go/types" 12 "testing" 13 14 "github.com/powerman/golang-tools/internal/typeparams" 15 ) 16 17 func TestSubst(t *testing.T) { 18 if !typeparams.Enabled { 19 return 20 } 21 22 const source = ` 23 package P 24 25 type t0 int 26 func (t0) f() 27 type t1 interface{ f() } 28 type t2 interface{ g() } 29 type t3 interface{ ~int } 30 31 func Fn0[T t1](x T) T { 32 x.f() 33 return x 34 } 35 36 type A[T any] [4]T 37 type B[T any] []T 38 type C[T, S any] []struct{s S; t T} 39 type D[T, S any] *struct{s S; t *T} 40 type E[T, S any] interface{ F() (T, S) } 41 type F[K comparable, V any] map[K]V 42 type G[T any] chan *T 43 type H[T any] func() T 44 type I[T any] struct{x, y, z int; t T} 45 type J[T any] interface{ t1 } 46 type K[T any] interface{ t1; F() T } 47 type L[T any] interface{ F() T; J[T] } 48 49 var _ L[int] = Fn0[L[int]](nil) 50 ` 51 52 fset := token.NewFileSet() 53 f, err := parser.ParseFile(fset, "hello.go", source, 0) 54 if err != nil { 55 t.Fatal(err) 56 } 57 58 var conf types.Config 59 pkg, err := conf.Check("P", fset, []*ast.File{f}, nil) 60 if err != nil { 61 t.Fatal(err) 62 } 63 64 for _, test := range []struct { 65 expr string // type expression of Named parameterized type 66 args []string // type expressions of args for named 67 want string // expected underlying value after substitution 68 }{ 69 {"A", []string{"string"}, "[4]string"}, 70 {"A", []string{"int"}, "[4]int"}, 71 {"B", []string{"int"}, "[]int"}, 72 {"B", []string{"int8"}, "[]int8"}, 73 {"C", []string{"int8", "string"}, "[]struct{s string; t int8}"}, 74 {"C", []string{"string", "int8"}, "[]struct{s int8; t string}"}, 75 {"D", []string{"int16", "string"}, "*struct{s string; t *int16}"}, 76 {"E", []string{"int32", "string"}, "interface{F() (int32, string)}"}, 77 {"F", []string{"int64", "string"}, "map[int64]string"}, 78 {"G", []string{"uint64"}, "chan *uint64"}, 79 {"H", []string{"uintptr"}, "func() uintptr"}, 80 {"I", []string{"t0"}, "struct{x int; y int; z int; t P.t0}"}, 81 {"J", []string{"t0"}, "interface{P.t1}"}, 82 {"K", []string{"t0"}, "interface{F() P.t0; P.t1}"}, 83 {"L", []string{"t0"}, "interface{F() P.t0; P.J[P.t0]}"}, 84 {"L", []string{"L[t0]"}, "interface{F() P.L[P.t0]; P.J[P.L[P.t0]]}"}, 85 } { 86 // Eval() expr for its type. 87 tv, err := types.Eval(fset, pkg, 0, test.expr) 88 if err != nil { 89 t.Fatalf("Eval(%s) failed: %v", test.expr, err) 90 } 91 // Eval() test.args[i] to get the i'th type arg. 92 var targs []types.Type 93 for _, astr := range test.args { 94 tv, err := types.Eval(fset, pkg, 0, astr) 95 if err != nil { 96 t.Fatalf("Eval(%s) failed: %v", astr, err) 97 } 98 targs = append(targs, tv.Type) 99 } 100 101 T := tv.Type.(*types.Named) 102 var tparams []*typeparams.TypeParam 103 for i, l := 0, typeparams.ForNamed(T); i < l.Len(); i++ { 104 tparams = append(tparams, l.At(i)) 105 } 106 107 subst := makeSubster(typeparams.NewContext(), tparams, targs, true) 108 sub := subst.typ(T.Underlying()) 109 if got := sub.String(); got != test.want { 110 t.Errorf("subst{%v->%v}.typ(%s) = %v, want %v", test.expr, test.args, T.Underlying(), got, test.want) 111 } 112 } 113 }