github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/functions/concrete.go (about) 1 package functions 2 3 import ( 4 "go/token" 5 "go/types" 6 7 "github.com/golangci/go-tools/ssa" 8 ) 9 10 func concreteReturnTypes(fn *ssa.Function) []*types.Tuple { 11 res := fn.Signature.Results() 12 if res == nil { 13 return nil 14 } 15 ifaces := make([]bool, res.Len()) 16 any := false 17 for i := 0; i < res.Len(); i++ { 18 _, ifaces[i] = res.At(i).Type().Underlying().(*types.Interface) 19 any = any || ifaces[i] 20 } 21 if !any { 22 return []*types.Tuple{res} 23 } 24 var out []*types.Tuple 25 for _, block := range fn.Blocks { 26 if len(block.Instrs) == 0 { 27 continue 28 } 29 ret, ok := block.Instrs[len(block.Instrs)-1].(*ssa.Return) 30 if !ok { 31 continue 32 } 33 vars := make([]*types.Var, res.Len()) 34 for i, v := range ret.Results { 35 var typ types.Type 36 if !ifaces[i] { 37 typ = res.At(i).Type() 38 } else if mi, ok := v.(*ssa.MakeInterface); ok { 39 // TODO(dh): if mi.X is a function call that returns 40 // an interface, call concreteReturnTypes on that 41 // function (or, really, go through Descriptions, 42 // avoid infinite recursion etc, just like nil error 43 // detection) 44 45 // TODO(dh): support Phi nodes 46 typ = mi.X.Type() 47 } else { 48 typ = res.At(i).Type() 49 } 50 vars[i] = types.NewParam(token.NoPos, nil, "", typ) 51 } 52 out = append(out, types.NewTuple(vars...)) 53 } 54 // TODO(dh): deduplicate out 55 return out 56 }