github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/parameterized.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/types" 9 10 "github.com/powerman/golang-tools/internal/typeparams" 11 ) 12 13 // tpWalker walks over types looking for parameterized types. 14 // 15 // NOTE: Adapted from go/types/infer.go. If that is exported in a future release remove this copy. 16 type tpWalker struct { 17 seen map[types.Type]bool 18 } 19 20 // isParameterized returns true when typ contains any type parameters. 21 func (w *tpWalker) isParameterized(typ types.Type) (res bool) { 22 // NOTE: Adapted from go/types/infer.go. Try to keep in sync. 23 24 // detect cycles 25 if x, ok := w.seen[typ]; ok { 26 return x 27 } 28 w.seen[typ] = false 29 defer func() { 30 w.seen[typ] = res 31 }() 32 33 switch t := typ.(type) { 34 case nil, *types.Basic: // TODO(gri) should nil be handled here? 35 break 36 37 case *types.Array: 38 return w.isParameterized(t.Elem()) 39 40 case *types.Slice: 41 return w.isParameterized(t.Elem()) 42 43 case *types.Struct: 44 for i, n := 0, t.NumFields(); i < n; i++ { 45 if w.isParameterized(t.Field(i).Type()) { 46 return true 47 } 48 } 49 50 case *types.Pointer: 51 return w.isParameterized(t.Elem()) 52 53 case *types.Tuple: 54 n := t.Len() 55 for i := 0; i < n; i++ { 56 if w.isParameterized(t.At(i).Type()) { 57 return true 58 } 59 } 60 61 case *types.Signature: 62 // t.tparams may not be nil if we are looking at a signature 63 // of a generic function type (or an interface method) that is 64 // part of the type we're testing. We don't care about these type 65 // parameters. 66 // Similarly, the receiver of a method may declare (rather then 67 // use) type parameters, we don't care about those either. 68 // Thus, we only need to look at the input and result parameters. 69 return w.isParameterized(t.Params()) || w.isParameterized(t.Results()) 70 71 case *types.Interface: 72 for i, n := 0, t.NumMethods(); i < n; i++ { 73 if w.isParameterized(t.Method(i).Type()) { 74 return true 75 } 76 } 77 terms, err := typeparams.InterfaceTermSet(t) 78 if err != nil { 79 panic(err) 80 } 81 for _, term := range terms { 82 if w.isParameterized(term.Type()) { 83 return true 84 } 85 } 86 87 case *types.Map: 88 return w.isParameterized(t.Key()) || w.isParameterized(t.Elem()) 89 90 case *types.Chan: 91 return w.isParameterized(t.Elem()) 92 93 case *types.Named: 94 args := typeparams.NamedTypeArgs(t) 95 // TODO(taking): this does not match go/types/infer.go. Check with rfindley. 96 if params := typeparams.ForNamed(t); params.Len() > args.Len() { 97 return true 98 } 99 for i, n := 0, args.Len(); i < n; i++ { 100 if w.isParameterized(args.At(i)) { 101 return true 102 } 103 } 104 105 case *typeparams.TypeParam: 106 return true 107 108 default: 109 panic(t) // unreachable 110 } 111 112 return false 113 }