...

Source file src/golang.org/x/tools/go/ssa/instantiate.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  	"fmt"
     9  	"go/types"
    10  	"sync"
    11  )
    12  
    13  // A generic records information about a generic origin function,
    14  // including a cache of existing instantiations.
    15  type generic struct {
    16  	instancesMu sync.Mutex
    17  	instances   map[*typeList]*Function // canonical type arguments to an instance.
    18  }
    19  
    20  // instance returns a Function that is the instantiation of generic
    21  // origin function fn with the type arguments targs.
    22  //
    23  // Any created instance is added to cr.
    24  //
    25  // Acquires fn.generic.instancesMu.
    26  func (fn *Function) instance(targs []types.Type, cr *creator) *Function {
    27  	key := fn.Prog.canon.List(targs)
    28  
    29  	gen := fn.generic
    30  
    31  	gen.instancesMu.Lock()
    32  	defer gen.instancesMu.Unlock()
    33  	inst, ok := gen.instances[key]
    34  	if !ok {
    35  		inst = createInstance(fn, targs, cr)
    36  		if gen.instances == nil {
    37  			gen.instances = make(map[*typeList]*Function)
    38  		}
    39  		gen.instances[key] = inst
    40  	}
    41  	return inst
    42  }
    43  
    44  // createInstance returns the instantiation of generic function fn using targs.
    45  // If the instantiation is created, this is added to cr.
    46  //
    47  // Requires fn.generic.instancesMu.
    48  func createInstance(fn *Function, targs []types.Type, cr *creator) *Function {
    49  	prog := fn.Prog
    50  
    51  	// Compute signature.
    52  	var sig *types.Signature
    53  	var obj *types.Func
    54  	if recv := fn.Signature.Recv(); recv != nil {
    55  		// method
    56  		obj = prog.canon.instantiateMethod(fn.object, targs, prog.ctxt)
    57  		sig = obj.Type().(*types.Signature)
    58  	} else {
    59  		// function
    60  		instSig, err := types.Instantiate(prog.ctxt, fn.Signature, targs, false)
    61  		if err != nil {
    62  			panic(err)
    63  		}
    64  		instance, ok := instSig.(*types.Signature)
    65  		if !ok {
    66  			panic("Instantiate of a Signature returned a non-signature")
    67  		}
    68  		obj = fn.object // instantiation does not exist yet
    69  		sig = prog.canon.Type(instance).(*types.Signature)
    70  	}
    71  
    72  	// Choose strategy (instance or wrapper).
    73  	var (
    74  		synthetic string
    75  		subst     *subster
    76  		build     buildFunc
    77  	)
    78  	if prog.mode&InstantiateGenerics != 0 && !prog.isParameterized(targs...) {
    79  		synthetic = fmt.Sprintf("instance of %s", fn.Name())
    80  		if fn.syntax != nil {
    81  			scope := obj.Origin().Scope()
    82  			subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false)
    83  			build = (*builder).buildFromSyntax
    84  		} else {
    85  			build = (*builder).buildParamsOnly
    86  		}
    87  	} else {
    88  		synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name())
    89  		build = (*builder).buildInstantiationWrapper
    90  	}
    91  
    92  	/* generic instance or instantiation wrapper */
    93  	instance := &Function{
    94  		name:           fmt.Sprintf("%s%s", fn.Name(), targs), // may not be unique
    95  		object:         obj,
    96  		Signature:      sig,
    97  		Synthetic:      synthetic,
    98  		syntax:         fn.syntax,    // \
    99  		info:           fn.info,      //  } empty for non-created packages
   100  		goversion:      fn.goversion, // /
   101  		build:          build,
   102  		topLevelOrigin: fn,
   103  		pos:            obj.Pos(),
   104  		Pkg:            nil,
   105  		Prog:           fn.Prog,
   106  		typeparams:     fn.typeparams, // share with origin
   107  		typeargs:       targs,
   108  		subst:          subst,
   109  	}
   110  	cr.Add(instance)
   111  	return instance
   112  }
   113  
   114  // isParameterized reports whether any of the specified types contains
   115  // a free type parameter. It is safe to call concurrently.
   116  func (prog *Program) isParameterized(ts ...types.Type) bool {
   117  	prog.hasParamsMu.Lock()
   118  	defer prog.hasParamsMu.Unlock()
   119  
   120  	// TODO(adonovan): profile. If this operation is expensive,
   121  	// handle the most common but shallow cases such as T, pkg.T,
   122  	// *T without consulting the cache under the lock.
   123  
   124  	for _, t := range ts {
   125  		if prog.hasParams.Has(t) {
   126  			return true
   127  		}
   128  	}
   129  	return false
   130  }
   131  

View as plain text