Mercurial > projects > ddmd
annotate dmd/CallExp.d @ 130:60bb0fe4563e
dmdfe 2.037 first main iteration
author | Eldar Insafutdinov <e.insafutdinov@gmail.com> |
---|---|
date | Thu, 09 Sep 2010 22:51:44 +0100 |
parents | e28b18c23469 |
children | af1bebfd96a4 |
rev | line source |
---|---|
72 | 1 module dmd.CallExp; |
2 | |
114 | 3 import dmd.common; |
79 | 4 import dmd.ErrorExp; |
72 | 5 import dmd.Expression; |
6 import dmd.Cast; | |
7 import dmd.WANT; | |
8 import dmd.BUILTIN; | |
9 import dmd.TypeFunction; | |
10 import dmd.ScopeDsymbol; | |
11 import dmd.CastExp; | |
12 import dmd.GlobalExpressions; | |
13 import dmd.TypePointer; | |
14 import dmd.ThisExp; | |
15 import dmd.OverExp; | |
16 import dmd.Dsymbol; | |
17 import dmd.CSX; | |
18 import dmd.AggregateDeclaration; | |
19 import dmd.TypeDelegate; | |
20 import dmd.ClassDeclaration; | |
21 import dmd.DsymbolExp; | |
22 import dmd.DotExp; | |
23 import dmd.TemplateExp; | |
24 import dmd.TypeStruct; | |
25 import dmd.TypeClass; | |
26 import dmd.Identifier; | |
27 import dmd.Lexer; | |
28 import dmd.VarDeclaration; | |
29 import dmd.DeclarationExp; | |
30 import dmd.CtorDeclaration; | |
31 import dmd.PtrExp; | |
32 import dmd.TemplateDeclaration; | |
33 import dmd.StructLiteralExp; | |
34 import dmd.StructDeclaration; | |
35 import dmd.DotTemplateExp; | |
36 import dmd.CommaExp; | |
37 import dmd.AggregateDeclaration; | |
38 import dmd.FuncDeclaration; | |
39 import dmd.Type; | |
40 import dmd.ScopeExp; | |
41 import dmd.VarExp; | |
42 import dmd.STC; | |
43 import dmd.LINK; | |
44 import dmd.Global; | |
45 import dmd.DotTemplateInstanceExp; | |
46 import dmd.TemplateInstance; | |
47 import dmd.DelegateExp; | |
48 import dmd.IdentifierExp; | |
49 import dmd.DotVarExp; | |
50 import dmd.DotIdExp; | |
51 import dmd.TY; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
52 import dmd.TRUST; |
72 | 53 import dmd.Id; |
54 import dmd.TypeAArray; | |
55 import dmd.RemoveExp; | |
56 import dmd.backend.elem; | |
57 import dmd.UnaExp; | |
58 import dmd.InterState; | |
59 import dmd.OutBuffer; | |
60 import dmd.Loc; | |
61 import dmd.Scope; | |
62 import dmd.InlineCostState; | |
63 import dmd.IRState; | |
64 import dmd.InlineDoState; | |
65 import dmd.HdrGenState; | |
66 import dmd.InlineScanState; | |
67 import dmd.ArrayTypes; | |
68 import dmd.TOK; | |
69 import dmd.PREC; | |
70 import dmd.expression.Util; | |
71 import dmd.backend.Symbol; | |
72 import dmd.backend.TYPE; | |
73 import dmd.backend.Util; | |
74 import dmd.backend.TYM; | |
75 import dmd.codegen.Util; | |
76 | |
77 import std.stdio; | |
78 | |
0 | 79 class CallExp : UnaExp |
80 { | |
81 Expressions arguments; | |
82 | |
83 this(Loc loc, Expression e, Expressions exps) | |
84 { | |
72 | 85 super(loc, TOK.TOKcall, CallExp.sizeof, e); |
0 | 86 this.arguments = exps; |
87 } | |
88 | |
89 this(Loc loc, Expression e) | |
90 { | |
91 super(loc, TOK.TOKcall, CallExp.sizeof, e); | |
92 } | |
93 | |
94 this(Loc loc, Expression e, Expression earg1) | |
95 { | |
72 | 96 super(loc, TOK.TOKcall, CallExp.sizeof, e); |
97 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
98 auto arguments = new Expressions(); |
96 | 99 if (earg1) |
73 | 100 { |
101 arguments.setDim(1); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
102 arguments[0] = earg1; |
73 | 103 } |
0 | 104 this.arguments = arguments; |
105 } | |
106 | |
107 this(Loc loc, Expression e, Expression earg1, Expression earg2) | |
72 | 108 { |
109 super(loc, TOK.TOKcall, CallExp.sizeof, e); | |
66 | 110 |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
111 auto arguments = new Expressions(); |
72 | 112 arguments.setDim(2); |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
113 arguments[0] = earg1; |
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
114 arguments[1] = earg2; |
72 | 115 |
66 | 116 this.arguments = arguments; |
0 | 117 } |
118 | |
72 | 119 override Expression syntaxCopy() |
0 | 120 { |
121 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); | |
122 } | |
123 | |
72 | 124 override Expression semantic(Scope sc) |
125 { | |
126 TypeFunction tf; | |
127 FuncDeclaration f; | |
128 Type t1; | |
129 int istemp; | |
130 Objects targsi; // initial list of template arguments | |
131 TemplateInstance tierror; | |
132 | |
79 | 133 version (LOGSEMANTIC) |
134 { | |
72 | 135 printf("CallExp.semantic() %s\n", toChars()); |
136 } | |
137 if (type) | |
138 return this; // semantic() already run | |
139 | |
79 | 140 static if (false) |
141 { | |
72 | 142 if (arguments && arguments.dim) |
143 { | |
144 Expression earg = cast(Expression)arguments.data[0]; | |
145 earg.print(); | |
146 if (earg.type) earg.type.print(); | |
147 } | |
148 } | |
149 | |
150 if (e1.op == TOK.TOKdelegate) | |
151 { | |
152 DelegateExp de = cast(DelegateExp)e1; | |
153 | |
154 e1 = new DotVarExp(de.loc, de.e1, de.func); | |
155 return semantic(sc); | |
156 } | |
157 | |
158 /* Transform: | |
159 * array.id(args) into .id(array,args) | |
160 * aa.remove(arg) into delete aa[arg] | |
161 */ | |
162 if (e1.op == TOK.TOKdot) | |
163 { | |
164 // BUG: we should handle array.a.b.c.e(args) too | |
165 | |
166 DotIdExp dotid = cast(DotIdExp)(e1); | |
167 dotid.e1 = dotid.e1.semantic(sc); | |
168 assert(dotid.e1); | |
169 if (dotid.e1.type) | |
170 { | |
171 TY e1ty = dotid.e1.type.toBasetype().ty; | |
172 if (e1ty == TY.Taarray && dotid.ident == Id.remove) | |
173 { | |
174 if (!arguments || arguments.dim != 1) | |
175 { | |
176 error("expected key as argument to aa.remove()"); | |
177 goto Lagain; | |
178 } | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
179 auto key = arguments[0]; |
72 | 180 key = key.semantic(sc); |
181 key = resolveProperties(sc, key); | |
182 key.rvalue(); | |
183 | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
184 auto taa = cast(TypeAArray)dotid.e1.type.toBasetype(); |
72 | 185 key = key.implicitCastTo(sc, taa.index); |
186 | |
187 return new RemoveExp(loc, dotid.e1, key); | |
188 } | |
109 | 189 else if (e1ty == TY.Tarray || e1ty == TY.Tsarray || |
190 (e1ty == Taarray && dotid.ident != Id.apply && dotid.ident != Id.applyReverse)) | |
72 | 191 { |
192 if (!arguments) | |
193 arguments = new Expressions(); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
194 arguments.shift(dotid.e1); |
72 | 195 version (DMDV2) { |
196 e1 = new DotIdExp(dotid.loc, new IdentifierExp(dotid.loc, Id.empty), dotid.ident); | |
197 } else { | |
198 e1 = new IdentifierExp(dotid.loc, dotid.ident); | |
199 } | |
200 } | |
201 } | |
202 } | |
203 | |
204 static if (true) { | |
205 /* This recognizes: | |
206 * foo!(tiargs)(funcargs) | |
207 */ | |
208 if (e1.op == TOK.TOKimport && !e1.type) | |
209 { | |
210 ScopeExp se = cast(ScopeExp)e1; | |
211 TemplateInstance ti = se.sds.isTemplateInstance(); | |
212 if (ti && !ti.semanticRun) | |
213 { | |
214 /* Attempt to instantiate ti. If that works, go with it. | |
215 * If not, go with partial explicit specialization. | |
216 */ | |
217 ti.semanticTiargs(sc); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
218 if (ti.needsTypeInference(sc)) |
72 | 219 { |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
220 /* Go with partial explicit specialization |
72 | 221 */ |
222 targsi = ti.tiargs; | |
223 tierror = ti; // for error reporting | |
224 e1 = new IdentifierExp(loc, ti.name); | |
225 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
226 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
227 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
228 ti.semantic(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
229 } |
72 | 230 } |
231 } | |
232 | |
233 /* This recognizes: | |
234 * expr.foo!(tiargs)(funcargs) | |
235 */ | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
236 Ldotti: |
72 | 237 if (e1.op == TOK.TOKdotti && !e1.type) |
238 { | |
239 DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)e1; | |
240 TemplateInstance ti = se.ti; | |
241 if (!ti.semanticRun) | |
242 { | |
243 /* Attempt to instantiate ti. If that works, go with it. | |
244 * If not, go with partial explicit specialization. | |
245 */ | |
246 ti.semanticTiargs(sc); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
247 static if (false) { |
72 | 248 Expression etmp = e1.trySemantic(sc); |
249 if (etmp) | |
250 e1 = etmp; // it worked | |
251 else // didn't work | |
252 { | |
253 targsi = ti.tiargs; | |
254 tierror = ti; // for error reporting | |
255 e1 = new DotIdExp(loc, se.e1, ti.name); | |
256 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
257 } else { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
258 if (!ti.tempdecl) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
259 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
260 se.getTempdecl(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
261 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
262 if (ti.tempdecl && ti.needsTypeInference(sc)) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
263 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
264 /* Go with partial explicit specialization |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
265 */ |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
266 targsi = ti.tiargs; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
267 tierror = ti; // for error reporting |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
268 e1 = new DotIdExp(loc, se.e1, ti.name); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
269 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
270 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
271 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
272 e1 = e1.semantic(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
273 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
274 } |
72 | 275 } |
276 } | |
277 } | |
278 | |
279 istemp = 0; | |
280 Lagain: | |
281 //printf("Lagain: %s\n", toChars()); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
282 //printf("test1 %s\n", toChars()); |
72 | 283 f = null; |
284 if (e1.op == TOK.TOKthis || e1.op == TOK.TOKsuper) | |
285 { | |
286 // semantic() run later for these | |
287 } | |
288 else | |
289 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
290 if (e1.op == TOK.TOKdot) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
291 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
292 auto die = cast(DotIdExp)e1; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
293 e1 = die.semantic(sc, 1); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
294 /* Look for e1 having been rewritten to expr.opDispatch!(string) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
295 * We handle such earlier, so go back. |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
296 * Note that in the rewrite, we carefully did not run semantic() on e1 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
297 */ |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
298 if (e1.op == TOK.TOKdotti && !e1.type) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
299 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
300 goto Ldotti; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
301 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
302 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
303 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
304 UnaExp.semantic(sc); |
72 | 305 |
306 /* Look for e1 being a lazy parameter | |
307 */ | |
308 if (e1.op == TOK.TOKvar) | |
309 { | |
310 VarExp ve = cast(VarExp)e1; | |
311 | |
312 if (ve.var.storage_class & STC.STClazy) | |
313 { | |
314 TypeFunction tff = new TypeFunction(null, ve.var.type, 0, LINK.LINKd); | |
315 TypeDelegate t = new TypeDelegate(tff); | |
316 ve.type = t.semantic(loc, sc); | |
317 } | |
318 } | |
319 | |
320 if (e1.op == TOK.TOKimport) | |
321 { | |
322 // Perhaps this should be moved to ScopeExp.semantic() | |
323 ScopeExp se = cast(ScopeExp)e1; | |
324 e1 = new DsymbolExp(loc, se.sds); | |
325 e1 = e1.semantic(sc); | |
326 } | |
327 ///static if (true) { // patch for #540 by Oskar Linde | |
328 else if (e1.op == TOK.TOKdotexp) | |
329 { | |
330 DotExp de = cast(DotExp)e1; | |
331 | |
332 if (de.e2.op == TOK.TOKimport) | |
333 { | |
334 // This should *really* be moved to ScopeExp.semantic() | |
335 ScopeExp se = cast(ScopeExp)de.e2; | |
336 de.e2 = new DsymbolExp(loc, se.sds); | |
337 de.e2 = de.e2.semantic(sc); | |
338 } | |
339 | |
340 if (de.e2.op == TOK.TOKtemplate) | |
341 { | |
342 TemplateExp te = cast(TemplateExp)de.e2; | |
343 e1 = new DotTemplateExp(loc,de.e1,te.td); | |
344 } | |
345 } | |
346 ///} | |
347 } | |
348 | |
349 if (e1.op == TOK.TOKcomma) | |
350 { | |
351 CommaExp ce = cast(CommaExp)e1; | |
352 | |
353 e1 = ce.e2; | |
354 e1.type = ce.type; | |
355 ce.e2 = this; | |
356 ce.type = null; | |
357 return ce.semantic(sc); | |
358 } | |
359 | |
360 t1 = null; | |
361 if (e1.type) | |
362 t1 = e1.type.toBasetype(); | |
363 | |
364 // Check for call operator overload | |
365 if (t1) | |
366 { | |
367 AggregateDeclaration ad; | |
368 | |
369 if (t1.ty == TY.Tstruct) | |
370 { | |
371 ad = (cast(TypeStruct)t1).sym; | |
372 version (DMDV2) { | |
373 // First look for constructor | |
374 if (ad.ctor && arguments && arguments.dim) | |
375 { | |
376 // Create variable that will get constructed | |
377 Identifier idtmp = Lexer.uniqueId("__ctmp"); | |
378 VarDeclaration tmp = new VarDeclaration(loc, t1, idtmp, null); | |
379 Expression av = new DeclarationExp(loc, tmp); | |
380 av = new CommaExp(loc, av, new VarExp(loc, tmp)); | |
381 | |
382 Expression e; | |
383 CtorDeclaration cf = ad.ctor.isCtorDeclaration(); | |
384 if (cf) | |
385 e = new DotVarExp(loc, av, cf, 1); | |
386 else | |
387 { | |
388 TemplateDeclaration td = ad.ctor.isTemplateDeclaration(); | |
389 assert(td); | |
390 e = new DotTemplateExp(loc, av, td); | |
391 } | |
392 e = new CallExp(loc, e, arguments); | |
393 version (STRUCTTHISREF) { | |
394 } else { | |
395 /* Constructors return a pointer to the instance | |
396 */ | |
397 e = new PtrExp(loc, e); | |
398 } | |
399 e = e.semantic(sc); | |
400 return e; | |
401 } | |
402 } | |
403 // No constructor, look for overload of opCall | |
404 if (search_function(ad, Id.call)) | |
405 goto L1; // overload of opCall, therefore it's a call | |
406 | |
407 if (e1.op != TOK.TOKtype) | |
408 error("%s %s does not overload ()", ad.kind(), ad.toChars()); | |
409 | |
410 /* It's a struct literal | |
411 */ | |
412 Expression e = new StructLiteralExp(loc, cast(StructDeclaration)ad, arguments); | |
413 e = e.semantic(sc); | |
414 e.type = e1.type; // in case e1.type was a typedef | |
415 return e; | |
416 } | |
417 else if (t1.ty == TY.Tclass) | |
418 { | |
419 ad = (cast(TypeClass)t1).sym; | |
420 goto L1; | |
421 L1: | |
422 // Rewrite as e1.call(arguments) | |
423 Expression e = new DotIdExp(loc, e1, Id.call); | |
424 e = new CallExp(loc, e, arguments); | |
425 e = e.semantic(sc); | |
426 return e; | |
427 } | |
428 } | |
429 | |
430 arrayExpressionSemantic(arguments, sc); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
431 preFunctionParameters(loc, sc, arguments); |
72 | 432 |
433 if (e1.op == TOK.TOKdotvar && t1.ty == TY.Tfunction || | |
434 e1.op == TOK.TOKdottd) | |
435 { | |
436 DotVarExp dve; | |
437 DotTemplateExp dte; | |
438 AggregateDeclaration ad; | |
439 UnaExp ue = cast(UnaExp)e1; | |
440 | |
441 if (e1.op == TOK.TOKdotvar) | |
442 { | |
443 // Do overload resolution | |
444 dve = cast(DotVarExp)e1; | |
445 | |
446 f = dve.var.isFuncDeclaration(); | |
447 assert(f); | |
448 f = f.overloadResolve(loc, ue.e1, arguments); | |
449 | |
450 ad = f.toParent().isAggregateDeclaration(); | |
451 } | |
452 else | |
453 { | |
454 dte = cast(DotTemplateExp)e1; | |
455 TemplateDeclaration td = dte.td; | |
456 assert(td); | |
457 | |
458 if (!arguments) | |
459 // Should fix deduceFunctionTemplate() so it works on null argument | |
460 arguments = new Expressions(); | |
461 | |
462 f = td.deduceFunctionTemplate(sc, loc, targsi, ue.e1, arguments); | |
463 if (!f) | |
464 { | |
465 type = Type.terror; | |
466 return this; | |
467 } | |
468 ad = td.toParent().isAggregateDeclaration(); | |
469 } | |
470 | |
471 if (f.needThis()) | |
472 { | |
473 ue.e1 = getRightThis(loc, sc, ad, ue.e1, f); | |
474 } | |
475 | |
476 /* Cannot call public functions from inside invariant | |
477 * (because then the invariant would have infinite recursion) | |
478 */ | |
479 if (sc.func && sc.func.isInvariantDeclaration() && | |
480 ue.e1.op == TOK.TOKthis && f.addPostInvariant()) | |
481 { | |
482 error("cannot call public/export function %s from invariant", f.toChars()); | |
483 } | |
484 | |
485 checkDeprecated(sc, f); | |
486 version (DMDV2) { | |
487 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
488 checkSafety(sc, f); |
72 | 489 } |
490 accessCheck(loc, sc, ue.e1, f); | |
491 if (!f.needThis()) | |
492 { | |
493 VarExp ve = new VarExp(loc, f); | |
494 e1 = new CommaExp(loc, ue.e1, ve); | |
495 e1.type = f.type; | |
496 } | |
497 else | |
498 { | |
499 if (e1.op == TOK.TOKdotvar) | |
500 dve.var = f; | |
501 else | |
502 e1 = new DotVarExp(loc, dte.e1, f); | |
503 | |
504 e1.type = f.type; | |
505 static if (false) { | |
506 printf("ue.e1 = %s\n", ue.e1.toChars()); | |
507 printf("f = %s\n", f.toChars()); | |
508 printf("t = %s\n", t.toChars()); | |
509 printf("e1 = %s\n", e1.toChars()); | |
510 printf("e1.type = %s\n", e1.type.toChars()); | |
511 } | |
512 // Const member function can take const/immutable/mutable this | |
513 if (!(f.type.isConst())) | |
514 { | |
515 // Check for const/immutable compatibility | |
516 Type tthis = ue.e1.type.toBasetype(); | |
517 if (tthis.ty == TY.Tpointer) | |
518 tthis = tthis.nextOf().toBasetype(); | |
519 | |
520 static if (false) { // this checking should have been already done | |
521 if (f.type.isInvariant()) | |
522 { | |
523 if (tthis.mod != MOD.MODinvariant) | |
524 error("%s can only be called with an immutable object", e1.toChars()); | |
525 } | |
526 else if (f.type.isShared()) | |
527 { | |
528 if (tthis.mod != MOD.MODinvariant && tthis.mod != MOD.MODshared && tthis.mod != (MOD.MODshared | MOD.MODconst)) | |
529 error("shared %s can only be called with a shared or immutable object", e1.toChars()); | |
530 } | |
531 else | |
532 { | |
533 if (tthis.mod != MOD.MODundefined) | |
534 { | |
535 //printf("mod = %x\n", tthis.mod); | |
536 error("%s can only be called with a mutable object, not %s", e1.toChars(), tthis.toChars()); | |
537 } | |
538 } | |
539 } | |
540 /* Cannot call mutable method on a final struct | |
541 */ | |
542 if (tthis.ty == TY.Tstruct && | |
543 ue.e1.op == TOK.TOKvar) | |
544 { | |
545 VarExp v = cast(VarExp)ue.e1; | |
546 if (v.var.storage_class & STC.STCfinal) | |
547 error("cannot call mutable method on final struct"); | |
548 } | |
549 } | |
550 | |
551 // See if we need to adjust the 'this' pointer | |
552 AggregateDeclaration add = f.isThis(); | |
553 ClassDeclaration cd = ue.e1.type.isClassHandle(); | |
554 if (add && cd && add.isClassDeclaration() && add != cd && ue.e1.op != TOK.TOKsuper) | |
555 { | |
556 ue.e1 = ue.e1.castTo(sc, add.type); //new CastExp(loc, ue.e1, add.type); | |
557 ue.e1 = ue.e1.semantic(sc); | |
558 } | |
559 } | |
560 t1 = e1.type; | |
561 } | |
562 else if (e1.op == TOK.TOKsuper) | |
563 { | |
564 // Base class constructor call | |
565 ClassDeclaration cd = null; | |
566 | |
567 if (sc.func) | |
568 cd = sc.func.toParent().isClassDeclaration(); | |
569 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) | |
570 { | |
571 error("super class constructor call must be in a constructor"); | |
572 type = Type.terror; | |
573 return this; | |
574 } | |
575 else | |
576 { | |
577 if (!cd.baseClass.ctor) | |
578 { | |
579 error("no super class constructor for %s", cd.baseClass.toChars()); | |
580 type = Type.terror; | |
581 return this; | |
582 } | |
583 else | |
584 { | |
585 if (!sc.intypeof) | |
586 { | |
587 static if (false) { | |
588 if (sc.callSuper & (CSX.CSXthis | CSX.CSXsuper)) | |
589 error("reference to this before super()"); | |
590 } | |
591 if (sc.noctor || sc.callSuper & CSX.CSXlabel) | |
592 error("constructor calls not allowed in loops or after labels"); | |
593 if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) | |
594 error("multiple constructor calls"); | |
595 sc.callSuper |= CSX.CSXany_ctor | CSX.CSXsuper_ctor; | |
596 } | |
597 | |
598 f = resolveFuncCall(sc, loc, cd.baseClass.ctor, null, null, arguments, 0); | |
599 checkDeprecated(sc, f); | |
600 version (DMDV2) { | |
601 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
602 checkSafety(sc, f); |
72 | 603 } |
604 e1 = new DotVarExp(e1.loc, e1, f); | |
605 e1 = e1.semantic(sc); | |
606 t1 = e1.type; | |
607 } | |
608 } | |
609 } | |
610 else if (e1.op == TOK.TOKthis) | |
611 { | |
612 // same class constructor call | |
613 AggregateDeclaration cd = null; | |
614 | |
615 if (sc.func) | |
616 cd = sc.func.toParent().isAggregateDeclaration(); | |
617 if (!cd || !sc.func.isCtorDeclaration()) | |
618 { | |
619 error("constructor call must be in a constructor"); | |
620 type = Type.terror; | |
621 return this; | |
622 } | |
623 else | |
624 { | |
625 if (!sc.intypeof) | |
626 { | |
627 static if (false) { | |
628 if (sc.callSuper & (CSXthis | CSXsuper)) | |
629 error("reference to this before super()"); | |
630 } | |
631 if (sc.noctor || sc.callSuper & CSX.CSXlabel) | |
632 error("constructor calls not allowed in loops or after labels"); | |
633 if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) | |
634 error("multiple constructor calls"); | |
635 sc.callSuper |= CSX.CSXany_ctor | CSX.CSXthis_ctor; | |
636 } | |
637 | |
638 f = resolveFuncCall(sc, loc, cd.ctor, null, null, arguments, 0); | |
639 checkDeprecated(sc, f); | |
640 version (DMDV2) { | |
641 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
642 checkSafety(sc, f); |
72 | 643 } |
644 e1 = new DotVarExp(e1.loc, e1, f); | |
645 e1 = e1.semantic(sc); | |
646 t1 = e1.type; | |
647 | |
648 // BUG: this should really be done by checking the static | |
649 // call graph | |
650 if (f == sc.func) | |
651 error("cyclic constructor call"); | |
652 } | |
653 } | |
654 else if (e1.op == TOK.TOKoverloadset) | |
655 { | |
656 OverExp eo = cast(OverExp)e1; | |
657 FuncDeclaration ff = null; | |
79 | 658 Dsymbol s = null; |
659 for(size_t i = 0; i<eo.vars.a.dim; i++) | |
660 { | |
661 s = eo.vars.a[i]; | |
72 | 662 FuncDeclaration f2 = s.isFuncDeclaration(); |
663 if (f2) | |
664 { | |
665 f2 = f2.overloadResolve(loc, null, arguments, 1); | |
666 } | |
667 else | |
668 { | |
669 TemplateDeclaration td = s.isTemplateDeclaration(); | |
670 assert(td); | |
671 f2 = td.deduceFunctionTemplate(sc, loc, targsi, null, arguments, 1); | |
672 } | |
673 if (f2) | |
674 { | |
675 if (ff) | |
676 /* Error if match in more than one overload set, | |
677 * even if one is a 'better' match than the other. | |
678 */ | |
679 ScopeDsymbol.multiplyDefined(loc, ff, f2); | |
680 else | |
681 ff = f2; | |
682 } | |
683 } | |
684 if (!ff) | |
79 | 685 { |
686 // No overload matches | |
687 error("no overload matches for %s", s.toChars()); | |
688 return new ErrorExp(); | |
72 | 689 } |
690 e1 = new VarExp(loc, ff); | |
691 goto Lagain; | |
692 } | |
693 else if (!t1) | |
694 { | |
695 error("function expected before (), not '%s'", e1.toChars()); | |
696 type = Type.terror; | |
697 return this; | |
698 } | |
699 else if (t1.ty != TY.Tfunction) | |
700 { | |
701 if (t1.ty == TY.Tdelegate) | |
702 { | |
703 TypeDelegate td = cast(TypeDelegate)t1; | |
704 assert(td.next.ty == TY.Tfunction); | |
705 tf = cast(TypeFunction)(td.next); | |
706 if (sc.func && sc.func.isPure() && !tf.ispure) | |
707 { | |
708 error("pure function '%s' cannot call impure delegate '%s'", sc.func.toChars(), e1.toChars()); | |
709 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
710 if (sc.func && sc.func.isSafe() && tf.trust <= TRUST.TRUSTsystem) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
711 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
712 error("safe function '%s' cannot call system delegate '%s'", sc.func.toChars(), e1.toChars()); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
713 } |
72 | 714 goto Lcheckargs; |
715 } | |
716 else if (t1.ty == TY.Tpointer && (cast(TypePointer)t1).next.ty == TY.Tfunction) | |
717 { | |
718 Expression e = new PtrExp(loc, e1); | |
719 t1 = (cast(TypePointer)t1).next; | |
720 if (sc.func && sc.func.isPure() && !(cast(TypeFunction)t1).ispure) | |
721 { | |
722 error("pure function '%s' cannot call impure function pointer '%s'", sc.func.toChars(), e1.toChars()); | |
723 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
724 if (sc.func && sc.func.isSafe() && !(cast(TypeFunction)t1).trust <= TRUST.TRUSTsystem) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
725 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
726 error("safe function '%s' cannot call system function pointer '%s'", sc.func.toChars(), e1.toChars()); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
727 } |
72 | 728 e.type = t1; |
729 e1 = e; | |
730 } | |
731 else if (e1.op == TOK.TOKtemplate) | |
732 { | |
733 TemplateExp te = cast(TemplateExp)e1; | |
734 f = te.td.deduceFunctionTemplate(sc, loc, targsi, null, arguments); | |
735 if (!f) | |
736 { | |
737 if (tierror) | |
738 tierror.error("errors instantiating template"); // give better error message | |
739 type = Type.terror; | |
740 return this; | |
741 } | |
742 if (f.needThis() && hasThis(sc)) | |
743 { | |
744 // Supply an implicit 'this', as in | |
745 // this.ident | |
746 | |
747 e1 = new DotTemplateExp(loc, (new ThisExp(loc)).semantic(sc), te.td); | |
748 goto Lagain; | |
749 } | |
750 | |
751 e1 = new VarExp(loc, f); | |
752 goto Lagain; | |
753 } | |
754 else | |
755 { | |
756 error("function expected before (), not %s of type %s", e1.toChars(), e1.type.toChars()); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
757 return new ErrorExp(); |
72 | 758 } |
759 } | |
760 else if (e1.op == TOK.TOKvar) | |
761 { | |
762 // Do overload resolution | |
763 VarExp ve = cast(VarExp)e1; | |
764 | |
765 f = ve.var.isFuncDeclaration(); | |
766 assert(f); | |
767 | |
768 if (ve.hasOverloads) | |
769 f = f.overloadResolve(loc, null, arguments); | |
770 | |
771 checkDeprecated(sc, f); | |
772 version (DMDV2) { | |
773 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
774 checkSafety(sc, f); |
72 | 775 } |
776 | |
777 if (f.needThis() && hasThis(sc)) | |
778 { | |
779 // Supply an implicit 'this', as in | |
780 // this.ident | |
781 | |
782 e1 = new DotVarExp(loc, new ThisExp(loc), f); | |
783 goto Lagain; | |
784 } | |
785 | |
786 accessCheck(loc, sc, null, f); | |
787 | |
788 ve.var = f; | |
73 | 789 // ve.hasOverloads = false; |
72 | 790 ve.type = f.type; |
791 t1 = f.type; | |
792 } | |
793 assert(t1.ty == TY.Tfunction); | |
794 tf = cast(TypeFunction)t1; | |
795 | |
796 Lcheckargs: | |
797 assert(tf.ty == TY.Tfunction); | |
798 type = tf.next; | |
799 | |
800 if (!arguments) | |
801 arguments = new Expressions(); | |
802 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
803 functionParameters(loc, sc, tf, arguments); |
72 | 804 |
805 if (!type) | |
806 { | |
807 error("forward reference to inferred return type of function call %s", toChars()); | |
808 type = Type.terror; | |
809 } | |
810 | |
811 if (f && f.tintro) | |
812 { | |
813 Type t = type; | |
814 int offset = 0; | |
815 TypeFunction tff = cast(TypeFunction)f.tintro; | |
816 | |
817 if (tff.next.isBaseOf(t, &offset) && offset) | |
818 { | |
819 type = tff.next; | |
820 return castTo(sc, t); | |
821 } | |
822 } | |
823 | |
824 return this; | |
0 | 825 } |
826 | |
72 | 827 override Expression optimize(int result) |
0 | 828 { |
96 | 829 // writef("CallExp::optimize(result = %d) %s\n", result, toChars()); |
72 | 830 Expression e = this; |
831 | |
832 // Optimize parameters | |
833 if (arguments) | |
834 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
835 foreach (ref Expression ee; arguments) |
72 | 836 { |
837 ee = ee.optimize(WANT.WANTvalue); | |
838 } | |
839 } | |
840 | |
841 e1 = e1.optimize(result); | |
842 if (e1.op == TOK.TOKvar) | |
843 { | |
844 FuncDeclaration fd = (cast(VarExp)e1).var.isFuncDeclaration(); | |
845 if (fd) | |
846 { | |
847 BUILTIN b = fd.isBuiltin(); | |
848 if (b) | |
849 { | |
850 e = eval_builtin(b, arguments); | |
851 if (!e) // failed | |
852 e = this; // evaluate at runtime | |
853 } | |
854 else if (result & WANT.WANTinterpret) | |
855 { | |
856 Expression eresult = fd.interpret(null, arguments); | |
857 if (eresult && eresult !is EXP_VOID_INTERPRET) | |
858 e = eresult; | |
859 else | |
860 error("cannot evaluate %s at compile time", toChars()); | |
861 } | |
862 } | |
863 } | |
96 | 864 else if (e1.op == TOKdotvar && result & WANTinterpret) |
865 { | |
866 DotVarExp dve = cast(DotVarExp) e1; | |
867 FuncDeclaration fd = dve.var.isFuncDeclaration(); | |
868 if (fd) | |
869 { | |
870 Expression eresult = fd.interpret(null, arguments, dve.e1); | |
871 if (eresult && eresult != EXP_VOID_INTERPRET) | |
872 e = eresult; | |
873 else | |
874 error("cannot evaluate %s at compile time", toChars()); | |
875 } | |
876 } | |
72 | 877 |
0 | 878 return e; |
879 } | |
880 | |
72 | 881 override Expression interpret(InterState istate) |
0 | 882 { |
72 | 883 Expression e = EXP_CANT_INTERPRET; |
884 | |
885 version (LOG) { | |
886 printf("CallExp.interpret() %.*s\n", toChars()); | |
887 } | |
888 if (e1.op == TOKdotvar) | |
889 { | |
890 Expression pthis = (cast(DotVarExp)e1).e1; | |
891 FuncDeclaration fd = (cast(DotVarExp)e1).var.isFuncDeclaration(); | |
892 TypeFunction tf = fd ? cast(TypeFunction)fd.type : null; | |
893 if (tf) | |
894 { | |
895 // Member function call | |
896 if(pthis.op == TOKthis) | |
96 | 897 pthis = istate.localThis; |
72 | 898 Expression eresult = fd.interpret(istate, arguments, pthis); |
899 if (eresult) | |
900 e = eresult; | |
901 else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) | |
902 e = EXP_VOID_INTERPRET; | |
903 else | |
904 error("cannot evaluate %s at compile time", toChars()); | |
905 return e; | |
906 } | |
907 error("cannot evaluate %s at compile time", toChars()); | |
908 return EXP_CANT_INTERPRET; | |
909 } | |
910 if (e1.op == TOKvar) | |
911 { | |
912 FuncDeclaration fd = (cast(VarExp)e1).var.isFuncDeclaration(); | |
913 if (fd) | |
914 { | |
915 ///version (DMDV2) { | |
916 BUILTIN b = fd.isBuiltin(); | |
917 if (b) | |
918 { | |
919 scope Expressions args = new Expressions(); | |
920 args.setDim(arguments.dim); | |
921 for (size_t i = 0; i < args.dim; i++) | |
922 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
923 auto earg = arguments[i]; |
72 | 924 earg = earg.interpret(istate); |
925 if (earg == EXP_CANT_INTERPRET) | |
926 return earg; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
927 args[i] = earg; |
72 | 928 } |
929 e = eval_builtin(b, args); | |
930 if (!e) | |
931 e = EXP_CANT_INTERPRET; | |
932 } | |
933 else | |
934 ///} | |
935 // Inline .dup | |
936 if (fd.ident == Id.adDup && arguments && arguments.dim == 2) | |
937 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
938 e = arguments[1]; |
72 | 939 e = e.interpret(istate); |
940 if (e !is EXP_CANT_INTERPRET) | |
941 { | |
942 e = expType(type, e); | |
943 } | |
944 } | |
945 else | |
946 { | |
947 Expression eresult = fd.interpret(istate, arguments); | |
948 if (eresult) | |
949 e = eresult; | |
950 else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) | |
951 e = EXP_VOID_INTERPRET; | |
952 else | |
953 error("cannot evaluate %s at compile time", toChars()); | |
954 } | |
955 } | |
956 } | |
63 | 957 return e; |
0 | 958 } |
959 | |
72 | 960 override bool checkSideEffect(int flag) |
0 | 961 { |
72 | 962 version (DMDV2) { |
963 if (flag != 2) | |
964 return true; | |
965 | |
966 if (e1.checkSideEffect(2)) | |
967 return true; | |
968 | |
969 /* If any of the arguments have side effects, this expression does | |
970 */ | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
971 foreach (e; arguments) |
72 | 972 { |
973 if (e.checkSideEffect(2)) | |
974 return true; | |
975 } | |
976 | |
977 /* If calling a function or delegate that is typed as pure, | |
978 * then this expression has no side effects. | |
979 */ | |
980 Type t = e1.type.toBasetype(); | |
981 if (t.ty == TY.Tfunction && (cast(TypeFunction)t).ispure) | |
982 return false; | |
983 if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).ispure) | |
984 return false; | |
985 } | |
0 | 986 return true; |
987 } | |
988 | |
72 | 989 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 990 { |
72 | 991 int i; |
992 expToCBuffer(buf, hgs, e1, precedence[op]); | |
993 buf.writeByte('('); | |
994 argsToCBuffer(buf, arguments, hgs); | |
0 | 995 buf.writeByte(')'); |
996 } | |
997 | |
72 | 998 override void dump(int indent) |
0 | 999 { |
1000 assert(false); | |
1001 } | |
1002 | |
72 | 1003 override elem* toElem(IRState* irs) |
0 | 1004 { |
72 | 1005 //printf("CallExp::toElem('%s')\n", toChars()); |
1006 assert(e1.type); | |
1007 elem* ec; | |
1008 int directcall; | |
1009 FuncDeclaration fd; | |
1010 Type t1 = e1.type.toBasetype(); | |
1011 Type ectype = t1; | |
1012 | |
1013 elem* ehidden = irs.ehidden; | |
1014 irs.ehidden = null; | |
1015 | |
1016 directcall = 0; | |
1017 fd = null; | |
1018 if (e1.op == TOK.TOKdotvar && t1.ty != TY.Tdelegate) | |
1019 { | |
1020 DotVarExp dve = cast(DotVarExp)e1; | |
1021 | |
1022 fd = dve.var.isFuncDeclaration(); | |
1023 Expression ex = dve.e1; | |
1024 while (1) | |
1025 { | |
1026 switch (ex.op) | |
1027 { | |
1028 case TOK.TOKsuper: // super.member() calls directly | |
1029 case TOK.TOKdottype: // type.member() calls directly | |
1030 directcall = 1; | |
1031 break; | |
1032 | |
1033 case TOK.TOKcast: | |
1034 ex = (cast(CastExp)ex).e1; | |
1035 continue; | |
1036 | |
1037 default: | |
1038 //ex.dump(0); | |
1039 break; | |
1040 } | |
1041 break; | |
1042 } | |
1043 ec = dve.e1.toElem(irs); | |
1044 ectype = dve.e1.type.toBasetype(); | |
1045 } | |
1046 else if (e1.op == TOK.TOKvar) | |
1047 { | |
1048 fd = (cast(VarExp)e1).var.isFuncDeclaration(); | |
1049 | |
1050 if (fd && fd.ident == Id.alloca && !fd.fbody && fd.linkage == LINK.LINKc && arguments && arguments.dim == 1) | |
1051 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
1052 auto arg = arguments[0]; |
72 | 1053 arg = arg.optimize(WANT.WANTvalue); |
1054 if (arg.isConst() && arg.type.isintegral()) | |
1055 { | |
1056 long sz = arg.toInteger(); | |
1057 if (sz > 0 && sz < 0x40000) | |
1058 { | |
1059 // It's an alloca(sz) of a fixed amount. | |
1060 // Replace with an array allocated on the stack | |
1061 // of the same size: char[sz] tmp; | |
1062 | |
1063 Symbol* stmp; | |
1064 .type* t; | |
1065 | |
1066 assert(!ehidden); | |
1067 t = type_allocn(TYM.TYarray, tschar); | |
1068 t.Tdim = cast(uint)sz; | |
1069 stmp = symbol_genauto(t); | |
1070 ec = el_ptr(stmp); | |
1071 el_setLoc(ec,loc); | |
1072 return ec; | |
1073 } | |
1074 } | |
1075 } | |
1076 | |
1077 ec = e1.toElem(irs); | |
1078 } | |
1079 else | |
1080 { | |
1081 ec = e1.toElem(irs); | |
1082 } | |
1083 ec = callfunc(loc, irs, directcall, type, ec, ectype, fd, t1, ehidden, arguments); | |
1084 el_setLoc(ec,loc); | |
0 | 1085 return ec; |
1086 } | |
1087 | |
72 | 1088 override void scanForNestedRef(Scope sc) |
0 | 1089 { |
72 | 1090 //printf("CallExp.scanForNestedRef(Scope *sc): %s\n", toChars()); |
1091 e1.scanForNestedRef(sc); | |
64 | 1092 arrayExpressionScanForNestedRef(sc, arguments); |
72 | 1093 } |
0 | 1094 |
1095 version (DMDV2) { | |
72 | 1096 override int isLvalue() |
0 | 1097 { |
96 | 1098 // if (type.toBasetype().ty == Tstruct) |
72 | 1099 // return 1; |
1100 Type tb = e1.type.toBasetype(); | |
1101 if (tb.ty == Tfunction && (cast(TypeFunction)tb).isref) | |
1102 return 1; // function returns a reference | |
0 | 1103 return 0; |
1104 } | |
1105 } | |
72 | 1106 override Expression toLvalue(Scope sc, Expression e) |
0 | 1107 { |
72 | 1108 if (isLvalue()) |
1109 return this; | |
0 | 1110 return Expression.toLvalue(sc, e); |
72 | 1111 } |
0 | 1112 |
1113 version (DMDV2) { | |
72 | 1114 override bool canThrow() |
0 | 1115 { |
72 | 1116 //printf("CallExp::canThrow() %s\n", toChars()); |
1117 if (e1.canThrow()) | |
1118 return true; | |
1119 | |
1120 /* If any of the arguments can throw, then this expression can throw | |
1121 */ | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
1122 foreach (e; arguments) |
72 | 1123 { |
1124 if (e && e.canThrow()) | |
1125 return true; | |
1126 } | |
1127 | |
1128 if (global.errors && !e1.type) | |
1129 return false; // error recovery | |
1130 | |
1131 /* If calling a function or delegate that is typed as nothrow, | |
1132 * then this expression cannot throw. | |
1133 * Note that pure functions can throw. | |
1134 */ | |
1135 Type t = e1.type.toBasetype(); | |
1136 if (t.ty == TY.Tfunction && (cast(TypeFunction)t).isnothrow) | |
1137 return false; | |
1138 if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) | |
1139 return false; | |
1140 | |
0 | 1141 return true; |
1142 } | |
1143 } | |
72 | 1144 override int inlineCost(InlineCostState* ics) |
0 | 1145 { |
1146 return 1 + e1.inlineCost(ics) + arrayInlineCost(ics, arguments); | |
1147 } | |
1148 | |
72 | 1149 override Expression doInline(InlineDoState ids) |
0 | 1150 { |
72 | 1151 CallExp ce = cast(CallExp)copy(); |
1152 ce.e1 = e1.doInline(ids); | |
1153 ce.arguments = arrayExpressiondoInline(arguments, ids); | |
0 | 1154 return ce; |
1155 } | |
1156 | |
72 | 1157 override Expression inlineScan(InlineScanState* iss) |
0 | 1158 { |
72 | 1159 Expression e = this; |
1160 | |
1161 //printf("CallExp.inlineScan()\n"); | |
1162 e1 = e1.inlineScan(iss); | |
1163 arrayInlineScan(iss, arguments); | |
1164 | |
1165 if (e1.op == TOKvar) | |
1166 { | |
1167 VarExp ve = cast(VarExp)e1; | |
1168 FuncDeclaration fd = ve.var.isFuncDeclaration(); | |
1169 | |
1170 if (fd && fd != iss.fd && fd.canInline(0)) | |
1171 { | |
1172 e = fd.doInline(iss, null, arguments); | |
1173 } | |
1174 } | |
1175 else if (e1.op == TOKdotvar) | |
1176 { | |
1177 DotVarExp dve = cast(DotVarExp)e1; | |
1178 FuncDeclaration fd = dve.var.isFuncDeclaration(); | |
1179 | |
1180 if (fd && fd != iss.fd && fd.canInline(1)) | |
1181 { | |
1182 if (dve.e1.op == TOKcall && | |
1183 dve.e1.type.toBasetype().ty == Tstruct) | |
1184 { | |
1185 /* To create ethis, we'll need to take the address | |
1186 * of dve.e1, but this won't work if dve.e1 is | |
1187 * a function call. | |
1188 */ | |
1189 ; | |
1190 } | |
1191 else | |
1192 e = fd.doInline(iss, dve.e1, arguments); | |
1193 } | |
1194 } | |
1195 | |
0 | 1196 return e; |
1197 } | |
1198 } | |
1199 |