github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/instantiate.go (about)

     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/ast"
    10  	"go/types"
    11  
    12  	"github.com/powerman/golang-tools/internal/typeparams"
    13  )
    14  
    15  // Instances returns all of the instances generated by runtime types for this function in an unspecified order.
    16  //
    17  // Thread-safe.
    18  //
    19  // This is an experimental interface! It may change without warning.
    20  func (prog *Program) _Instances(fn *Function) []*Function {
    21  	if len(fn._TypeParams) == 0 {
    22  		return nil
    23  	}
    24  
    25  	prog.methodsMu.Lock()
    26  	defer prog.methodsMu.Unlock()
    27  	return prog.instances[fn].list()
    28  }
    29  
    30  // A set of instantiations of a generic function fn.
    31  type instanceSet struct {
    32  	fn        *Function               // len(fn._TypeParams) > 0 and len(fn._TypeArgs) == 0.
    33  	instances map[*typeList]*Function // canonical type arguments to an instance.
    34  	syntax    *ast.FuncDecl           // fn.syntax copy for instantiating after fn is done. nil on synthetic packages.
    35  	info      *types.Info             // fn.pkg.info copy for building after fn is done.. nil on synthetic packages.
    36  
    37  	// TODO(taking): Consider ways to allow for clearing syntax and info when done building.
    38  	// May require a public API change as MethodValue can request these be built after prog.Build() is done.
    39  }
    40  
    41  func (insts *instanceSet) list() []*Function {
    42  	if insts == nil {
    43  		return nil
    44  	}
    45  
    46  	fns := make([]*Function, 0, len(insts.instances))
    47  	for _, fn := range insts.instances {
    48  		fns = append(fns, fn)
    49  	}
    50  	return fns
    51  }
    52  
    53  // createInstanceSet adds a new instanceSet for a generic function fn if one does not exist.
    54  //
    55  // Precondition: fn is a package level declaration (function or method).
    56  //
    57  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu)
    58  //
    59  func (prog *Program) createInstanceSet(fn *Function) {
    60  	assert(len(fn._TypeParams) > 0 && len(fn._TypeArgs) == 0, "Can only create instance sets for generic functions")
    61  
    62  	prog.methodsMu.Lock()
    63  	defer prog.methodsMu.Unlock()
    64  
    65  	syntax, _ := fn.syntax.(*ast.FuncDecl)
    66  	assert((syntax == nil) == (fn.syntax == nil), "fn.syntax is either nil or a *ast.FuncDecl")
    67  
    68  	if _, ok := prog.instances[fn]; !ok {
    69  		prog.instances[fn] = &instanceSet{
    70  			fn:     fn,
    71  			syntax: syntax,
    72  			info:   fn.info,
    73  		}
    74  	}
    75  }
    76  
    77  // needsInstance returns an Function that that is the instantiation of fn with the type arguments targs.
    78  //
    79  // Any CREATEd instance is added to cr.
    80  //
    81  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu)
    82  func (prog *Program) needsInstance(fn *Function, targs []types.Type, cr *creator) *Function {
    83  	prog.methodsMu.Lock()
    84  	defer prog.methodsMu.Unlock()
    85  
    86  	return prog.instances[fn].lookupOrCreate(targs, cr)
    87  }
    88  
    89  // lookupOrCreate returns the instantiation of insts.fn using targs.
    90  // If the instantiation is reported, this is added to cr.
    91  //
    92  func (insts *instanceSet) lookupOrCreate(targs []types.Type, cr *creator) *Function {
    93  	if insts.instances == nil {
    94  		insts.instances = make(map[*typeList]*Function)
    95  	}
    96  
    97  	// canonicalize on a tuple of targs. Sig is not unique.
    98  	//
    99  	// func A[T any]() {
   100  	//   var x T
   101  	//   fmt.Println("%T", x)
   102  	// }
   103  	key := insts.fn.Prog.canon.List(targs)
   104  	if inst, ok := insts.instances[key]; ok {
   105  		return inst
   106  	}
   107  	instance := createInstance(insts.fn, targs, insts.info, insts.syntax, cr)
   108  
   109  	// TODO(taking): Allow for the function to be built after monomorphization is supported.
   110  	instance.syntax = nil // treat instance as an external function to prevent building.
   111  
   112  	insts.instances[key] = instance
   113  	return instance
   114  }
   115  
   116  // createInstance returns an CREATEd instantiation of fn using targs.
   117  //
   118  // Function is added to cr.
   119  //
   120  func createInstance(fn *Function, targs []types.Type, info *types.Info, syntax ast.Node, cr *creator) *Function {
   121  	prog := fn.Prog
   122  	var sig *types.Signature
   123  	var obj *types.Func
   124  	if recv := fn.Signature.Recv(); recv != nil {
   125  		// method
   126  		// instantiates m with targs and returns a canonical representative for this method.
   127  		m := fn.object.(*types.Func)
   128  		recv := recvType(m)
   129  		if p, ok := recv.(*types.Pointer); ok {
   130  			recv = p.Elem()
   131  		}
   132  		named := recv.(*types.Named)
   133  		inst, err := typeparams.Instantiate(prog.ctxt, typeparams.NamedTypeOrigin(named), targs, false)
   134  		if err != nil {
   135  			panic(err)
   136  		}
   137  		canon, _, _ := types.LookupFieldOrMethod(prog.canon.Type(inst), true, m.Pkg(), m.Name())
   138  		obj = canon.(*types.Func)
   139  		sig = obj.Type().(*types.Signature)
   140  	} else {
   141  		instSig, err := typeparams.Instantiate(prog.ctxt, fn.Signature, targs, false)
   142  		if err != nil {
   143  			panic(err)
   144  		}
   145  		instance, ok := instSig.(*types.Signature)
   146  		if !ok {
   147  			panic("Instantiate of a Signature returned a non-signature")
   148  		}
   149  		obj = fn.object.(*types.Func) // instantiation does not exist yet
   150  		sig = prog.canon.Type(instance).(*types.Signature)
   151  	}
   152  
   153  	name := fmt.Sprintf("%s[%s]", fn.Name(), targs) // may not be unique
   154  	synthetic := fmt.Sprintf("instantiation of %s", fn.Name())
   155  	instance := &Function{
   156  		name:        name,
   157  		object:      obj,
   158  		Signature:   sig,
   159  		Synthetic:   synthetic,
   160  		syntax:      syntax, // on synthetic packages syntax is nil.
   161  		_Origin:     fn,
   162  		pos:         obj.Pos(),
   163  		Pkg:         nil,
   164  		Prog:        fn.Prog,
   165  		_TypeParams: fn._TypeParams,
   166  		_TypeArgs:   targs,
   167  		info:        info, // on synthetic packages info is nil.
   168  		subst:       makeSubster(prog.ctxt, fn._TypeParams, targs, false),
   169  	}
   170  	cr.Add(instance)
   171  	return instance
   172  }