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