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