GoPLS Viewer

Home|gopls/go/ssa/instantiate.go
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
5package ssa
6
7import (
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.
20func (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.
31type 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
41func (insts *instanceSetlist() []*Function {
42    if insts == nil {
43        return nil
44    }
45
46    fns := make([]*Function0len(insts.instances))
47    for _fn := range insts.instances {
48        fns = append(fnsfn)
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)
58func (prog *ProgramcreateInstanceSet(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            syntaxsyntax,
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)
81func (prog *ProgramneedsInstance(fn *Functiontargs []types.Typecr *creator) *Function {
82    prog.methodsMu.Lock()
83    defer prog.methodsMu.Unlock()
84
85    return prog.lookupOrCreateInstance(fntargscr)
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)
93func (prog *ProgramlookupOrCreateInstance(fn *Functiontargs []types.Typecr *creator) *Function {
94    return prog.instances[fn].lookupOrCreate(targs, &prog.parameterizedcr)
95}
96
97// lookupOrCreate returns the instantiation of insts.fn using targs.
98// If the instantiation is created, this is added to cr.
99func (insts *instanceSetlookupOrCreate(targs []types.Typeparameterized *tpWalkercr *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 instok := 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(mtargsprog.ctxt)
130        sig = obj.Type().(*types.Signature)
131    } else {
132        instSigerr := typeparams.Instantiate(prog.ctxtfn.Signaturetargsfalse)
133        if err != nil {
134            panic(err)
135        }
136        instanceok := 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.ctxtfn.typeparamstargsfalse)
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        topLevelOriginfn,
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
MembersX
instanceSet.instances
instanceSet.info
instanceSet.lookupOrCreate.insts
instanceSet.lookupOrCreate
instanceSet.lookupOrCreate.syntax
instanceSet.lookupOrCreate.recv
instanceSet.syntax
Program.needsInstance.fn
Program.needsInstance.cr
instanceSet.lookupOrCreate.prog
instanceSet.lookupOrCreate.subst
instanceSet.lookupOrCreate.instance
Program._Instances.fn
instanceSet
instanceSet.list.insts
instanceSet.list
Program.needsInstance.targs
Program.lookupOrCreateInstance
instanceSet.lookupOrCreate.obj
Program._Instances.prog
Program._Instances
instanceSet.lookupOrCreate.fn
instanceSet.fn
Program.createInstanceSet.fn
instanceSet.lookupOrCreate.cr
instanceSet.lookupOrCreate.key
instanceSet.lookupOrCreate.synthetic
instanceSet.list.RangeStmt_1496.fn
Program.lookupOrCreateInstance.prog
Program.lookupOrCreateInstance.fn
Program.lookupOrCreateInstance.targs
instanceSet.lookupOrCreate.sig
instanceSet.lookupOrCreate.BlockStmt.instSig
instanceSet.lookupOrCreate.BlockStmt.err
Program.createInstanceSet.prog
Program.needsInstance.prog
Program.lookupOrCreateInstance.cr
instanceSet.lookupOrCreate.parameterized
instanceSet.list.fns
Program.createInstanceSet
Program.needsInstance
instanceSet.lookupOrCreate.targs
instanceSet.lookupOrCreate.name
Members
X