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