github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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  	"golang.org/x/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  
   103  		subst := makeSubster(typeparams.NewContext(), nil, typeparams.ForNamed(T), targs, true)
   104  		sub := subst.typ(T.Underlying())
   105  		if got := sub.String(); got != test.want {
   106  			t.Errorf("subst{%v->%v}.typ(%s) = %v, want %v", test.expr, test.args, T.Underlying(), got, test.want)
   107  		}
   108  	}
   109  }