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