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