...

Source file src/golang.org/x/tools/go/ssa/parameterized.go

Documentation: golang.org/x/tools/go/ssa

     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  	"golang.org/x/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  }
   114  
   115  func (w *tpWalker) anyParameterized(ts []types.Type) bool {
   116  	for _, t := range ts {
   117  		if w.isParameterized(t) {
   118  			return true
   119  		}
   120  	}
   121  	return false
   122  }
   123  

View as plain text