package gotypes
import (
)
func ( *types.Context, types.Type, map[*types.TypeParam]types.Type) types.Type {
return (&subster{ctxt: , m: }).subst()
}
type subster struct {
ctxt *types.Context
m map[*types.TypeParam]types.Type
}
func ( *subster) ( types.Type) types.Type {
if == nil || !.mentions() {
return
}
= types.Unalias()
switch u := .(type) {
case *types.TypeParam:
if , := .m[]; {
return
}
return
case *types.Pointer:
return types.NewPointer(.(.Elem()))
case *types.Slice:
return types.NewSlice(.(.Elem()))
case *types.Array:
return types.NewArray(.(.Elem()), .Len())
case *types.Chan:
return types.NewChan(.Dir(), .(.Elem()))
case *types.Map:
return types.NewMap(.(.Key()), .(.Elem()))
case *types.Union:
:= make([]*types.Term, .Len())
for := range .Len() {
:= .Term()
[] = types.NewTerm(.Tilde(), .(.Type()))
}
return types.NewUnion()
case *types.Interface:
var []*types.Func
for := range .ExplicitMethods() {
:= .(.Type()).(*types.Signature)
= append(, types.NewFunc(.Pos(), .Pkg(), .Name(), ))
}
var []types.Type
for := range .EmbeddedTypes() {
= append(, .())
}
:= types.NewInterfaceType(, )
.Complete()
return
case *types.Signature:
return types.NewSignatureType(nil, nil, nil,
.substTuple(.Params()), .substTuple(.Results()), .Variadic())
case *types.Struct:
:= .NumFields()
:= make([]*types.Var, )
:= make([]string, )
for := range {
:= .Field()
[] = types.NewField(.Pos(), .Pkg(), .Name(), .(.Type()), .Embedded())
[] = .Tag()
}
return types.NewStruct(, )
case *types.Named:
:= .TypeArgs()
if .Len() == 0 {
return
}
:= make([]types.Type, .Len())
for := range .Len() {
[] = .(.At())
}
, := types.Instantiate(.ctxt, .Origin(), , false)
if != nil {
panic(fmt.Sprintf("plumb: Subst: re-instantiating %s failed: %v", , ))
}
return
default:
panic(fmt.Sprintf("plumb: subst on unsupported type %T", ))
}
}
func ( *subster) ( *types.Tuple) *types.Tuple {
:= make([]*types.Var, .Len())
for := range .Len() {
:= .At()
[] = types.NewVar(.Pos(), .Pkg(), .Name(), .subst(.Type()))
}
return types.NewTuple(...)
}
func ( *subster) ( types.Type) bool {
return typeContains(, &Set[types.Type]{}, func( types.Type) bool {
, := .(*types.TypeParam)
if ! {
return false
}
_, = .m[]
return
})
}