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