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.X.(*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))
51 addr.Curfn = clofn
52 addr.SetType(types.NewPtr(v.Type()))
53 v.Heapaddr = addr
54 v = addr
55 }
56
57 v.Class = ir.PPARAM
58 decls = append(decls, v)
59
60 fld := types.NewField(src.NoXPos, v.Sym(), v.Type())
61 fld.Nname = v
62 params = append(params, fld)
63 }
64
65
66 f := clofn.Nname
67 typ := f.Type()
68
69
70
71 typ = types.NewSignature(typ.Pkg(), nil, nil, append(params, typ.Params().FieldSlice()...), typ.Results().FieldSlice())
72 f.SetType(typ)
73 clofn.Dcl = append(decls, clofn.Dcl...)
74
75
76 n.X = f
77 n.Args.Prepend(closureArgs(clo)...)
78
79
80
81
82
83 if typ.NumResults() == 1 {
84 n.SetType(typ.Results().Field(0).Type)
85 } else {
86 n.SetType(typ.Results())
87 }
88
89
90
91
92
93 ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
94 }
95
96 func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
97 clofn := clo.Func
98
99
100 if ir.IsTrivialClosure(clo) {
101 if base.Debug.Closure > 0 {
102 base.WarnfAt(clo.Pos(), "closure converted to global")
103 }
104 return clofn.Nname
105 }
106
107
108 ir.ClosureDebugRuntimeCheck(clo)
109 clofn.SetNeedctxt(true)
110
111
112
113
114
115
116 if !clofn.Walked() {
117 clofn.SetWalked(true)
118 ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
119 }
120
121 typ := typecheck.ClosureType(clo)
122
123 clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
124 clos.SetEsc(clo.Esc())
125 clos.List = append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, clofn.Nname)}, closureArgs(clo)...)
126 for i, value := range clos.List {
127 clos.List[i] = ir.NewStructKeyExpr(base.Pos, typ.Field(i), value)
128 }
129
130 addr := typecheck.NodAddr(clos)
131 addr.SetEsc(clo.Esc())
132
133
134 cfn := typecheck.ConvNop(addr, clo.Type())
135
136
137 if x := clo.Prealloc; x != nil {
138 if !types.Identical(typ, x.Type()) {
139 panic("closure type does not match order's assigned type")
140 }
141 addr.Prealloc = x
142 clo.Prealloc = nil
143 }
144
145 return walkExpr(cfn, init)
146 }
147
148
149
150
151
152
153 func closureArgs(clo *ir.ClosureExpr) []ir.Node {
154 fn := clo.Func
155
156 args := make([]ir.Node, len(fn.ClosureVars))
157 for i, v := range fn.ClosureVars {
158 var outer ir.Node
159 outer = v.Outer
160 if !v.Byval() {
161 outer = typecheck.NodAddrAt(fn.Pos(), outer)
162 }
163 args[i] = typecheck.Expr(outer)
164 }
165 return args
166 }
167
168 func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
169
170
171
172
173
174
175
176 if n.X.Type().IsInterface() {
177
178
179 n.X = cheapExpr(n.X, init)
180 n.X = walkExpr(n.X, nil)
181
182 tab := ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X)
183 check := ir.NewUnaryExpr(base.Pos, ir.OCHECKNIL, tab)
184 init.Append(typecheck.Stmt(check))
185 }
186
187 typ := typecheck.MethodValueType(n)
188
189 clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
190 clos.SetEsc(n.Esc())
191 clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, methodValueWrapper(n)), n.X}
192
193 addr := typecheck.NodAddr(clos)
194 addr.SetEsc(n.Esc())
195
196
197 cfn := typecheck.ConvNop(addr, n.Type())
198
199
200 if x := n.Prealloc; x != nil {
201 if !types.Identical(typ, x.Type()) {
202 panic("partial call type does not match order's assigned type")
203 }
204 addr.Prealloc = x
205 n.Prealloc = nil
206 }
207
208 return walkExpr(cfn, init)
209 }
210
211
212
213
214
215 func methodValueWrapper(dot *ir.SelectorExpr) *ir.Name {
216 if dot.Op() != ir.OMETHVALUE {
217 base.Fatalf("methodValueWrapper: unexpected %v (%v)", dot, dot.Op())
218 }
219
220 t0 := dot.Type()
221 meth := dot.Sel
222 rcvrtype := dot.X.Type()
223 sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
224
225 if sym.Uniq() {
226 return sym.Def.(*ir.Name)
227 }
228 sym.SetUniq(true)
229
230 if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 {
231 base.FatalfAt(dot.Pos(), "missing wrapper for %v", meth)
232 }
233
234 savecurfn := ir.CurFunc
235 saveLineNo := base.Pos
236 ir.CurFunc = nil
237
238 base.Pos = base.AutogeneratedPos
239
240 tfn := ir.NewFuncType(base.Pos, nil,
241 typecheck.NewFuncParams(t0.Params(), true),
242 typecheck.NewFuncParams(t0.Results(), false))
243
244 fn := typecheck.DeclFunc(sym, tfn)
245 fn.SetDupok(true)
246 fn.SetWrapper(true)
247
248
249 ptr := ir.NewHiddenParam(base.Pos, fn, typecheck.Lookup(".this"), rcvrtype)
250
251 call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
252 call.Args = ir.ParamNames(tfn.Type())
253 call.IsDDD = tfn.Type().IsVariadic()
254
255 var body ir.Node = call
256 if t0.NumResults() != 0 {
257 ret := ir.NewReturnStmt(base.Pos, nil)
258 ret.Results = []ir.Node{call}
259 body = ret
260 }
261
262 fn.Body = []ir.Node{body}
263 typecheck.FinishFuncBody()
264
265 typecheck.Func(fn)
266
267
268 ir.CurFunc = fn
269 typecheck.Stmts(fn.Body)
270 sym.Def = fn.Nname
271 typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
272 ir.CurFunc = savecurfn
273 base.Pos = saveLineNo
274
275 return fn.Nname
276 }
277
View as plain text