...

Source file src/golang.org/x/tools/internal/typeparams/free.go

Documentation: golang.org/x/tools/internal/typeparams

     1  // Copyright 2024 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 typeparams
     6  
     7  import (
     8  	"go/types"
     9  
    10  	"golang.org/x/tools/internal/aliases"
    11  )
    12  
    13  // Free is a memoization of the set of free type parameters within a
    14  // type. It makes a sequence of calls to [Free.Has] for overlapping
    15  // types more efficient. The zero value is ready for use.
    16  //
    17  // NOTE: Adapted from go/types/infer.go. If it is later exported, factor.
    18  type Free struct {
    19  	seen map[types.Type]bool
    20  }
    21  
    22  // Has reports whether the specified type has a free type parameter.
    23  func (w *Free) Has(typ types.Type) (res bool) {
    24  
    25  	// detect cycles
    26  	if x, ok := w.seen[typ]; ok {
    27  		return x
    28  	}
    29  	if w.seen == nil {
    30  		w.seen = make(map[types.Type]bool)
    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 *aliases.Alias:
    42  		return w.Has(aliases.Unalias(t))
    43  
    44  	case *types.Array:
    45  		return w.Has(t.Elem())
    46  
    47  	case *types.Slice:
    48  		return w.Has(t.Elem())
    49  
    50  	case *types.Struct:
    51  		for i, n := 0, t.NumFields(); i < n; i++ {
    52  			if w.Has(t.Field(i).Type()) {
    53  				return true
    54  			}
    55  		}
    56  
    57  	case *types.Pointer:
    58  		return w.Has(t.Elem())
    59  
    60  	case *types.Tuple:
    61  		n := t.Len()
    62  		for i := 0; i < n; i++ {
    63  			if w.Has(t.At(i).Type()) {
    64  				return true
    65  			}
    66  		}
    67  
    68  	case *types.Signature:
    69  		// t.tparams may not be nil if we are looking at a signature
    70  		// of a generic function type (or an interface method) that is
    71  		// part of the type we're testing. We don't care about these type
    72  		// parameters.
    73  		// Similarly, the receiver of a method may declare (rather than
    74  		// use) type parameters, we don't care about those either.
    75  		// Thus, we only need to look at the input and result parameters.
    76  		return w.Has(t.Params()) || w.Has(t.Results())
    77  
    78  	case *types.Interface:
    79  		for i, n := 0, t.NumMethods(); i < n; i++ {
    80  			if w.Has(t.Method(i).Type()) {
    81  				return true
    82  			}
    83  		}
    84  		terms, err := InterfaceTermSet(t)
    85  		if err != nil {
    86  			panic(err)
    87  		}
    88  		for _, term := range terms {
    89  			if w.Has(term.Type()) {
    90  				return true
    91  			}
    92  		}
    93  
    94  	case *types.Map:
    95  		return w.Has(t.Key()) || w.Has(t.Elem())
    96  
    97  	case *types.Chan:
    98  		return w.Has(t.Elem())
    99  
   100  	case *types.Named:
   101  		args := t.TypeArgs()
   102  		// TODO(taking): this does not match go/types/infer.go. Check with rfindley.
   103  		if params := t.TypeParams(); params.Len() > args.Len() {
   104  			return true
   105  		}
   106  		for i, n := 0, args.Len(); i < n; i++ {
   107  			if w.Has(args.At(i)) {
   108  				return true
   109  			}
   110  		}
   111  		return w.Has(t.Underlying()) // recurse for types local to parameterized functions
   112  
   113  	case *types.TypeParam:
   114  		return true
   115  
   116  	default:
   117  		panic(t) // unreachable
   118  	}
   119  
   120  	return false
   121  }
   122  

View as plain text