...

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/ast"
    10  	"go/types"
    11  
    12  	"golang.org/x/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 fn.typeparams.Len() == 0 || len(fn.typeargs) > 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               // fn.typeparams.Len() > 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  func (prog *Program) createInstanceSet(fn *Function) {
    59  	assert(fn.typeparams.Len() > 0 && len(fn.typeargs) == 0, "Can only create instance sets for generic functions")
    60  
    61  	prog.methodsMu.Lock()
    62  	defer prog.methodsMu.Unlock()
    63  
    64  	syntax, _ := fn.syntax.(*ast.FuncDecl)
    65  	assert((syntax == nil) == (fn.syntax == nil), "fn.syntax is either nil or a *ast.FuncDecl")
    66  
    67  	if _, ok := prog.instances[fn]; !ok {
    68  		prog.instances[fn] = &instanceSet{
    69  			fn:     fn,
    70  			syntax: syntax,
    71  			info:   fn.info,
    72  		}
    73  	}
    74  }
    75  
    76  // needsInstance returns a Function that is the instantiation of fn with the type arguments targs.
    77  //
    78  // Any CREATEd instance is added to cr.
    79  //
    80  // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu)
    81  func (prog *Program) needsInstance(fn *Function, targs []types.Type, cr *creator) *Function {
    82  	prog.methodsMu.Lock()
    83  	defer prog.methodsMu.Unlock()
    84  
    85  	return prog.lookupOrCreateInstance(fn, targs, cr)
    86  }
    87  
    88  // lookupOrCreateInstance returns a Function that is the instantiation of fn with the type arguments targs.
    89  //
    90  // Any CREATEd instance is added to cr.
    91  //
    92  // EXCLUSIVE_LOCKS_REQUIRED(prog.methodMu)
    93  func (prog *Program) lookupOrCreateInstance(fn *Function, targs []types.Type, cr *creator) *Function {
    94  	return prog.instances[fn].lookupOrCreate(targs, &prog.parameterized, cr)
    95  }
    96  
    97  // lookupOrCreate returns the instantiation of insts.fn using targs.
    98  // If the instantiation is created, this is added to cr.
    99  func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWalker, cr *creator) *Function {
   100  	if insts.instances == nil {
   101  		insts.instances = make(map[*typeList]*Function)
   102  	}
   103  
   104  	fn := insts.fn
   105  	prog := fn.Prog
   106  
   107  	// canonicalize on a tuple of targs. Sig is not unique.
   108  	//
   109  	// func A[T any]() {
   110  	//   var x T
   111  	//   fmt.Println("%T", x)
   112  	// }
   113  	key := prog.canon.List(targs)
   114  	if inst, ok := insts.instances[key]; ok {
   115  		return inst
   116  	}
   117  
   118  	// CREATE instance/instantiation wrapper
   119  	var syntax ast.Node
   120  	if insts.syntax != nil {
   121  		syntax = insts.syntax
   122  	}
   123  
   124  	var sig *types.Signature
   125  	var obj *types.Func
   126  	if recv := fn.Signature.Recv(); recv != nil {
   127  		// method
   128  		m := fn.object.(*types.Func)
   129  		obj = prog.canon.instantiateMethod(m, targs, prog.ctxt)
   130  		sig = obj.Type().(*types.Signature)
   131  	} else {
   132  		instSig, err := typeparams.Instantiate(prog.ctxt, fn.Signature, targs, false)
   133  		if err != nil {
   134  			panic(err)
   135  		}
   136  		instance, ok := instSig.(*types.Signature)
   137  		if !ok {
   138  			panic("Instantiate of a Signature returned a non-signature")
   139  		}
   140  		obj = fn.object.(*types.Func) // instantiation does not exist yet
   141  		sig = prog.canon.Type(instance).(*types.Signature)
   142  	}
   143  
   144  	var synthetic string
   145  	var subst *subster
   146  
   147  	concrete := !parameterized.anyParameterized(targs)
   148  
   149  	if prog.mode&InstantiateGenerics != 0 && concrete {
   150  		synthetic = fmt.Sprintf("instance of %s", fn.Name())
   151  		subst = makeSubster(prog.ctxt, fn.typeparams, targs, false)
   152  	} else {
   153  		synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name())
   154  	}
   155  
   156  	name := fmt.Sprintf("%s%s", fn.Name(), targs) // may not be unique
   157  	instance := &Function{
   158  		name:           name,
   159  		object:         obj,
   160  		Signature:      sig,
   161  		Synthetic:      synthetic,
   162  		syntax:         syntax,
   163  		topLevelOrigin: fn,
   164  		pos:            obj.Pos(),
   165  		Pkg:            nil,
   166  		Prog:           fn.Prog,
   167  		typeparams:     fn.typeparams, // share with origin
   168  		typeargs:       targs,
   169  		info:           insts.info, // on synthetic packages info is nil.
   170  		subst:          subst,
   171  	}
   172  
   173  	cr.Add(instance)
   174  	insts.instances[key] = instance
   175  	return instance
   176  }
   177  

View as plain text