Mercurial > projects > ddmd
comparison dmd/BinExp.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 832f71e6f96c |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:10317f0c89a5 |
---|---|
1 module dmd.BinExp; | |
2 | |
3 import dmd.Expression; | |
4 import dmd.Loc; | |
5 import dmd.ClassDeclaration; | |
6 import dmd.OutBuffer; | |
7 import dmd.HdrGenState; | |
8 import dmd.TOK; | |
9 import dmd.IRState; | |
10 import dmd.Scope; | |
11 import dmd.Type; | |
12 import dmd.InterState; | |
13 import dmd.InlineCostState; | |
14 import dmd.InlineScanState; | |
15 import dmd.InlineDoState; | |
16 import dmd.AggregateDeclaration; | |
17 import dmd.Identifier; | |
18 import dmd.MATCH; | |
19 import dmd.declaration.Match; | |
20 import dmd.ArrayTypes; | |
21 import dmd.TY; | |
22 import dmd.TypeClass; | |
23 import dmd.TypeStruct; | |
24 import dmd.Dsymbol; | |
25 import dmd.FuncDeclaration; | |
26 import dmd.TemplateDeclaration; | |
27 import dmd.DotIdExp; | |
28 import dmd.ErrorExp; | |
29 import dmd.WANT; | |
30 import dmd.IntegerExp; | |
31 import dmd.MulExp; | |
32 import dmd.Token; | |
33 import dmd.PREC; | |
34 | |
35 import dmd.expression.Util; | |
36 | |
37 import dmd.backend.elem; | |
38 import dmd.backend.Util; | |
39 | |
40 import std.stdio : writef; | |
41 | |
42 /************************************** | |
43 * Combine types. | |
44 * Output: | |
45 * *pt merged type, if *pt is not null | |
46 * *pe1 rewritten e1 | |
47 * *pe2 rewritten e2 | |
48 * Returns: | |
49 * !=0 success | |
50 * 0 failed | |
51 */ | |
52 | |
53 int typeMerge(Scope sc, Expression e, Type* pt, Expression* pe1, Expression* pe2) | |
54 { | |
55 //printf("typeMerge() %s op %s\n", (*pe1).toChars(), (*pe2).toChars()); | |
56 //dump(0); | |
57 | |
58 Expression e1 = (*pe1).integralPromotions(sc); | |
59 Expression e2 = (*pe2).integralPromotions(sc); | |
60 | |
61 Type t1 = e1.type; | |
62 Type t2 = e2.type; | |
63 assert(t1); | |
64 Type t = t1; | |
65 | |
66 //if (t1) printf("\tt1 = %s\n", t1.toChars()); | |
67 //if (t2) printf("\tt2 = %s\n", t2.toChars()); | |
68 debug { | |
69 if (!t2) writef("\te2 = '%s'\n", e2.toChars()); | |
70 } | |
71 assert(t2); | |
72 | |
73 Type t1b = t1.toBasetype(); | |
74 Type t2b = t2.toBasetype(); | |
75 | |
76 TY ty = cast(TY)Type.impcnvResult[t1b.ty][t2b.ty]; | |
77 if (ty != TY.Terror) | |
78 { | |
79 TY ty1; | |
80 TY ty2; | |
81 | |
82 ty1 = cast(TY)Type.impcnvType1[t1b.ty][t2b.ty]; | |
83 ty2 = cast(TY)Type.impcnvType2[t1b.ty][t2b.ty]; | |
84 | |
85 if (t1b.ty == ty1) // if no promotions | |
86 { | |
87 if (t1 == t2) | |
88 { | |
89 t = t1; | |
90 goto Lret; | |
91 } | |
92 | |
93 if (t1b == t2b) | |
94 { | |
95 t = t1b; | |
96 goto Lret; | |
97 } | |
98 } | |
99 | |
100 t = Type.basic[ty]; | |
101 | |
102 t1 = Type.basic[ty1]; | |
103 t2 = Type.basic[ty2]; | |
104 | |
105 e1 = e1.castTo(sc, t1); | |
106 e2 = e2.castTo(sc, t2); | |
107 //printf("after typeCombine():\n"); | |
108 //dump(0); | |
109 //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); | |
110 goto Lret; | |
111 } | |
112 | |
113 t1 = t1b; | |
114 t2 = t2b; | |
115 | |
116 Lagain: | |
117 if (t1 == t2) | |
118 { | |
119 } | |
120 else if (t1.ty == TY.Tpointer && t2.ty == TY.Tpointer) | |
121 { | |
122 // Bring pointers to compatible type | |
123 Type t1n = t1.nextOf(); | |
124 Type t2n = t2.nextOf(); | |
125 | |
126 if (t1n == t2n) { | |
127 ; | |
128 } else if (t1n.ty == TY.Tvoid) {// pointers to void are always compatible | |
129 t = t2; | |
130 } else if (t2n.ty == TY.Tvoid) { | |
131 ; | |
132 } else if (t1n.mod != t2n.mod) { | |
133 t1 = t1n.mutableOf().constOf().pointerTo(); | |
134 t2 = t2n.mutableOf().constOf().pointerTo(); | |
135 t = t1; | |
136 goto Lagain; | |
137 } else if (t1n.ty == TY.Tclass && t2n.ty == TY.Tclass) { | |
138 ClassDeclaration cd1 = t1n.isClassHandle(); | |
139 ClassDeclaration cd2 = t2n.isClassHandle(); | |
140 int offset; | |
141 | |
142 if (cd1.isBaseOf(cd2, &offset)) | |
143 { | |
144 if (offset) | |
145 e2 = e2.castTo(sc, t); | |
146 } | |
147 else if (cd2.isBaseOf(cd1, &offset)) | |
148 { | |
149 t = t2; | |
150 if (offset) | |
151 e1 = e1.castTo(sc, t); | |
152 } | |
153 else | |
154 goto Lincompatible; | |
155 } else { | |
156 goto Lincompatible; | |
157 } | |
158 } | |
159 else if ((t1.ty == TY.Tsarray || t1.ty == TY.Tarray) && | |
160 e2.op == TOK.TOKnull && t2.ty == TY.Tpointer && t2.nextOf().ty == TY.Tvoid) | |
161 { /* (T[n] op void*) | |
162 * (T[] op void*) | |
163 */ | |
164 goto Lx1; | |
165 } | |
166 else if ((t2.ty == TY.Tsarray || t2.ty == TY.Tarray) && | |
167 e1.op == TOK.TOKnull && t1.ty == TY.Tpointer && t1.nextOf().ty == TY.Tvoid) | |
168 { /* (void* op T[n]) | |
169 * (void* op T[]) | |
170 */ | |
171 goto Lx2; | |
172 } | |
173 else if ((t1.ty == TY.Tsarray || t1.ty == TY.Tarray) && t1.implicitConvTo(t2)) | |
174 { | |
175 goto Lt2; | |
176 } | |
177 else if ((t2.ty == TY.Tsarray || t2.ty == TY.Tarray) && t2.implicitConvTo(t1)) | |
178 { | |
179 goto Lt1; | |
180 } | |
181 /* If one is mutable and the other invariant, then retry | |
182 * with both of them as const | |
183 */ | |
184 else if ((t1.ty == TY.Tsarray || t1.ty == TY.Tarray || t1.ty == TY.Tpointer) && | |
185 (t2.ty == TY.Tsarray || t2.ty == TY.Tarray || t2.ty == TY.Tpointer) && | |
186 t1.nextOf().mod != t2.nextOf().mod | |
187 ) | |
188 { | |
189 if (t1.ty == TY.Tpointer) | |
190 t1 = t1.nextOf().mutableOf().constOf().pointerTo(); | |
191 else | |
192 t1 = t1.nextOf().mutableOf().constOf().arrayOf(); | |
193 | |
194 if (t2.ty == TY.Tpointer) | |
195 t2 = t2.nextOf().mutableOf().constOf().pointerTo(); | |
196 else | |
197 t2 = t2.nextOf().mutableOf().constOf().arrayOf(); | |
198 t = t1; | |
199 goto Lagain; | |
200 } | |
201 else if (t1.ty == TY.Tclass || t2.ty == TY.Tclass) | |
202 { | |
203 while (1) | |
204 { | |
205 int i1 = e2.implicitConvTo(t1); | |
206 int i2 = e1.implicitConvTo(t2); | |
207 | |
208 if (i1 && i2) | |
209 { | |
210 // We have the case of class vs. void*, so pick class | |
211 if (t1.ty == TY.Tpointer) | |
212 i1 = 0; | |
213 else if (t2.ty == TY.Tpointer) | |
214 i2 = 0; | |
215 } | |
216 | |
217 if (i2) | |
218 { | |
219 goto Lt2; | |
220 } | |
221 else if (i1) | |
222 { | |
223 goto Lt1; | |
224 } | |
225 else if (t1.ty == TY.Tclass && t2.ty == TY.Tclass) | |
226 { | |
227 TypeClass tc1 = cast(TypeClass)t1; | |
228 TypeClass tc2 = cast(TypeClass)t2; | |
229 | |
230 /* Pick 'tightest' type | |
231 */ | |
232 ClassDeclaration cd1 = tc1.sym.baseClass; | |
233 ClassDeclaration cd2 = tc2.sym.baseClass; | |
234 | |
235 if (cd1 && cd2) | |
236 { t1 = cd1.type; | |
237 t2 = cd2.type; | |
238 } | |
239 else if (cd1) | |
240 t1 = cd1.type; | |
241 else if (cd2) | |
242 t2 = cd2.type; | |
243 else | |
244 goto Lincompatible; | |
245 } | |
246 else | |
247 goto Lincompatible; | |
248 } | |
249 } | |
250 else if (t1.ty == TY.Tstruct && t2.ty == TY.Tstruct) | |
251 { | |
252 if ((cast(TypeStruct)t1).sym != (cast(TypeStruct)t2).sym) | |
253 goto Lincompatible; | |
254 } | |
255 else if ((e1.op == TOK.TOKstring || e1.op == TOK.TOKnull) && e1.implicitConvTo(t2)) | |
256 { | |
257 goto Lt2; | |
258 } | |
259 else if ((e2.op == TOK.TOKstring || e2.op == TOK.TOKnull) && e2.implicitConvTo(t1)) | |
260 { | |
261 goto Lt1; | |
262 } | |
263 else if (t1.ty == TY.Tsarray && t2.ty == TY.Tsarray && | |
264 e2.implicitConvTo(t1.nextOf().arrayOf())) | |
265 { | |
266 Lx1: | |
267 t = t1.nextOf().arrayOf(); | |
268 e1 = e1.castTo(sc, t); | |
269 e2 = e2.castTo(sc, t); | |
270 } | |
271 else if (t1.ty == TY.Tsarray && t2.ty == TY.Tsarray && | |
272 e1.implicitConvTo(t2.nextOf().arrayOf())) | |
273 { | |
274 Lx2: | |
275 t = t2.nextOf().arrayOf(); | |
276 e1 = e1.castTo(sc, t); | |
277 e2 = e2.castTo(sc, t); | |
278 } | |
279 else if (t1.isintegral() && t2.isintegral()) | |
280 { | |
281 assert(0); | |
282 } | |
283 else if (e1.op == TOK.TOKslice && t1.ty == TY.Tarray && | |
284 e2.implicitConvTo(t1.nextOf())) | |
285 { // T[] op T | |
286 e2 = e2.castTo(sc, t1.nextOf()); | |
287 t = t1.nextOf().arrayOf(); | |
288 } | |
289 else if (e2.op == TOK.TOKslice && t2.ty == TY.Tarray && | |
290 e1.implicitConvTo(t2.nextOf())) | |
291 { // T op T[] | |
292 e1 = e1.castTo(sc, t2.nextOf()); | |
293 t = t2.nextOf().arrayOf(); | |
294 | |
295 //printf("test %s\n", e.toChars()); | |
296 e1 = e1.optimize(WANT.WANTvalue); | |
297 if (e && e.isCommutative() && e1.isConst()) | |
298 { /* Swap operands to minimize number of functions generated | |
299 */ | |
300 //printf("swap %s\n", e.toChars()); | |
301 Expression tmp = e1; | |
302 e1 = e2; | |
303 e2 = tmp; | |
304 } | |
305 } | |
306 else | |
307 { | |
308 Lincompatible: | |
309 return 0; | |
310 } | |
311 Lret: | |
312 if (!*pt) | |
313 *pt = t; | |
314 *pe1 = e1; | |
315 *pe2 = e2; | |
316 static if (false) { | |
317 printf("-typeMerge() %s op %s\n", e1.toChars(), e2.toChars()); | |
318 if (e1.type) printf("\tt1 = %s\n", e1.type.toChars()); | |
319 if (e2.type) printf("\tt2 = %s\n", e2.type.toChars()); | |
320 printf("\ttype = %s\n", t.toChars()); | |
321 } | |
322 //dump(0); | |
323 return 1; | |
324 | |
325 | |
326 Lt1: | |
327 e2 = e2.castTo(sc, t1); | |
328 t = t1; | |
329 goto Lret; | |
330 | |
331 Lt2: | |
332 e1 = e1.castTo(sc, t2); | |
333 t = t2; | |
334 goto Lret; | |
335 } | |
336 | |
337 class BinExp : Expression | |
338 { | |
339 Expression e1; | |
340 Expression e2; | |
341 | |
342 this(Loc loc, TOK op, int size, Expression e1, Expression e2) | |
343 { | |
344 super(loc, op, size); | |
345 this.e1 = e1; | |
346 this.e2 = e2; | |
347 } | |
348 | |
349 Expression syntaxCopy() | |
350 { | |
351 BinExp e = cast(BinExp)copy(); | |
352 e.type = null; | |
353 e.e1 = e.e1.syntaxCopy(); | |
354 e.e2 = e.e2.syntaxCopy(); | |
355 | |
356 return e; | |
357 } | |
358 | |
359 Expression semantic(Scope sc) | |
360 { | |
361 version (LOGSEMANTIC) { | |
362 printf("BinExp.semantic('%s')\n", toChars()); | |
363 } | |
364 e1 = e1.semantic(sc); | |
365 if (!e1.type && !(op == TOK.TOKassign && e1.op == TOK.TOKdottd)) // a.template = e2 | |
366 { | |
367 error("%s has no value", e1.toChars()); | |
368 e1.type = Type.terror; | |
369 } | |
370 e2 = e2.semantic(sc); | |
371 if (!e2.type) | |
372 { | |
373 error("%s has no value", e2.toChars()); | |
374 e2.type = Type.terror; | |
375 } | |
376 return this; | |
377 } | |
378 | |
379 Expression semanticp(Scope sc) | |
380 { | |
381 version (LOGSEMANTIC) { | |
382 printf("BinExp.semantic('%s')\n", toChars()); | |
383 } | |
384 e1 = e1.semantic(sc); | |
385 if (!e1.type && | |
386 !(op == TOK.TOKassign && e1.op == TOK.TOKdottd)) // a.template = e2 | |
387 { | |
388 error("%s has no value", e1.toChars()); | |
389 e1.type = Type.terror; | |
390 } | |
391 e2 = e2.semantic(sc); | |
392 if (!e2.type) | |
393 { | |
394 error("%s has no value", e2.toChars()); | |
395 e2.type = Type.terror; | |
396 } | |
397 return this; | |
398 } | |
399 | |
400 Expression commonSemanticAssign(Scope sc) | |
401 { | |
402 assert(false); | |
403 } | |
404 | |
405 Expression commonSemanticAssignIntegral(Scope sc) | |
406 { | |
407 Expression e; | |
408 | |
409 if (!type) | |
410 { | |
411 BinExp.semantic(sc); | |
412 e2 = resolveProperties(sc, e2); | |
413 | |
414 e = op_overload(sc); | |
415 if (e) | |
416 return e; | |
417 | |
418 if (e1.op == TOK.TOKslice) | |
419 { // T[] op= ... | |
420 typeCombine(sc); | |
421 type = e1.type; | |
422 return arrayOp(sc); | |
423 } | |
424 | |
425 e1 = e1.modifiableLvalue(sc, e1); | |
426 e1.checkScalar(); | |
427 type = e1.type; | |
428 if (type.toBasetype().ty == TY.Tbool) | |
429 { | |
430 e2 = e2.implicitCastTo(sc, type); | |
431 } | |
432 | |
433 typeCombine(sc); | |
434 e1.checkIntegral(); | |
435 e2.checkIntegral(); | |
436 } | |
437 | |
438 return this; | |
439 } | |
440 | |
441 bool checkSideEffect(int flag) | |
442 { | |
443 switch (op) { | |
444 case TOK.TOKplusplus: | |
445 case TOK.TOKminusminus: | |
446 case TOK.TOKassign: | |
447 case TOK.TOKconstruct: | |
448 case TOK.TOKblit: | |
449 case TOK.TOKaddass: | |
450 case TOK.TOKminass: | |
451 case TOK.TOKcatass: | |
452 case TOK.TOKmulass: | |
453 case TOK.TOKdivass: | |
454 case TOK.TOKmodass: | |
455 case TOK.TOKshlass: | |
456 case TOK.TOKshrass: | |
457 case TOK.TOKushrass: | |
458 case TOK.TOKandass: | |
459 case TOK.TOKorass: | |
460 case TOK.TOKxorass: | |
461 case TOK.TOKin: | |
462 case TOK.TOKremove: | |
463 return true; | |
464 | |
465 default: | |
466 return Expression.checkSideEffect(flag); | |
467 } | |
468 } | |
469 | |
470 void toCBuffer(OutBuffer buf, HdrGenState* hgs) | |
471 { | |
472 expToCBuffer(buf, hgs, e1, precedence[op]); | |
473 buf.writeByte(' '); | |
474 buf.writestring(Token.toChars(op)); | |
475 buf.writeByte(' '); | |
476 expToCBuffer(buf, hgs, e2, cast(PREC)(precedence[op] + 1)); | |
477 } | |
478 | |
479 /**************************************** | |
480 * Scale addition/subtraction to/from pointer. | |
481 */ | |
482 Expression scaleFactor(Scope sc) | |
483 { | |
484 ulong stride; | |
485 Type t1b = e1.type.toBasetype(); | |
486 Type t2b = e2.type.toBasetype(); | |
487 | |
488 if (t1b.ty == Tpointer && t2b.isintegral()) | |
489 { | |
490 // Need to adjust operator by the stride | |
491 // Replace (ptr + int) with (ptr + (int * stride)) | |
492 Type t = Type.tptrdiff_t; | |
493 | |
494 stride = t1b.nextOf().size(loc); | |
495 if (!t.equals(t2b)) | |
496 e2 = e2.castTo(sc, t); | |
497 e2 = new MulExp(loc, e2, new IntegerExp(Loc(0), stride, t)); | |
498 e2.type = t; | |
499 type = e1.type; | |
500 } | |
501 else if (t2b.ty == Tpointer && t1b.isintegral()) | |
502 { | |
503 // Need to adjust operator by the stride | |
504 // Replace (int + ptr) with (ptr + (int * stride)) | |
505 Type t = Type.tptrdiff_t; | |
506 Expression e; | |
507 | |
508 stride = t2b.nextOf().size(loc); | |
509 if (!t.equals(t1b)) | |
510 e = e1.castTo(sc, t); | |
511 else | |
512 e = e1; | |
513 e = new MulExp(loc, e, new IntegerExp(Loc(0), stride, t)); | |
514 e.type = t; | |
515 type = e2.type; | |
516 e1 = e2; | |
517 e2 = e; | |
518 } | |
519 return this; | |
520 } | |
521 | |
522 /************************************ | |
523 * Bring leaves to common type. | |
524 */ | |
525 Expression typeCombine(Scope sc) | |
526 { | |
527 Type t1 = e1.type.toBasetype(); | |
528 Type t2 = e2.type.toBasetype(); | |
529 | |
530 if (op == TOK.TOKmin || op == TOK.TOKadd) | |
531 { | |
532 if (t1.ty == TY.Tstruct) | |
533 { | |
534 if (t2.ty == TY.Tstruct && (cast(TypeStruct)t1).sym is (cast(TypeStruct)t2).sym) | |
535 goto Lerror; | |
536 } | |
537 else if (t1.ty == TY.Tclass) | |
538 { | |
539 if (t2.ty == TY.Tclass) | |
540 goto Lerror; | |
541 } | |
542 } | |
543 | |
544 if (!typeMerge(sc, this, &type, &e1, &e2)) | |
545 goto Lerror; | |
546 return this; | |
547 | |
548 Lerror: | |
549 incompatibleTypes(); | |
550 type = Type.terror; | |
551 e1 = new ErrorExp(); | |
552 e2 = new ErrorExp(); | |
553 return this; | |
554 } | |
555 | |
556 Expression optimize(int result) | |
557 { | |
558 //printf("BinExp.optimize(result = %d) %s\n", result, toChars()); | |
559 if (op != TOK.TOKconstruct && op != TOK.TOKblit) // don't replace const variable with its initializer | |
560 e1 = e1.optimize(result); | |
561 | |
562 e2 = e2.optimize(result); | |
563 if (op == TOK.TOKshlass || op == TOK.TOKshrass || op == TOK.TOKushrass) | |
564 { | |
565 if (e2.isConst() == 1) | |
566 { | |
567 long i2 = e2.toInteger(); | |
568 ulong sz = e1.type.size() * 8; | |
569 | |
570 if (i2 < 0 || i2 > sz) | |
571 { | |
572 error("shift assign by %jd is outside the range 0..%zu", i2, sz); | |
573 e2 = new IntegerExp(0); | |
574 } | |
575 } | |
576 } | |
577 | |
578 return this; | |
579 } | |
580 | |
581 bool isunsigned() | |
582 { | |
583 assert(false); | |
584 } | |
585 | |
586 void incompatibleTypes() | |
587 { | |
588 error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", | |
589 e1.toChars(), Token.toChars(op), e2.toChars(), | |
590 e1.type.toChars(), e2.type.toChars()); | |
591 } | |
592 | |
593 void dump(int indent) | |
594 { | |
595 assert(false); | |
596 } | |
597 | |
598 void scanForNestedRef(Scope *sc) | |
599 { | |
600 assert(false); | |
601 } | |
602 | |
603 Expression interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)) | |
604 { | |
605 assert(false); | |
606 } | |
607 | |
608 Expression interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)) | |
609 { | |
610 assert(false); | |
611 } | |
612 | |
613 Expression interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0) | |
614 { | |
615 assert(false); | |
616 } | |
617 | |
618 bool canThrow() | |
619 { | |
620 return e1.canThrow() || e2.canThrow(); | |
621 } | |
622 | |
623 Expression arrayOp(Scope sc) | |
624 { | |
625 assert(false); | |
626 } | |
627 | |
628 int inlineCost(InlineCostState* ics) | |
629 { | |
630 return 1 + e1.inlineCost(ics) + e2.inlineCost(ics); | |
631 } | |
632 | |
633 Expression doInline(InlineDoState ids) | |
634 { | |
635 BinExp be = cast(BinExp)copy(); | |
636 | |
637 be.e1 = e1.doInline(ids); | |
638 be.e2 = e2.doInline(ids); | |
639 return be; | |
640 } | |
641 | |
642 Expression inlineScan(InlineScanState* iss) | |
643 { | |
644 e1 = e1.inlineScan(iss); | |
645 e2 = e2.inlineScan(iss); | |
646 return this; | |
647 } | |
648 | |
649 Expression op_overload(Scope sc) | |
650 { | |
651 //printf("BinExp.op_overload() (%s)\n", toChars()); | |
652 | |
653 AggregateDeclaration ad; | |
654 Type t1 = e1.type.toBasetype(); | |
655 Type t2 = e2.type.toBasetype(); | |
656 Identifier id = opId(); | |
657 Identifier id_r = opId_r(); | |
658 | |
659 Match m; | |
660 scope Expressions args1 = new Expressions(); | |
661 scope Expressions args2 = new Expressions(); | |
662 int argsset = 0; | |
663 | |
664 AggregateDeclaration ad1; | |
665 if (t1.ty == TY.Tclass) | |
666 ad1 = (cast(TypeClass)t1).sym; | |
667 else if (t1.ty == TY.Tstruct) | |
668 ad1 = (cast(TypeStruct)t1).sym; | |
669 else | |
670 ad1 = null; | |
671 | |
672 AggregateDeclaration ad2; | |
673 if (t2.ty == TY.Tclass) | |
674 ad2 = (cast(TypeClass)t2).sym; | |
675 else if (t2.ty == TY.Tstruct) | |
676 ad2 = (cast(TypeStruct)t2).sym; | |
677 else | |
678 ad2 = null; | |
679 | |
680 Dsymbol s = null; | |
681 Dsymbol s_r = null; | |
682 FuncDeclaration fd = null; | |
683 TemplateDeclaration td = null; | |
684 if (ad1 && id) | |
685 { | |
686 s = search_function(ad1, id); | |
687 } | |
688 if (ad2 && id_r) | |
689 { | |
690 s_r = search_function(ad2, id_r); | |
691 } | |
692 | |
693 if (s || s_r) | |
694 { | |
695 /* Try: | |
696 * a.opfunc(b) | |
697 * b.opfunc_r(a) | |
698 * and see which is better. | |
699 */ | |
700 Expression e; | |
701 FuncDeclaration lastf; | |
702 | |
703 args1.setDim(1); | |
704 args1.data[0] = cast(void*) e1; | |
705 args2.setDim(1); | |
706 args2.data[0] = cast(void*) e2; | |
707 argsset = 1; | |
708 | |
709 ///memset(&m, 0, sizeof(m)); | |
710 m.last = MATCH.MATCHnomatch; | |
711 | |
712 if (s) | |
713 { | |
714 fd = s.isFuncDeclaration(); | |
715 if (fd) | |
716 { | |
717 overloadResolveX(&m, fd, null, args2); | |
718 } | |
719 else | |
720 { | |
721 td = s.isTemplateDeclaration(); | |
722 templateResolve(&m, td, sc, loc, null, null, args2); | |
723 } | |
724 } | |
725 | |
726 lastf = m.lastf; | |
727 | |
728 if (s_r) | |
729 { | |
730 fd = s_r.isFuncDeclaration(); | |
731 if (fd) | |
732 { | |
733 overloadResolveX(&m, fd, null, args1); | |
734 } | |
735 else | |
736 { | |
737 td = s_r.isTemplateDeclaration(); | |
738 templateResolve(&m, td, sc, loc, null, null, args1); | |
739 } | |
740 } | |
741 | |
742 if (m.count > 1) | |
743 { | |
744 // Error, ambiguous | |
745 error("overloads %s and %s both match argument list for %s", | |
746 m.lastf.type.toChars(), | |
747 m.nextf.type.toChars(), | |
748 m.lastf.toChars()); | |
749 } | |
750 else if (m.last == MATCH.MATCHnomatch) | |
751 { | |
752 m.lastf = m.anyf; | |
753 } | |
754 | |
755 if (op == TOK.TOKplusplus || op == TOK.TOKminusminus) | |
756 // Kludge because operator overloading regards e++ and e-- | |
757 // as unary, but it's implemented as a binary. | |
758 // Rewrite (e1 ++ e2) as e1.postinc() | |
759 // Rewrite (e1 -- e2) as e1.postdec() | |
760 e = build_overload(loc, sc, e1, null, id); | |
761 else if (lastf && m.lastf == lastf || m.last == MATCH.MATCHnomatch) | |
762 // Rewrite (e1 op e2) as e1.opfunc(e2) | |
763 e = build_overload(loc, sc, e1, e2, id); | |
764 else | |
765 // Rewrite (e1 op e2) as e2.opfunc_r(e1) | |
766 e = build_overload(loc, sc, e2, e1, id_r); | |
767 return e; | |
768 } | |
769 | |
770 if (isCommutative()) | |
771 { | |
772 s = null; | |
773 s_r = null; | |
774 if (ad1 && id_r) | |
775 { | |
776 s_r = search_function(ad1, id_r); | |
777 } | |
778 if (ad2 && id) | |
779 { | |
780 s = search_function(ad2, id); | |
781 } | |
782 | |
783 if (s || s_r) | |
784 { | |
785 /* Try: | |
786 * a.opfunc_r(b) | |
787 * b.opfunc(a) | |
788 * and see which is better. | |
789 */ | |
790 | |
791 if (!argsset) | |
792 { | |
793 args1.setDim(1); | |
794 args1.data[0] = cast(void*) e1; | |
795 args2.setDim(1); | |
796 args2.data[0] = cast(void*) e2; | |
797 } | |
798 | |
799 ///memset(&m, 0, sizeof(m)); | |
800 m.last = MATCH.MATCHnomatch; | |
801 | |
802 if (s_r) | |
803 { | |
804 fd = s_r.isFuncDeclaration(); | |
805 if (fd) | |
806 { | |
807 overloadResolveX(&m, fd, null, args2); | |
808 } | |
809 else | |
810 { td = s_r.isTemplateDeclaration(); | |
811 templateResolve(&m, td, sc, loc, null, null, args2); | |
812 } | |
813 } | |
814 FuncDeclaration lastf = m.lastf; | |
815 | |
816 if (s) | |
817 { | |
818 fd = s.isFuncDeclaration(); | |
819 if (fd) | |
820 { | |
821 overloadResolveX(&m, fd, null, args1); | |
822 } | |
823 else | |
824 { td = s.isTemplateDeclaration(); | |
825 templateResolve(&m, td, sc, loc, null, null, args1); | |
826 } | |
827 } | |
828 | |
829 if (m.count > 1) | |
830 { | |
831 // Error, ambiguous | |
832 error("overloads %s and %s both match argument list for %s", | |
833 m.lastf.type.toChars(), | |
834 m.nextf.type.toChars(), | |
835 m.lastf.toChars()); | |
836 } | |
837 else if (m.last == MATCH.MATCHnomatch) | |
838 { | |
839 m.lastf = m.anyf; | |
840 } | |
841 | |
842 Expression e; | |
843 if (lastf && m.lastf == lastf || id_r && m.last == MATCH.MATCHnomatch) | |
844 // Rewrite (e1 op e2) as e1.opfunc_r(e2) | |
845 e = build_overload(loc, sc, e1, e2, id_r); | |
846 else | |
847 // Rewrite (e1 op e2) as e2.opfunc(e1) | |
848 e = build_overload(loc, sc, e2, e1, id); | |
849 | |
850 // When reversing operands of comparison operators, | |
851 // need to reverse the sense of the op | |
852 switch (op) | |
853 { | |
854 case TOK.TOKlt: op = TOK.TOKgt; break; | |
855 case TOK.TOKgt: op = TOK.TOKlt; break; | |
856 case TOK.TOKle: op = TOK.TOKge; break; | |
857 case TOK.TOKge: op = TOK.TOKle; break; | |
858 | |
859 // Floating point compares | |
860 case TOK.TOKule: op = TOK.TOKuge; break; | |
861 case TOK.TOKul: op = TOK.TOKug; break; | |
862 case TOK.TOKuge: op = TOK.TOKule; break; | |
863 case TOK.TOKug: op = TOK.TOKul; break; | |
864 | |
865 // These are symmetric | |
866 case TOK.TOKunord: | |
867 case TOK.TOKlg: | |
868 case TOK.TOKleg: | |
869 case TOK.TOKue: | |
870 break; | |
871 } | |
872 | |
873 return e; | |
874 } | |
875 } | |
876 | |
877 version (DMDV2) { | |
878 // Try alias this on first operand | |
879 if (ad1 && ad1.aliasthis) | |
880 { | |
881 /* Rewrite (e1 op e2) as: | |
882 * (e1.aliasthis op e2) | |
883 */ | |
884 Expression e1 = new DotIdExp(loc, this.e1, ad1.aliasthis.ident); | |
885 Expression e = copy(); | |
886 (cast(BinExp)e).e1 = e1; | |
887 e = e.semantic(sc); | |
888 return e; | |
889 } | |
890 | |
891 // Try alias this on second operand | |
892 if (ad2 && ad2.aliasthis) | |
893 { | |
894 /* Rewrite (e1 op e2) as: | |
895 * (e1 op e2.aliasthis) | |
896 */ | |
897 Expression e2 = new DotIdExp(loc, this.e2, ad2.aliasthis.ident); | |
898 Expression e = copy(); | |
899 (cast(BinExp)e).e2 = e2; | |
900 e = e.semantic(sc); | |
901 return e; | |
902 } | |
903 } | |
904 return null; | |
905 } | |
906 | |
907 elem* toElemBin(IRState* irs, int op) | |
908 { | |
909 //printf("toElemBin() '%s'\n", toChars()); | |
910 | |
911 tym_t tym = type.totym(); | |
912 | |
913 elem* el = e1.toElem(irs); | |
914 elem* er = e2.toElem(irs); | |
915 elem* e = el_bin(op,tym,el,er); | |
916 el_setLoc(e,loc); | |
917 | |
918 return e; | |
919 } | |
920 } |