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 !clofn.IsClosure() {
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 ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
92 }
93
94 func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
95 clofn := clo.Func
96
97
98 if !clofn.IsClosure() {
99 if base.Debug.Closure > 0 {
100 base.WarnfAt(clo.Pos(), "closure converted to global")
101 }
102 return clofn.Nname
103 }
104
105
106 ir.ClosureDebugRuntimeCheck(clo)
107 clofn.SetNeedctxt(true)
108
109
110
111
112
113
114 if !clofn.Walked() {
115 clofn.SetWalked(true)
116 ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
117 }
118
119 typ := typecheck.ClosureType(clo)
120
121 clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, typ, nil)
122 clos.SetEsc(clo.Esc())
123 clos.List = append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, clofn.Nname)}, closureArgs(clo)...)
124 for i, value := range clos.List {
125 clos.List[i] = ir.NewStructKeyExpr(base.Pos, typ.Field(i), value)
126 }
127
128 addr := typecheck.NodAddr(clos)
129 addr.SetEsc(clo.Esc())
130
131
132 cfn := typecheck.ConvNop(addr, clo.Type())
133
134
135 if x := clo.Prealloc; x != nil {
136 if !types.Identical(typ, x.Type()) {
137 panic("closure type does not match order's assigned type")
138 }
139 addr.Prealloc = x
140 clo.Prealloc = nil
141 }
142
143 return walkExpr(cfn, init)
144 }
145
146
147
148
149
150
151 func closureArgs(clo *ir.ClosureExpr) []ir.Node {
152 fn := clo.Func
153
154 args := make([]ir.Node, len(fn.ClosureVars))
155 for i, v := range fn.ClosureVars {
156 var outer ir.Node
157 outer = v.Outer
158 if !v.Byval() {
159 outer = typecheck.NodAddrAt(fn.Pos(), outer)
160 }
161 args[i] = typecheck.Expr(outer)
162 }
163 return args
164 }
165
166 func walkMethodValue(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
167
168
169
170
171
172
173
174 if n.X.Type().IsInterface() {
175
176
177 n.X = cheapExpr(n.X, init)
178 n.X = walkExpr(n.X, nil)
179
180 tab := ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X)
181 check := ir.NewUnaryExpr(base.Pos, ir.OCHECKNIL, tab)
182 init.Append(typecheck.Stmt(check))
183 }
184
185 typ := typecheck.MethodValueType(n)
186
187 clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, typ, nil)
188 clos.SetEsc(n.Esc())
189 clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, methodValueWrapper(n)), n.X}
190
191 addr := typecheck.NodAddr(clos)
192 addr.SetEsc(n.Esc())
193
194
195 cfn := typecheck.ConvNop(addr, n.Type())
196
197
198 if x := n.Prealloc; x != nil {
199 if !types.Identical(typ, x.Type()) {
200 panic("partial call type does not match order's assigned type")
201 }
202 addr.Prealloc = x
203 n.Prealloc = nil
204 }
205
206 return walkExpr(cfn, init)
207 }
208
209
210
211
212
213 func methodValueWrapper(dot *ir.SelectorExpr) *ir.Name {
214 if dot.Op() != ir.OMETHVALUE {
215 base.Fatalf("methodValueWrapper: unexpected %v (%v)", dot, dot.Op())
216 }
217
218 meth := dot.Sel
219 rcvrtype := dot.X.Type()
220 sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
221
222 if sym.Uniq() {
223 return sym.Def.(*ir.Name)
224 }
225 sym.SetUniq(true)
226
227 base.FatalfAt(dot.Pos(), "missing wrapper for %v", meth)
228 panic("unreachable")
229 }
230
View as plain text