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