...

Source file src/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go

Documentation: golang.org/x/tools/go/analysis/passes/ifaceassert

     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  	"golang.org/x/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  }
   113  

View as plain text