1
2
3
4
5 package walk
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/typecheck"
11 "cmd/compile/internal/types"
12 "cmd/internal/src"
13 )
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 func directClosureCall(n *ir.CallExpr) {
33 clo := n.Fun.(*ir.ClosureExpr)
34 clofn := clo.Func
35
36 if ir.IsTrivialClosure(clo) {
37 return
38 }
39
40
41 var params []*types.Field
42 var decls []*ir.Name
43 for _, v := range clofn.ClosureVars {
44 if !v.Byval() {
45
46
47
48
49
50 addr := ir.NewNameAt(clofn.Pos(), typecheck.Lookup("&"+v.Sym().Name), types.NewPtr(v.Type()))
51 addr.Curfn = clofn
52 v.Heapaddr = addr
53 v = addr
54 }
55
56 v.Class = ir.PPARAM
57 decls = append(decls, v)
58
59 fld := types.NewField(src.NoXPos, v.Sym(), v.Type())
60 fld.Nname = v
61 params = append(params, fld)
62 }
63
64
65 f := clofn.Nname
66 typ := f.Type()
67
68
69
70 typ = types.NewSignature(nil, append(params, typ.Params()...), typ.Results())
71 f.SetType(typ)
72 clofn.Dcl = append(decls, clofn.Dcl...)
73
74
75 n.Fun = f
76 n.Args.Prepend(closureArgs(clo)...)
77
78
79
80
81
82 if typ.NumResults() == 1 {
83 n.SetType(typ.Result(0).Type)
84 } else {
85 n.SetType(typ.ResultsTuple())
86 }
87
88
89
90
91
92 ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
93 }
94
95 func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
96 clofn := clo.Func
97
98
99 if ir.IsTrivialClosure(clo) {
100 if base.Debug.Closure > 0 {
101 base.WarnfAt(clo.Pos(), "closure converted to global")
102 }
103 return clofn.Nname
104 }
105
106
107 ir.ClosureDebugRuntimeCheck(clo)
108 clofn.SetNeedctxt(true)
109
110
111
112
113
114
115 if !clofn.Walked() {
116 clofn.SetWalked(true)
117 ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
118 }
119
120 typ := typecheck.ClosureType(clo)
121
122 clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, typ, nil)
123 clos.SetEsc(clo.Esc())
124 clos.List = append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, clofn.Nname)}, closureArgs(clo)...)
125 for i, value := range clos.List {
126 clos.List[i] = ir.NewStructKeyExpr(base.Pos, typ.Field(i), value)
127 }
128
129 addr := typecheck.NodAddr(clos)
130 addr.SetEsc(clo.Esc())
131
132
133 cfn := typecheck.ConvNop(addr, clo.Type())
134
135
136 if x := clo.Prealloc; x != nil {
137 if !types.Identical(typ, x.Type()) {
138 panic("closure type does not match order's assigned type")
139 }
140 addr.Prealloc = x
141 clo.Prealloc = nil
142 }
143
144 return walkExpr(cfn, init)
145 }
146
147
148
149
150
151
152 func closureArgs(clo *ir.ClosureExpr) []ir.Node {
153 fn := clo.Func
154
155 args := make([]ir.Node, len(fn.ClosureVars))
156 for i, v := range fn.ClosureVars {
157 var outer ir.Node
158 outer = v.Outer
159 if !v.Byval() {
160 outer = typecheck.NodAddrAt(fn.Pos(), outer)
161 }
162 args[i] = typecheck.Expr(outer)
163 }
164 return args
165 }
166
167 func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
168
169
170
171
172
173
174
175 if n.X.Type().IsInterface() {
176
177
178 n.X = cheapExpr(n.X, init)
179 n.X = walkExpr(n.X, nil)
180
181 tab := ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X)
182 check := ir.NewUnaryExpr(base.Pos, ir.OCHECKNIL, tab)
183 init.Append(typecheck.Stmt(check))
184 }
185
186 typ := typecheck.MethodValueType(n)
187
188 clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, typ, nil)
189 clos.SetEsc(n.Esc())
190 clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, methodValueWrapper(n)), n.X}
191
192 addr := typecheck.NodAddr(clos)
193 addr.SetEsc(n.Esc())
194
195
196 cfn := typecheck.ConvNop(addr, n.Type())
197
198
199 if x := n.Prealloc; x != nil {
200 if !types.Identical(typ, x.Type()) {
201 panic("partial call type does not match order's assigned type")
202 }
203 addr.Prealloc = x
204 n.Prealloc = nil
205 }
206
207 return walkExpr(cfn, init)
208 }
209
210
211
212
213
214 func methodValueWrapper(dot *ir.SelectorExpr) *ir.Name {
215 if dot.Op() != ir.OMETHVALUE {
216 base.Fatalf("methodValueWrapper: unexpected %v (%v)", dot, dot.Op())
217 }
218
219 meth := dot.Sel
220 rcvrtype := dot.X.Type()
221 sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
222
223 if sym.Uniq() {
224 return sym.Def.(*ir.Name)
225 }
226 sym.SetUniq(true)
227
228 base.FatalfAt(dot.Pos(), "missing wrapper for %v", meth)
229 panic("unreachable")
230 }
231
View as plain text