golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/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 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 // type expression of Named parameterized type 60 args []string // type expressions of args for named 61 want string // expected underlying value after substitution 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 // Eval() expr for its type. 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 // Eval() test.args[i] to get the i'th type arg. 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 }