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 }