src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

instantiate.go (4785B)


      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 	"slices"
     11 	"sync"
     12 )
     13 
     14 // A generic records information about a generic origin function,
     15 // including a cache of existing instantiations.
     16 type generic struct {
     17 	instancesMu sync.Mutex
     18 	instances   map[*typeList]*Function // canonical type arguments to an instance.
     19 }
     20 
     21 // instance returns a Function that is the instantiation of generic
     22 // origin function fn with the type arguments rtargs and targs.
     23 //
     24 // Any created instance is added to cr.
     25 //
     26 // Acquires fn.generic.instancesMu.
     27 func (fn *Function) instance(rtargs, targs []types.Type, b *builder) *Function {
     28 	key := fn.Prog.canon.List(slices.Concat(rtargs, targs))
     29 
     30 	gen := fn.generic
     31 
     32 	gen.instancesMu.Lock()
     33 	defer gen.instancesMu.Unlock()
     34 	inst, ok := gen.instances[key]
     35 	if !ok {
     36 		inst = createInstance(fn, rtargs, targs)
     37 		inst.buildshared = b.shared()
     38 		b.enqueue(inst)
     39 
     40 		if gen.instances == nil {
     41 			gen.instances = make(map[*typeList]*Function)
     42 		}
     43 		gen.instances[key] = inst
     44 	} else {
     45 		b.waitForSharedFunction(inst)
     46 	}
     47 	return inst
     48 }
     49 
     50 // createInstance returns the instantiation of generic function fn using targs.
     51 // If fn is a method on a generic type, fn's receiver type will be instantiated
     52 // using rtargs.
     53 //
     54 // Requires fn.generic.instancesMu.
     55 func createInstance(fn *Function, rtargs, targs []types.Type) *Function {
     56 	prog := fn.Prog
     57 
     58 	// Compute signature.
     59 	var sig *types.Signature
     60 	var obj *types.Func
     61 	if recv := fn.Signature.Recv(); recv != nil {
     62 		// method, len(rtargs) > 0 || len(targs) > 0
     63 		if len(rtargs) > 0 {
     64 			// possibly generic method on generic type
     65 			obj = prog.canon.instantiateMethod(fn.object, rtargs, prog.ctxt)
     66 		} else {
     67 			// generic method on non-generic type
     68 			obj = fn.object // instantiation does not exist yet
     69 		}
     70 		if len(targs) > 0 {
     71 			// generic method
     72 			instSig, err := types.Instantiate(prog.ctxt, obj.Signature(), targs, false)
     73 			if err != nil {
     74 				panic(err)
     75 			}
     76 			instance, ok := instSig.(*types.Signature)
     77 			if !ok {
     78 				panic("Instantiate of a Signature returned a non-signature")
     79 			}
     80 			// Do not canonicalize generic methods, because the receiver is not
     81 			// part of a Signature's type identity. For example,
     82 			// (*G[int]).m[int] and (G[int]).n[int] may be identical types even
     83 			// though their receiver types differ.
     84 			sig = instance
     85 		} else {
     86 			// non-generic method on generic type
     87 			sig = obj.Signature()
     88 		}
     89 	} else {
     90 		// function, len(rtargs) == 0 && len(targs) > 0
     91 		instSig, err := types.Instantiate(prog.ctxt, fn.Signature, targs, false)
     92 		if err != nil {
     93 			panic(err)
     94 		}
     95 		instance, ok := instSig.(*types.Signature)
     96 		if !ok {
     97 			panic("Instantiate of a Signature returned a non-signature")
     98 		}
     99 		obj = fn.object // instantiation does not exist yet
    100 		sig = prog.canon.Type(instance).(*types.Signature)
    101 	}
    102 
    103 	// Choose strategy (instance or wrapper).
    104 	var (
    105 		synthetic string
    106 		subst     *subster
    107 		build     buildFunc
    108 	)
    109 	if prog.mode&InstantiateGenerics != 0 && !prog.isParameterized(slices.Concat(rtargs, targs)...) {
    110 		synthetic = fmt.Sprintf("instance of %s", fn.Name())
    111 		if fn.syntax != nil {
    112 			subst = makeSubster(prog.ctxt, obj, fn.recvtypeparams, rtargs, fn.typeparams, targs)
    113 			build = (*builder).buildFromSyntax
    114 		} else {
    115 			build = (*builder).buildParamsOnly
    116 		}
    117 	} else {
    118 		synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name())
    119 		build = (*builder).buildInstantiationWrapper
    120 	}
    121 
    122 	name := fn.Name()
    123 	if len(targs) > 0 {
    124 		name = fmt.Sprintf("%s%s", name, targstr(targs)) // may not be unique
    125 	}
    126 
    127 	/* generic instance or instantiation wrapper */
    128 	return &Function{
    129 		name:           name,
    130 		object:         obj,
    131 		Signature:      sig,
    132 		Synthetic:      synthetic,
    133 		syntax:         fn.syntax,    // \
    134 		info:           fn.info,      //  } empty for non-created packages
    135 		goversion:      fn.goversion, // /
    136 		build:          build,
    137 		topLevelOrigin: fn,
    138 		pos:            obj.Pos(),
    139 		Pkg:            nil,
    140 		Prog:           fn.Prog,
    141 		recvtypeparams: fn.recvtypeparams, // share with origin
    142 		recvtypeargs:   rtargs,
    143 		typeparams:     fn.typeparams, // share with origin
    144 		typeargs:       targs,
    145 		subst:          subst,
    146 	}
    147 }
    148 
    149 // isParameterized reports whether any of the specified types contains
    150 // a free type parameter. It is safe to call concurrently.
    151 func (prog *Program) isParameterized(ts ...types.Type) bool {
    152 	prog.hasParamsMu.Lock()
    153 	defer prog.hasParamsMu.Unlock()
    154 
    155 	// TODO(adonovan): profile. If this operation is expensive,
    156 	// handle the most common but shallow cases such as T, pkg.T,
    157 	// *T without consulting the cache under the lock.
    158 
    159 	return slices.ContainsFunc(ts, prog.hasParams.Has)
    160 }