Mercurial > projects > ddmd
annotate dmd/expression/Util.d @ 114:e28b18c23469
added a module dmd.common for commonly used stuff
it currently holds code for consistency checking of predefined versions
also added a VisualD project file
author | Trass3r |
---|---|
date | Wed, 01 Sep 2010 18:21:58 +0200 |
parents | ceda59b4d255 |
children | 1765f3ef917d |
rev | line source |
---|---|
0 | 1 module dmd.expression.Util; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.Expression; |
5 import dmd.Loc; | |
53 | 6 import dmd.RealExp; |
0 | 7 import dmd.Scope; |
8 import dmd.FuncExp; | |
9 import dmd.DelegateExp; | |
10 import dmd.LINK; | |
11 import dmd.NullExp; | |
12 import dmd.SymOffExp; | |
13 import dmd.ExpInitializer; | |
14 import dmd.Lexer; | |
15 import dmd.TypeSArray; | |
16 import dmd.TypeArray; | |
17 import dmd.VarDeclaration; | |
18 import dmd.VoidInitializer; | |
19 import dmd.DeclarationExp; | |
20 import dmd.VarExp; | |
21 import dmd.NewExp; | |
22 import dmd.STC; | |
23 import dmd.WANT; | |
24 import dmd.IndexExp; | |
25 import dmd.AssignExp; | |
26 import dmd.CommaExp; | |
27 import dmd.Argument; | |
28 import dmd.DefaultInitExp; | |
29 import dmd.Identifier; | |
30 import dmd.Dsymbol; | |
31 import dmd.Global; | |
32 import dmd.ScopeDsymbol; | |
33 import dmd.DotIdExp; | |
34 import dmd.DotVarExp; | |
35 import dmd.CallExp; | |
36 import dmd.TY; | |
37 import dmd.MATCH; | |
53 | 38 import dmd.BUILTIN; |
0 | 39 import dmd.TypeFunction; |
40 import dmd.declaration.Match; | |
41 import dmd.ArrayTypes; | |
42 import dmd.Declaration; | |
43 import dmd.FuncAliasDeclaration; | |
44 import dmd.AliasDeclaration; | |
45 import dmd.FuncDeclaration; | |
46 import dmd.TemplateDeclaration; | |
47 import dmd.AggregateDeclaration; | |
48 import dmd.IntegerExp; | |
49 import dmd.Type; | |
50 import dmd.TOK; | |
51 import dmd.TypeExp; | |
52 import dmd.TypeTuple; | |
53 import dmd.TupleExp; | |
54 import dmd.OutBuffer; | |
55 import dmd.HdrGenState; | |
56 import dmd.ClassDeclaration; | |
57 import dmd.TypeClass; | |
58 import dmd.StructDeclaration; | |
59 import dmd.TypeStruct; | |
60 import dmd.MOD; | |
61 import dmd.PROT; | |
62 import dmd.PREC; | |
63 import dmd.Util; | |
64 import dmd.TypeAArray; | |
65 import dmd.Id; | |
114 | 66 import dmd.PtrExp; |
0 | 67 |
68 import std.stdio : writef; | |
69 | |
70 | |
71 /*********************************** | |
72 * Utility to build a function call out of this reference and argument. | |
73 */ | |
74 Expression build_overload(Loc loc, Scope sc, Expression ethis, Expression earg, Identifier id) | |
75 { | |
76 Expression e; | |
77 | |
78 //printf("build_overload(id = '%s')\n", id.toChars()); | |
79 //earg.print(); | |
80 //earg.type.print(); | |
81 e = new DotIdExp(loc, ethis, id); | |
82 | |
83 if (earg) | |
84 e = new CallExp(loc, e, earg); | |
85 else | |
86 e = new CallExp(loc, e); | |
87 | |
88 e = e.semantic(sc); | |
89 return e; | |
90 } | |
91 | |
92 /*************************************** | |
93 * Search for function funcid in aggregate ad. | |
94 */ | |
95 | |
96 Dsymbol search_function(ScopeDsymbol ad, Identifier funcid) | |
97 { | |
98 Dsymbol s; | |
99 FuncDeclaration fd; | |
100 TemplateDeclaration td; | |
101 | |
102 s = ad.search(Loc(0), funcid, 0); | |
103 if (s) | |
104 { | |
105 Dsymbol s2; | |
106 | |
107 //printf("search_function: s = '%s'\n", s.kind()); | |
108 s2 = s.toAlias(); | |
109 //printf("search_function: s2 = '%s'\n", s2.kind()); | |
110 fd = s2.isFuncDeclaration(); | |
111 if (fd && fd.type.ty == TY.Tfunction) | |
112 return fd; | |
113 | |
114 td = s2.isTemplateDeclaration(); | |
115 if (td) | |
116 return td; | |
117 } | |
118 | |
119 return null; | |
120 } | |
121 | |
122 /******************************************** | |
123 * Find function in overload list that exactly matches t. | |
124 */ | |
125 | |
126 /*************************************************** | |
127 * Visit each overloaded function in turn, and call | |
128 * dg(param, f) on it. | |
129 * Exit when no more, or dg(param, f) returns 1. | |
130 * Returns: | |
131 * 0 continue | |
132 * 1 done | |
133 */ | |
134 | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
135 int overloadApply(FuncDeclaration fstart, int delegate(void*, FuncDeclaration) dg, void* param) |
0 | 136 { |
137 FuncDeclaration f; | |
138 Declaration d; | |
139 Declaration next; | |
140 | |
141 for (d = fstart; d; d = next) | |
142 { | |
143 FuncAliasDeclaration fa = d.isFuncAliasDeclaration(); | |
144 | |
145 if (fa) | |
146 { | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
147 if (overloadApply(fa.funcalias, dg, param)) |
0 | 148 return 1; |
149 next = fa.overnext; | |
150 } | |
151 else | |
152 { | |
153 AliasDeclaration a = d.isAliasDeclaration(); | |
154 | |
155 if (a) | |
156 { | |
157 Dsymbol s = a.toAlias(); | |
158 next = s.isDeclaration(); | |
159 if (next is a) | |
160 break; | |
161 if (next is fstart) | |
162 break; | |
163 } | |
164 else | |
165 { | |
166 f = d.isFuncDeclaration(); | |
167 if (f is null) | |
168 { | |
169 d.error("is aliased to a function"); | |
170 break; // BUG: should print error message? | |
171 } | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
172 if (dg(param, f)) |
0 | 173 return 1; |
174 | |
175 next = f.overnext; | |
176 } | |
177 } | |
178 } | |
179 return 0; | |
180 } | |
181 | |
182 /******************************************** | |
183 * Decide which function matches the arguments best. | |
184 */ | |
185 | |
186 struct Param2 | |
187 { | |
188 Match* m; | |
189 Expression ethis; | |
190 Expressions arguments; | |
191 | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
192 int fp2(void*, FuncDeclaration f) |
0 | 193 { |
194 MATCH match; | |
195 | |
196 if (f != m.lastf) // skip duplicates | |
197 { | |
198 m.anyf = f; | |
199 TypeFunction tf = cast(TypeFunction)f.type; | |
200 match = tf.callMatch(f.needThis() ? ethis : null, arguments); | |
98 | 201 //printf("test: match = %d\n", match); |
0 | 202 if (match != MATCH.MATCHnomatch) |
203 { | |
204 if (match > m.last) | |
205 goto LfIsBetter; | |
206 | |
207 if (match < m.last) | |
208 goto LlastIsBetter; | |
209 | |
210 /* See if one of the matches overrides the other. | |
211 */ | |
212 if (m.lastf.overrides(f)) | |
213 goto LlastIsBetter; | |
214 else if (f.overrides(m.lastf)) | |
215 goto LfIsBetter; | |
216 | |
217 /* Try to disambiguate using template-style partial ordering rules. | |
218 * In essence, if f() and g() are ambiguous, if f() can call g(), | |
219 * but g() cannot call f(), then pick f(). | |
220 * This is because f() is "more specialized." | |
221 */ | |
222 { | |
223 MATCH c1 = f.leastAsSpecialized(m.lastf); | |
224 MATCH c2 = m.lastf.leastAsSpecialized(f); | |
225 //printf("c1 = %d, c2 = %d\n", c1, c2); | |
226 if (c1 > c2) | |
227 goto LfIsBetter; | |
228 if (c1 < c2) | |
229 goto LlastIsBetter; | |
230 } | |
231 | |
232 Lambiguous: | |
233 m.nextf = f; | |
234 m.count++; | |
235 return 0; | |
236 | |
237 LfIsBetter: | |
238 m.last = match; | |
239 m.lastf = f; | |
240 m.count = 1; | |
241 return 0; | |
242 | |
243 LlastIsBetter: | |
244 return 0; | |
245 } | |
246 } | |
247 return 0; | |
248 } | |
249 } | |
250 | |
251 struct Param1 | |
252 { | |
253 Type t; // type to match | |
254 FuncDeclaration f; // return value | |
255 | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
256 int fp1(void*, FuncDeclaration f) |
0 | 257 { |
258 if (t.equals(f.type)) | |
259 { | |
260 this.f = f; | |
261 return 1; | |
262 } | |
263 | |
264 version (DMDV2) { | |
265 /* Allow covariant matches, if it's just a const conversion | |
266 * of the return type | |
267 */ | |
268 if (t.ty == Tfunction) | |
269 { | |
270 TypeFunction tf = cast(TypeFunction)f.type; | |
271 if (tf.covariant(t) == 1 && | |
272 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCHconst) | |
273 { | |
274 this.f = f; | |
275 return 1; | |
276 } | |
277 } | |
278 } | |
279 return 0; | |
280 } | |
281 } | |
282 | |
283 void overloadResolveX(Match* m, FuncDeclaration fstart, Expression ethis, Expressions arguments) | |
284 { | |
285 Param2 p; | |
286 p.m = m; | |
287 p.ethis = ethis; | |
288 p.arguments = arguments; | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
289 overloadApply(fstart, &p.fp2, &p); |
0 | 290 } |
291 | |
292 void templateResolve(Match* m, TemplateDeclaration td, Scope sc, Loc loc, Objects targsi, Expression ethis, Expressions arguments) | |
293 { | |
294 FuncDeclaration fd; | |
295 | |
296 assert(td); | |
297 fd = td.deduceFunctionTemplate(sc, loc, targsi, ethis, arguments); | |
298 if (!fd) | |
299 return; | |
300 m.anyf = fd; | |
301 if (m.last >= MATCH.MATCHexact) | |
302 { | |
303 m.nextf = fd; | |
304 m.count++; | |
305 } | |
306 else | |
307 { | |
308 m.last = MATCH.MATCHexact; | |
309 m.lastf = fd; | |
310 m.count = 1; | |
311 } | |
312 } | |
313 | |
314 /****************************** | |
315 * Perform semantic() on an array of Expressions. | |
316 */ | |
317 | |
318 void arrayExpressionSemantic(Expressions exps, Scope sc) | |
319 { | |
320 if (exps) | |
321 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
322 foreach (ref Expression e; exps) |
0 | 323 { |
324 e = e.semantic(sc); | |
325 } | |
326 } | |
327 } | |
328 | |
329 /**************************************** | |
330 * Preprocess arguments to function. | |
331 */ | |
332 | |
333 void preFunctionArguments(Loc loc, Scope sc, Expressions exps) | |
334 { | |
335 if (exps) | |
336 { | |
337 expandTuples(exps); | |
57 | 338 |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
339 foreach (size_t i, ref Expression arg; exps) |
0 | 340 { |
341 if (!arg.type) | |
342 { | |
343 debug { | |
57 | 344 if (!global.gag) { |
0 | 345 writef("1: \n"); |
57 | 346 } |
0 | 347 } |
348 arg.error("%s is not an expression", arg.toChars()); | |
349 arg = new IntegerExp(arg.loc, 0, Type.tint32); | |
350 } | |
351 | |
352 arg = resolveProperties(sc, arg); | |
353 | |
354 //arg.rvalue(); | |
355 static if (false) { | |
356 if (arg.type.ty == TY.Tfunction) | |
357 { | |
358 arg = new AddrExp(arg.loc, arg); | |
359 arg = arg.semantic(sc); | |
360 } | |
361 } | |
362 } | |
363 } | |
364 } | |
365 | |
366 /************************************************************* | |
367 * Given var, we need to get the | |
368 * right 'this' pointer if var is in an outer class, but our | |
369 * existing 'this' pointer is in an inner class. | |
370 * Input: | |
371 * e1 existing 'this' | |
372 * ad struct or class we need the correct 'this' for | |
373 * var the specific member of ad we're accessing | |
374 */ | |
375 | |
376 Expression getRightThis(Loc loc, Scope sc, AggregateDeclaration ad, Expression e1, Declaration var) | |
377 { | |
378 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars()); | |
379 L1: | |
380 Type t = e1.type.toBasetype(); | |
381 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars()); | |
382 | |
383 /* If e1 is not the 'this' pointer for ad | |
384 */ | |
385 if (ad && !(t.ty == TY.Tpointer && t.nextOf().ty == TY.Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) && !(t.ty == TY.Tstruct && (cast(TypeStruct)t).sym == ad)) | |
386 { | |
387 ClassDeclaration cd = ad.isClassDeclaration(); | |
388 ClassDeclaration tcd = t.isClassHandle(); | |
389 | |
390 /* e1 is the right this if ad is a base class of e1 | |
391 */ | |
392 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) | |
393 { | |
394 /* Only classes can be inner classes with an 'outer' | |
395 * member pointing to the enclosing class instance | |
396 */ | |
397 if (tcd && tcd.isNested()) | |
398 { | |
399 /* e1 is the 'this' pointer for an inner class: tcd. | |
400 * Rewrite it as the 'this' pointer for the outer class. | |
401 */ | |
402 | |
403 e1 = new DotVarExp(loc, e1, tcd.vthis); | |
404 e1.type = tcd.vthis.type; | |
405 // Do not call checkNestedRef() | |
406 //e1 = e1.semantic(sc); | |
407 | |
408 // Skip up over nested functions, and get the enclosing | |
409 // class type. | |
410 int n = 0; | |
411 Dsymbol s; | |
412 for (s = tcd.toParent(); s && s.isFuncDeclaration(); s = s.toParent()) | |
413 { | |
414 FuncDeclaration f = s.isFuncDeclaration(); | |
415 if (f.vthis) | |
416 { | |
417 //printf("rewriting e1 to %s's this\n", f.toChars()); | |
418 n++; | |
419 e1 = new VarExp(loc, f.vthis); | |
420 } | |
421 } | |
422 if (s && s.isClassDeclaration()) | |
423 { | |
424 e1.type = s.isClassDeclaration().type; | |
425 if (n > 1) | |
426 e1 = e1.semantic(sc); | |
427 } | |
428 else | |
429 e1 = e1.semantic(sc); | |
430 goto L1; | |
431 } | |
432 /* Can't find a path from e1 to ad | |
433 */ | |
434 e1.error("this for %s needs to be type %s not type %s", var.toChars(), ad.toChars(), t.toChars()); | |
435 } | |
436 } | |
437 return e1; | |
438 } | |
439 | |
440 /******************************************* | |
441 * Given a symbol that could be either a FuncDeclaration or | |
442 * a function template, resolve it to a function symbol. | |
443 * sc instantiation scope | |
444 * loc instantiation location | |
445 * targsi initial list of template arguments | |
446 * ethis if !null, the 'this' pointer argument | |
447 * fargs arguments to function | |
448 * flags 1: do not issue error message on no match, just return null | |
449 */ | |
450 | |
451 FuncDeclaration resolveFuncCall(Scope sc, Loc loc, Dsymbol s, | |
452 Objects tiargs, | |
453 Expression ethis, | |
454 Expressions arguments, | |
455 int flags) | |
456 { | |
457 if (!s) | |
458 return null; // no match | |
459 FuncDeclaration f = s.isFuncDeclaration(); | |
460 if (f) | |
461 f = f.overloadResolve(loc, ethis, arguments); | |
462 else | |
463 { | |
464 TemplateDeclaration td = s.isTemplateDeclaration(); | |
465 assert(td); | |
466 f = td.deduceFunctionTemplate(sc, loc, tiargs, null, arguments, flags); | |
467 } | |
468 return f; | |
469 } | |
470 | |
471 /**************************************** | |
472 * Now that we know the exact type of the function we're calling, | |
473 * the arguments[] need to be adjusted: | |
474 * 1. implicitly convert argument to the corresponding parameter type | |
475 * 2. add default arguments for any missing arguments | |
476 * 3. do default promotions on arguments corresponding to ... | |
477 * 4. add hidden _arguments[] argument | |
478 * 5. call copy constructor for struct value arguments | |
479 */ | |
480 | |
481 void functionArguments(Loc loc, Scope sc, TypeFunction tf, Expressions arguments) | |
482 { | |
483 uint n; | |
484 | |
485 //printf("functionArguments()\n"); | |
486 assert(arguments); | |
487 size_t nargs = arguments ? arguments.dim : 0; | |
488 size_t nparams = Argument.dim(tf.parameters); | |
489 | |
490 if (nargs > nparams && tf.varargs == 0) | |
491 error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf.toChars()); | |
492 | |
493 n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) | |
494 | |
495 int done = 0; | |
496 for (size_t i = 0; i < n; i++) | |
497 { | |
498 Expression arg; | |
499 | |
500 if (i < nargs) | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
501 arg = arguments[i]; |
0 | 502 else |
503 arg = null; | |
504 | |
505 Type tb; | |
506 | |
507 if (i < nparams) | |
508 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
509 auto p = Argument.getNth(tf.parameters, i); |
0 | 510 |
511 if (!arg) | |
512 { | |
513 if (!p.defaultArg) | |
514 { | |
515 if (tf.varargs == 2 && i + 1 == nparams) | |
516 goto L2; | |
517 | |
518 error(loc, "expected %d function arguments, not %d", nparams, nargs); | |
519 break; | |
520 } | |
521 arg = p.defaultArg; | |
522 version (DMDV2) { | |
523 if (arg.op == TOK.TOKdefault) | |
524 { | |
525 DefaultInitExp de = cast(DefaultInitExp)arg; | |
526 arg = de.resolve(loc, sc); | |
527 } | |
528 else | |
529 { | |
530 arg = arg.copy(); | |
531 } | |
532 } else { | |
533 arg = arg.copy(); | |
534 } | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
535 arguments.push(arg); |
0 | 536 nargs++; |
537 } | |
538 | |
539 if (tf.varargs == 2 && i + 1 == nparams) | |
540 { | |
541 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars()); | |
542 if (arg.implicitConvTo(p.type)) | |
543 { | |
544 if (nargs != nparams) | |
545 error(loc, "expected %zu function arguments, not %zu", nparams, nargs); | |
546 goto L1; | |
547 } | |
548 L2: | |
549 tb = p.type.toBasetype(); /// | |
550 Type tret = p.isLazyArray(); | |
551 switch (tb.ty) | |
552 { | |
553 case TY.Tsarray: | |
554 case TY.Tarray: | |
555 { // Create a static array variable v of type arg.type | |
556 version (IN_GCC) { | |
557 /* GCC 4.0 does not like zero length arrays used like | |
558 this; pass a null array value instead. Could also | |
559 just make a one-element array. */ | |
560 if (nargs - i == 0) | |
561 { | |
562 arg = new NullExp(loc); | |
563 break; | |
564 } | |
565 } | |
566 Identifier id = Lexer.uniqueId("__arrayArg"); | |
567 Type t = new TypeSArray((cast(TypeArray)tb).next, new IntegerExp(nargs - i)); | |
568 t = t.semantic(loc, sc); | |
569 VarDeclaration v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); | |
570 v.semantic(sc); | |
571 v.parent = sc.parent; | |
572 //sc.insert(v); | |
573 | |
574 Expression c = new DeclarationExp(Loc(0), v); | |
575 c.type = v.type; | |
576 | |
577 for (size_t u = i; u < nargs; u++) | |
578 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
579 auto a = arguments[u]; |
0 | 580 if (tret && !(cast(TypeArray)tb).next.equals(a.type)) |
581 a = a.toDelegate(sc, tret); | |
582 | |
583 Expression e = new VarExp(loc, v); | |
584 e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
585 auto ae = new AssignExp(loc, e, a); |
0 | 586 |
587 version (DMDV2) { | |
588 ae.op = TOK.TOKconstruct; | |
589 } | |
590 | |
591 if (c) | |
592 c = new CommaExp(loc, c, ae); | |
593 else | |
594 c = ae; | |
595 } | |
596 | |
597 arg = new VarExp(loc, v); | |
598 if (c) | |
599 arg = new CommaExp(loc, c, arg); | |
600 break; | |
601 } | |
602 | |
603 case TY.Tclass: | |
604 { /* Set arg to be: | |
605 * new Tclass(arg0, arg1, ..., argn) | |
606 */ | |
607 Expressions args = new Expressions(); | |
608 args.setDim(nargs - i); | |
609 for (size_t u = i; u < nargs; u++) | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
610 args[u - i] = arguments[u]; |
0 | 611 arg = new NewExp(loc, null, null, p.type, args); |
612 break; | |
613 } | |
614 | |
615 default: | |
616 if (!arg) | |
617 { | |
618 error(loc, "not enough arguments"); | |
619 return; | |
620 } | |
621 break; | |
622 } | |
623 | |
624 arg = arg.semantic(sc); | |
625 //printf("\targ = '%s'\n", arg.toChars()); | |
626 arguments.setDim(i + 1); | |
627 done = 1; | |
628 } | |
629 | |
630 L1: | |
631 if (!(p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid)) | |
632 { | |
633 if (p.type != arg.type) | |
634 { | |
635 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); | |
109 | 636 if (arg.op == TOKtype) |
637 arg.error("cannot pass type %s as function argument", arg.toChars()); | |
0 | 638 arg = arg.implicitCastTo(sc, p.type); |
639 arg = arg.optimize(WANT.WANTvalue); | |
640 } | |
641 } | |
642 if (p.storageClass & STC.STCref) | |
643 { | |
644 arg = arg.toLvalue(sc, arg); | |
645 } | |
646 else if (p.storageClass & STC.STCout) | |
647 { | |
648 arg = arg.modifiableLvalue(sc, arg); | |
649 } | |
650 | |
109 | 651 tb = arg.type.toBasetype(); |
652 version(SARRAYVALUE) {} else | |
653 { | |
0 | 654 // Convert static arrays to pointers |
655 if (tb.ty == TY.Tsarray) | |
656 { | |
657 arg = arg.checkToPointer(); | |
658 } | |
109 | 659 } |
0 | 660 version (DMDV2) { |
661 if (tb.ty == TY.Tstruct && !(p.storageClass & (STC.STCref | STC.STCout))) | |
662 { | |
663 arg = callCpCtor(loc, sc, arg); | |
664 } | |
665 } | |
666 | |
667 // Convert lazy argument to a delegate | |
668 if (p.storageClass & STC.STClazy) | |
669 { | |
670 arg = arg.toDelegate(sc, p.type); | |
671 } | |
672 version (DMDV2) { | |
673 /* Look for arguments that cannot 'escape' from the called | |
674 * function. | |
675 */ | |
676 if (!tf.parameterEscapes(p)) | |
677 { | |
678 /* Function literals can only appear once, so if this | |
679 * appearance was scoped, there cannot be any others. | |
680 */ | |
681 if (arg.op == TOK.TOKfunction) | |
682 { | |
683 FuncExp fe = cast(FuncExp)arg; | |
684 fe.fd.tookAddressOf = 0; | |
685 } | |
686 | |
687 /* For passing a delegate to a scoped parameter, | |
688 * this doesn't count as taking the address of it. | |
689 * We only worry about 'escaping' references to the function. | |
690 */ | |
691 else if (arg.op == TOK.TOKdelegate) | |
692 { | |
693 DelegateExp de = cast(DelegateExp)arg; | |
694 if (de.e1.op == TOK.TOKvar) | |
695 { | |
696 VarExp ve = cast(VarExp)de.e1; | |
697 FuncDeclaration f = ve.var.isFuncDeclaration(); | |
698 if (f) | |
699 { | |
700 f.tookAddressOf--; | |
701 //printf("tookAddressOf = %d\n", f.tookAddressOf); | |
702 } | |
703 } | |
704 } | |
705 } | |
706 } | |
707 } | |
708 else | |
709 { | |
710 // If not D linkage, do promotions | |
711 if (tf.linkage != LINK.LINKd) | |
712 { | |
713 // Promote bytes, words, etc., to ints | |
714 arg = arg.integralPromotions(sc); | |
715 | |
716 // Promote floats to doubles | |
717 switch (arg.type.ty) | |
718 { | |
719 case TY.Tfloat32: | |
720 arg = arg.castTo(sc, Type.tfloat64); | |
721 break; | |
722 | |
723 case TY.Timaginary32: | |
724 arg = arg.castTo(sc, Type.timaginary64); | |
725 break; | |
726 default: | |
727 break; | |
728 } | |
729 } | |
730 | |
731 // Convert static arrays to dynamic arrays | |
732 tb = arg.type.toBasetype(); | |
733 if (tb.ty == TY.Tsarray) | |
734 { | |
735 TypeSArray ts = cast(TypeSArray)tb; | |
736 Type ta = ts.next.arrayOf(); | |
737 if (ts.size(arg.loc) == 0) | |
738 { | |
739 arg = new NullExp(arg.loc); | |
740 arg.type = ta; | |
741 } | |
742 else | |
743 { | |
744 arg = arg.castTo(sc, ta); | |
745 } | |
746 } | |
747 version (DMDV2) { | |
73 | 748 if (tb.ty == Tstruct) |
0 | 749 { |
750 arg = callCpCtor(loc, sc, arg); | |
751 } | |
73 | 752 } |
0 | 753 |
73 | 754 // Give error for overloaded function addresses |
755 if (arg.op == TOKsymoff) | |
756 { | |
757 SymOffExp se = cast(SymOffExp)arg; | |
758 version (DMDV2) { | |
759 bool aux = (se.hasOverloads != 0); | |
760 } else { | |
761 bool aux = true; | |
0 | 762 } |
73 | 763 if (aux && !se.var.isFuncDeclaration().isUnique()) |
764 arg.error("function %s is overloaded", arg.toChars()); | |
765 } | |
766 | |
767 arg.rvalue(); | |
768 } | |
769 | |
0 | 770 arg = arg.optimize(WANT.WANTvalue); |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
771 arguments[i] = arg; |
0 | 772 if (done) |
773 break; | |
774 } | |
775 | |
776 // If D linkage and variadic, add _arguments[] as first argument | |
777 if (tf.linkage == LINK.LINKd && tf.varargs == 1) | |
778 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
779 auto e = createTypeInfoArray(sc, &arguments[nparams], arguments.dim - nparams); |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
780 arguments.insert(0, e); |
0 | 781 } |
782 } | |
783 | |
16
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
784 /****************************** |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
785 * Perform canThrow() on an array of Expressions. |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
786 */ |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
787 |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
788 version (DMDV2) { |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
789 bool arrayExpressionCanThrow(Expressions exps) |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
790 { |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
791 if (exps) |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
792 { |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
793 foreach (e; exps) |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
794 { |
16
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
795 if (e && e.canThrow()) |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
796 return true; |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
797 } |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
798 } |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
799 return false; |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
800 } |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
801 } |
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
802 |
0 | 803 /**************************************** |
804 * Expand tuples. | |
805 */ | |
806 | |
807 void expandTuples(Expressions exps) | |
808 { | |
809 //printf("expandTuples()\n"); | |
810 if (exps) | |
811 { | |
812 for (size_t i = 0; i < exps.dim; i++) | |
813 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
814 auto arg = exps[i]; |
0 | 815 if (!arg) |
816 continue; | |
817 | |
818 // Look for tuple with 0 members | |
819 if (arg.op == TOK.TOKtype) | |
57 | 820 { |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
821 auto e = cast(TypeExp)arg; |
0 | 822 if (e.type.toBasetype().ty == TY.Ttuple) |
823 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
824 auto tt = cast(TypeTuple)e.type.toBasetype(); |
0 | 825 |
826 if (!tt.arguments || tt.arguments.dim == 0) | |
827 { | |
828 exps.remove(i); | |
829 if (i == exps.dim) | |
830 return; | |
831 i--; | |
832 continue; | |
833 } | |
834 } | |
835 } | |
836 | |
837 // Inline expand all the tuples | |
838 while (arg.op == TOK.TOKtuple) | |
839 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
840 auto te = cast(TupleExp)arg; |
0 | 841 |
842 exps.remove(i); // remove arg | |
57 | 843 exps.insert(i, te.exps); // replace with tuple contents |
0 | 844 |
845 if (i == exps.dim) | |
846 return; // empty tuple, no more arguments | |
847 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
848 arg = exps[i]; |
0 | 849 } |
850 } | |
851 } | |
852 } | |
853 | |
854 /************************************************** | |
855 * Write out argument types to buf. | |
856 */ | |
857 | |
858 void argExpTypesToCBuffer(OutBuffer buf, Expressions arguments, HdrGenState* hgs) | |
859 { | |
860 if (arguments) | |
861 { | |
862 scope OutBuffer argbuf = new OutBuffer(); | |
863 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
864 foreach (size_t i, Expression arg; arguments) |
0 | 865 { |
866 if (i) | |
867 buf.writeByte(','); | |
868 | |
869 argbuf.reset(); | |
870 arg.type.toCBuffer2(argbuf, hgs, MOD.MODundefined); | |
871 buf.write(argbuf); | |
872 } | |
873 } | |
874 } | |
875 | |
876 /**************************************** | |
877 * Determine if scope sc has package level access to s. | |
878 */ | |
879 | |
880 bool hasPackageAccess(Scope sc, Dsymbol s) | |
881 { | |
882 version (LOG) { | |
883 printf("hasPackageAccess(s = '%s', sc = '%p')\n", s.toChars(), sc); | |
884 } | |
885 | |
886 for (; s; s = s.parent) | |
887 { | |
888 if (s.isPackage() && !s.isModule()) | |
889 break; | |
890 } | |
891 version (LOG) { | |
892 if (s) | |
893 printf("\tthis is in package '%s'\n", s.toChars()); | |
894 } | |
895 | |
896 if (s && s == sc.module_.parent) | |
897 { | |
898 version (LOG) { | |
899 printf("\ts is in same package as sc\n"); | |
900 } | |
901 return true; | |
902 } | |
903 | |
904 | |
905 version (LOG) { | |
906 printf("\tno package access\n"); | |
907 } | |
908 | |
909 return false; | |
910 } | |
911 | |
912 /********************************************* | |
913 * Call copy constructor for struct value argument. | |
914 */ | |
915 version (DMDV2) { | |
916 Expression callCpCtor(Loc loc, Scope sc, Expression e) | |
917 { | |
918 Type tb = e.type.toBasetype(); | |
919 assert(tb.ty == Tstruct); | |
920 StructDeclaration sd = (cast(TypeStruct)tb).sym; | |
921 if (sd.cpctor) | |
922 { | |
923 /* Create a variable tmp, and replace the argument e with: | |
924 * (tmp = e),tmp | |
925 * and let AssignExp() handle the construction. | |
926 * This is not the most efficent, ideally tmp would be constructed | |
927 * directly onto the stack. | |
928 */ | |
929 Identifier idtmp = Lexer.uniqueId("__tmp"); | |
930 VarDeclaration tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(Loc(0), e)); | |
931 Expression ae = new DeclarationExp(loc, tmp); | |
932 e = new CommaExp(loc, ae, new VarExp(loc, tmp)); | |
933 e = e.semantic(sc); | |
934 } | |
935 return e; | |
936 } | |
937 } | |
938 | |
939 /*************************************** | |
940 * Create a static array of TypeInfo references | |
941 * corresponding to an array of Expression's. | |
942 * Used to supply hidden _arguments[] value for variadic D functions. | |
943 */ | |
944 | |
945 Expression createTypeInfoArray(Scope sc, Expression* exps, int dim) | |
946 { | |
79 | 947 static if (true) |
948 { | |
57 | 949 /* Get the corresponding TypeInfo_Tuple and |
950 * point at its elements[]. | |
951 */ | |
952 | |
953 /* Create the TypeTuple corresponding to the types of args[] | |
954 */ | |
955 Arguments args = new Arguments; | |
956 args.setDim(dim); | |
957 for (size_t i = 0; i < dim; i++) | |
958 { | |
959 Argument arg = new Argument(STCin, exps[i].type, null, null); | |
960 args.data[i] = cast(void*)arg; | |
961 } | |
962 TypeTuple tup = new TypeTuple(args); | |
963 Expression e = tup.getTypeInfo(sc); | |
964 e = e.optimize(WANTvalue); | |
965 assert(e.op == TOKsymoff); // should be SymOffExp | |
966 | |
79 | 967 version (BREAKABI) |
968 { | |
57 | 969 /* |
970 * Should just pass a reference to TypeInfo_Tuple instead, | |
971 * but that would require existing code to be recompiled. | |
972 * Source compatibility can be maintained by computing _arguments[] | |
973 * at the start of the called function by offseting into the | |
974 * TypeInfo_Tuple reference. | |
975 */ | |
976 | |
79 | 977 } |
978 else | |
979 { | |
57 | 980 // Advance to elements[] member of TypeInfo_Tuple |
981 SymOffExp se = cast(SymOffExp)e; | |
982 se.offset += PTRSIZE + PTRSIZE; | |
983 | |
984 // Set type to TypeInfo[]* | |
985 se.type = Type.typeinfo.type.arrayOf().pointerTo(); | |
986 | |
987 // Indirect to get the _arguments[] value | |
988 e = new PtrExp(Loc(0), se); | |
989 e.type = se.type.next; | |
990 } | |
991 return e; | |
79 | 992 } // of static if (true) |
993 else | |
994 { | |
57 | 995 /* Improvements: |
996 * 1) create an array literal instead, | |
997 * as it would eliminate the extra dereference of loading the | |
998 * static variable. | |
999 */ | |
1000 | |
1001 ArrayInitializer ai = new ArrayInitializer(Loc(0)); | |
1002 VarDeclaration v; | |
1003 Type t; | |
1004 Expression e; | |
1005 scope OutBuffer buf = new OutBuffer(); | |
1006 Identifier id; | |
1007 string name; | |
1008 | |
1009 // Generate identifier for _arguments[] | |
1010 buf.writestring("_arguments_"); | |
1011 for (int i = 0; i < dim; i++) | |
1012 { | |
1013 t = exps[i].type; | |
1014 t.toDecoBuffer(buf); | |
1015 } | |
1016 buf.writeByte(0); | |
1017 id = Lexer.idPool(buf.extractString()); | |
1018 | |
1019 Module m = sc.module_; | |
1020 Dsymbol s = m.symtab.lookup(id); | |
1021 | |
1022 if (s && s.parent == m) | |
1023 { | |
1024 // Use existing one | |
1025 v = s.isVarDeclaration(); | |
1026 assert(v); | |
1027 } | |
1028 else | |
1029 { | |
1030 // Generate new one | |
1031 | |
1032 for (int i = 0; i < dim; i++) | |
1033 { | |
1034 t = exps[i].type; | |
1035 e = t.getTypeInfo(sc); | |
1036 ai.addInit(new IntegerExp(i), new ExpInitializer(0, e)); | |
1037 } | |
1038 | |
1039 t = Type.typeinfo.type.arrayOf(); | |
1040 ai.type = t; | |
1041 v = new VarDeclaration(0, t, id, ai); | |
1042 m.members.push(v); | |
79 | 1043 m.symtabInsert(v); |
57 | 1044 sc = sc.push(); |
1045 sc.linkage = LINKc; | |
1046 sc.stc = STCstatic | STCcomdat; | |
1047 ai.semantic(sc, t); | |
1048 v.semantic(sc); | |
1049 v.parent = m; | |
1050 sc = sc.pop(); | |
1051 } | |
1052 e = new VarExp(0, v); | |
1053 e = e.semantic(sc); | |
1054 return e; | |
1055 } | |
0 | 1056 } |
1057 | |
1058 /************************************** | |
1059 * Evaluate builtin function. | |
1060 * Return result: null if cannot evaluate it. | |
1061 */ | |
1062 | |
53 | 1063 extern(C) extern real sinl(real); |
1064 extern(C) extern real cosl(real); | |
1065 extern(C) extern real tanl(real); | |
1066 extern(C) extern real sqrtl(real); | |
1067 extern(C) extern real fabsl(real); | |
1068 | |
0 | 1069 Expression eval_builtin(BUILTIN builtin, Expressions arguments) |
1070 { | |
53 | 1071 assert(arguments && arguments.dim); |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
1072 auto arg0 = arguments[0]; |
53 | 1073 Expression e = null; |
1074 switch (builtin) | |
1075 { | |
1076 case BUILTINsin: | |
1077 if (arg0.op == TOKfloat64) | |
1078 e = new RealExp(Loc(0), sinl(arg0.toReal()), arg0.type); | |
1079 break; | |
1080 | |
1081 case BUILTINcos: | |
1082 if (arg0.op == TOKfloat64) | |
1083 e = new RealExp(Loc(0), cosl(arg0.toReal()), arg0.type); | |
1084 break; | |
1085 | |
1086 case BUILTINtan: | |
1087 if (arg0.op == TOKfloat64) | |
1088 e = new RealExp(Loc(0), tanl(arg0.toReal()), arg0.type); | |
1089 break; | |
1090 | |
1091 case BUILTINsqrt: | |
1092 if (arg0.op == TOKfloat64) | |
1093 e = new RealExp(Loc(0), sqrtl(arg0.toReal()), arg0.type); | |
1094 break; | |
1095 | |
1096 case BUILTINfabs: | |
1097 if (arg0.op == TOKfloat64) | |
1098 e = new RealExp(Loc(0), fabsl(arg0.toReal()), arg0.type); | |
1099 break; | |
1100 } | |
1101 return e; | |
0 | 1102 } |
1103 | |
1104 Expression fromConstInitializer(int result, Expression e1) | |
1105 { | |
1106 //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars()); | |
1107 //static int xx; if (xx++ == 10) assert(0); | |
1108 Expression e = e1; | |
1109 if (e1.op == TOK.TOKvar) | |
1110 { | |
1111 VarExp ve = cast(VarExp)e1; | |
1112 VarDeclaration v = ve.var.isVarDeclaration(); | |
1113 e = expandVar(result, v); | |
1114 if (e) | |
1115 { | |
1116 if (e.type != e1.type) | |
1117 { | |
1118 // Type 'paint' operation | |
1119 e = e.copy(); | |
1120 e.type = e1.type; | |
1121 } | |
79 | 1122 e.loc = e1.loc; |
0 | 1123 } |
1124 else | |
1125 { | |
1126 e = e1; | |
1127 } | |
1128 } | |
1129 return e; | |
1130 } | |
1131 | |
1132 /************************************* | |
1133 * If variable has a const initializer, | |
1134 * return that initializer. | |
1135 */ | |
1136 | |
1137 Expression expandVar(int result, VarDeclaration v) | |
1138 { | |
1139 //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null"); | |
1140 | |
1141 Expression e = null; | |
1142 if (!v) | |
1143 return e; | |
1144 | |
1145 if (v.isConst() || v.isInvariant() || v.storage_class & STC.STCmanifest) | |
1146 { | |
1147 if (!v.type) | |
1148 { | |
1149 //error("ICE"); | |
1150 return e; | |
1151 } | |
1152 | |
1153 Type tb = v.type.toBasetype(); | |
1154 if (result & WANT.WANTinterpret || v.storage_class & STC.STCmanifest || (tb.ty != TY.Tsarray && tb.ty != TY.Tstruct)) | |
1155 { | |
1156 if (v.init) | |
1157 { | |
1158 if (v.inuse) | |
1159 { | |
1160 if (v.storage_class & STC.STCmanifest) | |
1161 v.error("recursive initialization of constant"); | |
1162 goto L1; | |
1163 } | |
1164 Expression ei = v.init.toExpression(); | |
1165 if (!ei) | |
1166 goto L1; | |
1167 if (ei.op == TOK.TOKconstruct || ei.op == TOK.TOKblit) | |
1168 { | |
1169 AssignExp ae = cast(AssignExp)ei; | |
1170 ei = ae.e2; | |
1171 if (ei.isConst() != 1 && ei.op != TOK.TOKstring) | |
1172 goto L1; | |
1173 if (ei.type != v.type) | |
1174 goto L1; | |
1175 } | |
1176 if (v.scope_) | |
1177 { | |
1178 v.inuse++; | |
1179 e = ei.syntaxCopy(); | |
1180 e = e.semantic(v.scope_); | |
1181 e = e.implicitCastTo(v.scope_, v.type); | |
1182 // enabling this line causes test22 in test suite to fail | |
1183 //ei.type = e.type; | |
1184 v.scope_ = null; | |
1185 v.inuse--; | |
1186 } | |
1187 else if (!ei.type) | |
1188 { | |
1189 goto L1; | |
1190 } | |
1191 else | |
1192 // Should remove the copy() operation by | |
1193 // making all mods to expressions copy-on-write | |
1194 e = ei.copy(); | |
1195 } | |
1196 else | |
1197 { | |
1198 static if (true) { | |
1199 goto L1; | |
1200 } else { | |
1201 // BUG: what if const is initialized in constructor? | |
1202 e = v.type.defaultInit(); | |
1203 e.loc = e1.loc; | |
1204 } | |
1205 } | |
1206 if (e.type != v.type) | |
1207 { | |
1208 e = e.castTo(null, v.type); | |
1209 } | |
1210 v.inuse++; | |
1211 e = e.optimize(result); | |
1212 v.inuse--; | |
1213 } | |
1214 } | |
1215 L1: | |
1216 //if (e) printf("\te = %s, e.type = %s\n", e.toChars(), e.type.toChars()); | |
1217 return e; | |
1218 } | |
1219 | |
1220 /**************************************** | |
1221 * Check access to d for expression e.d | |
1222 */ | |
1223 | |
1224 void accessCheck(Loc loc, Scope sc, Expression e, Declaration d) | |
1225 { | |
1226 version (LOG) { | |
1227 if (e) | |
1228 { | |
1229 printf("accessCheck(%s . %s)\n", e.toChars(), d.toChars()); | |
1230 printf("\te.type = %s\n", e.type.toChars()); | |
1231 } | |
1232 else | |
1233 { | |
1234 //printf("accessCheck(%s)\n", d.toChars()); | |
1235 } | |
1236 } | |
1237 if (!e) | |
1238 { | |
1239 if (d.prot() == PROT.PROTprivate && d.getModule() != sc.module_ || | |
1240 d.prot() == PROT.PROTpackage && !hasPackageAccess(sc, d)) | |
1241 | |
1242 error(loc, "%s %s.%s is not accessible from %s", | |
1243 d.kind(), d.getModule().toChars(), d.toChars(), sc.module_.toChars()); | |
1244 } | |
1245 else if (e.type.ty == TY.Tclass) | |
1246 { | |
1247 // Do access check | |
1248 ClassDeclaration cd; | |
1249 | |
1250 cd = cast(ClassDeclaration)((cast(TypeClass)e.type).sym); | |
1251 static if (true) { | |
1252 if (e.op == TOK.TOKsuper) | |
1253 { | |
1254 ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration(); | |
1255 if (cd2) | |
1256 cd = cd2; | |
1257 } | |
1258 } | |
1259 cd.accessCheck(loc, sc, d); | |
1260 } | |
1261 else if (e.type.ty == TY.Tstruct) | |
1262 { | |
1263 // Do access check | |
1264 StructDeclaration cd = cast(StructDeclaration)((cast(TypeStruct)e.type).sym); | |
1265 cd.accessCheck(loc, sc, d); | |
1266 } | |
1267 } | |
1268 | |
1269 /***************************************** | |
1270 * Given array of arguments and an aggregate type, | |
1271 * if any of the argument types are missing, attempt to infer | |
1272 * them from the aggregate type. | |
1273 */ | |
1274 | |
1275 void inferApplyArgTypes(TOK op, Arguments arguments, Expression aggr) | |
1276 { | |
1277 if (!arguments || !arguments.dim) | |
1278 return; | |
1279 | |
1280 /* Return if no arguments need types. | |
1281 */ | |
1282 for (size_t u = 0; 1; u++) | |
1283 { | |
1284 if (u == arguments.dim) | |
1285 return; | |
1286 | |
1287 Argument arg = cast(Argument)arguments.data[u]; | |
1288 if (!arg.type) | |
1289 break; | |
1290 } | |
1291 | |
1292 AggregateDeclaration ad; | |
1293 | |
1294 Argument arg = cast(Argument)arguments.data[0]; | |
1295 Type taggr = aggr.type; | |
1296 if (!taggr) | |
1297 return; | |
1298 Type tab = taggr.toBasetype(); | |
1299 switch (tab.ty) | |
1300 { | |
1301 case TY.Tarray: | |
1302 case TY.Tsarray: | |
1303 case TY.Ttuple: | |
1304 if (arguments.dim == 2) | |
1305 { | |
1306 if (!arg.type) | |
1307 arg.type = Type.tsize_t; // key type | |
1308 arg = cast(Argument)arguments.data[1]; | |
1309 } | |
1310 if (!arg.type && tab.ty != TY.Ttuple) | |
1311 arg.type = tab.nextOf(); // value type | |
1312 break; | |
1313 | |
1314 case TY.Taarray: | |
1315 { | |
1316 TypeAArray taa = cast(TypeAArray)tab; | |
1317 | |
1318 if (arguments.dim == 2) | |
1319 { | |
1320 if (!arg.type) | |
1321 arg.type = taa.index; // key type | |
1322 arg = cast(Argument)arguments.data[1]; | |
1323 } | |
1324 if (!arg.type) | |
1325 arg.type = taa.next; // value type | |
1326 break; | |
1327 } | |
1328 | |
1329 case TY.Tclass: | |
1330 ad = (cast(TypeClass)tab).sym; | |
1331 goto Laggr; | |
1332 | |
1333 case TY.Tstruct: | |
1334 ad = (cast(TypeStruct)tab).sym; | |
1335 goto Laggr; | |
1336 | |
1337 Laggr: | |
1338 if (arguments.dim == 1) | |
1339 { | |
1340 if (!arg.type) | |
1341 { | |
1342 /* Look for a head() or rear() overload | |
1343 */ | |
1344 Identifier id = (op == TOK.TOKforeach) ? Id.Fhead : Id.Ftoe; | |
1345 Dsymbol s = search_function(ad, id); | |
1346 FuncDeclaration fd = s ? s.isFuncDeclaration() : null; | |
1347 if (!fd) | |
1348 { | |
1349 if (s && s.isTemplateDeclaration()) | |
1350 break; | |
1351 goto Lapply; | |
1352 } | |
1353 arg.type = fd.type.nextOf(); | |
1354 } | |
1355 break; | |
1356 } | |
1357 | |
1358 Lapply: | |
1359 { /* Look for an | |
1360 * int opApply(int delegate(ref Type [, ...]) dg); | |
1361 * overload | |
1362 */ | |
1363 Dsymbol s = search_function(ad, (op == TOK.TOKforeach_reverse) ? Id.applyReverse : Id.apply); | |
1364 if (s) | |
1365 { | |
1366 FuncDeclaration fd = s.isFuncDeclaration(); | |
1367 if (fd) | |
1368 { | |
1369 inferApplyArgTypesX(fd, arguments); | |
1370 break; | |
1371 } | |
1372 static if (false) { | |
1373 TemplateDeclaration td = s.isTemplateDeclaration(); | |
1374 if (td) | |
1375 { | |
1376 inferApplyArgTypesZ(td, arguments); | |
1377 break; | |
1378 } | |
1379 } | |
1380 } | |
1381 break; | |
1382 } | |
1383 | |
1384 case TY.Tdelegate: | |
1385 { | |
1386 if (0 && aggr.op == TOK.TOKdelegate) | |
1387 { | |
1388 DelegateExp de = cast(DelegateExp)aggr; | |
1389 | |
1390 FuncDeclaration fd = de.func.isFuncDeclaration(); | |
1391 if (fd) | |
1392 inferApplyArgTypesX(fd, arguments); | |
1393 } | |
1394 else | |
1395 { | |
1396 inferApplyArgTypesY(cast(TypeFunction)tab.nextOf(), arguments); | |
1397 } | |
1398 break; | |
1399 } | |
1400 | |
1401 default: | |
1402 break; // ignore error, caught later | |
1403 } | |
1404 } | |
1405 | |
1406 struct Param3 | |
1407 { | |
1408 /******************************** | |
1409 * Recursive helper function, | |
1410 * analogous to func.overloadResolveX(). | |
1411 */ | |
1412 | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
1413 int fp3(void*, FuncDeclaration f) |
0 | 1414 { |
1415 TypeFunction tf = cast(TypeFunction)f.type; | |
1416 if (inferApplyArgTypesY(tf, arguments) == 1) | |
1417 return 0; | |
1418 | |
1419 if (arguments.dim == 0) | |
1420 return 1; | |
1421 | |
1422 return 0; | |
1423 } | |
1424 | |
1425 Arguments arguments; | |
1426 } | |
1427 | |
1428 void inferApplyArgTypesX(FuncDeclaration fstart, Arguments arguments) | |
1429 { | |
1430 Param3 p3; | |
1431 p3.arguments = arguments; | |
17
ddae60498573
Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
Robert Clipsham <robert@octarineparrot.com>
parents:
16
diff
changeset
|
1432 overloadApply(fstart, &p3.fp3, cast(void*)arguments); |
0 | 1433 } |
1434 | |
1435 /****************************** | |
1436 * Infer arguments from type of function. | |
1437 * Returns: | |
1438 * 0 match for this function | |
1439 * 1 no match for this function | |
1440 */ | |
1441 | |
1442 int inferApplyArgTypesY(TypeFunction tf, Arguments arguments) | |
1443 { | |
1444 size_t nparams; | |
1445 Argument p; | |
1446 | |
1447 if (Argument.dim(tf.parameters) != 1) | |
1448 goto Lnomatch; | |
1449 | |
1450 p = Argument.getNth(tf.parameters, 0); | |
1451 if (p.type.ty != TY.Tdelegate) | |
1452 goto Lnomatch; | |
1453 | |
1454 tf = cast(TypeFunction)p.type.nextOf(); | |
1455 assert(tf.ty == TY.Tfunction); | |
1456 | |
1457 /* We now have tf, the type of the delegate. Match it against | |
1458 * the arguments, filling in missing argument types. | |
1459 */ | |
1460 nparams = Argument.dim(tf.parameters); | |
1461 if (nparams == 0 || tf.varargs) | |
1462 goto Lnomatch; // not enough parameters | |
1463 if (arguments.dim != nparams) | |
1464 goto Lnomatch; // not enough parameters | |
1465 | |
1466 for (size_t u = 0; u < nparams; u++) | |
1467 { | |
1468 Argument arg = cast(Argument)arguments.data[u]; | |
1469 Argument param = Argument.getNth(tf.parameters, u); | |
1470 if (arg.type) | |
1471 { | |
1472 if (!arg.type.equals(param.type)) | |
1473 { | |
1474 /* Cannot resolve argument types. Indicate an | |
1475 * error by setting the number of arguments to 0. | |
1476 */ | |
1477 arguments.dim = 0; | |
1478 goto Lmatch; | |
1479 } | |
1480 continue; | |
1481 } | |
1482 arg.type = param.type; | |
1483 } | |
1484 | |
1485 Lmatch: | |
1486 return 0; | |
1487 | |
1488 Lnomatch: | |
1489 return 1; | |
1490 } | |
1491 | |
1492 /************************************************** | |
1493 * Write expression out to buf, but wrap it | |
1494 * in ( ) if its precedence is less than pr. | |
1495 */ | |
1496 | |
1497 void expToCBuffer(OutBuffer buf, HdrGenState* hgs, Expression e, PREC pr) | |
1498 { | |
1499 //if (precedence[e.op] == 0) e.dump(0); | |
1500 if (precedence[e.op] < pr || | |
1501 /* Despite precedence, we don't allow a<b<c expressions. | |
1502 * They must be parenthesized. | |
1503 */ | |
1504 (pr == PREC.PREC_rel && precedence[e.op] == pr)) | |
1505 { | |
1506 buf.writeByte('('); | |
1507 e.toCBuffer(buf, hgs); | |
1508 buf.writeByte(')'); | |
1509 } | |
1510 else | |
1511 e.toCBuffer(buf, hgs); | |
1512 } | |
1513 | |
1514 /************************************************** | |
1515 * Write out argument list to buf. | |
1516 */ | |
1517 | |
1518 void argsToCBuffer(OutBuffer buf, Expressions arguments, HdrGenState* hgs) | |
1519 { | |
1520 if (arguments) | |
1521 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
1522 foreach (size_t i, Expression arg; arguments) |
0 | 1523 { |
1524 if (arg) | |
1525 { | |
1526 if (i) | |
1527 buf.writeByte(','); | |
1528 expToCBuffer(buf, hgs, arg, PREC.PREC_assign); | |
1529 } | |
1530 } | |
1531 } | |
16
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
1532 } |
53 | 1533 |
1534 ulong getMask(ulong v) | |
1535 { | |
1536 ulong u = 0; | |
1537 if (v >= 0x80) | |
1538 u = 0xFF; | |
1539 while (u < v) | |
1540 u = (u << 1) | 1; | |
1541 return u; | |
64 | 1542 } |
1543 | |
1544 /****************************** | |
1545 * Perform scanForNestedRef() on an array of Expressions. | |
1546 */ | |
1547 | |
1548 void arrayExpressionScanForNestedRef(Scope sc, Expressions a) | |
1549 { | |
1550 //printf("arrayExpressionScanForNestedRef(%p)\n", a); | |
1551 if (a) | |
1552 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
1553 foreach (e; a) |
64 | 1554 { |
1555 if (e) | |
1556 { | |
1557 e.scanForNestedRef(sc); | |
1558 } | |
1559 } | |
1560 } | |
53 | 1561 } |