1 
2 /* Compiler implementation of the D programming language
3  * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4  * written by Walter Bright
5  * http://www.digitalmars.com
6  * Distributed under the Boost Software License, Version 1.0.
7  * http://www.boost.org/LICENSE_1_0.txt
8  * https://github.com/D-Programming-Language/dmd/blob/master/src/opover.c
9  */
10 
11 #include "root/dsystem.h"               // memset()
12 #include "root/rmem.h"
13 
14 #include "mars.h"
15 #include "mtype.h"
16 #include "init.h"
17 #include "expression.h"
18 #include "statement.h"
19 #include "scope.h"
20 #include "id.h"
21 #include "declaration.h"
22 #include "aggregate.h"
23 #include "template.h"
24 #include "tokens.h"
25 
26 static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters);
27 static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags = 0);
28 Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id);
29 bool MODimplicitConv(MOD modfrom, MOD modto);
30 Expression *trySemantic(Expression *e, Scope *sc);
31 Expression *binSemanticProp(BinExp *e, Scope *sc);
32 Expression *semantic(Expression *e, Scope *sc);
33 
34 /******************************** Expression **************************/
35 
36 
37 /***********************************
38  * Determine if operands of binary op can be reversed
39  * to fit operator overload.
40  */
41 
isCommutative(TOK op)42 bool isCommutative(TOK op)
43 {
44     switch (op)
45     {
46         case TOKadd:
47         case TOKmul:
48         case TOKand:
49         case TOKor:
50         case TOKxor:
51 
52         // EqualExp
53         case TOKequal:
54         case TOKnotequal:
55 
56         // CmpExp
57         case TOKlt:
58         case TOKle:
59         case TOKgt:
60         case TOKge:
61             return true;
62 
63         default:
64             break;
65     }
66     return false;
67 }
68 
69 /***********************************
70  * Get Identifier for operator overload.
71  */
72 
opId(Expression * e)73 static Identifier *opId(Expression *e)
74 {
75     class OpIdVisitor : public Visitor
76     {
77     public:
78         Identifier *id;
79         void visit(Expression *)    { assert(0); }
80         void visit(UAddExp *)       { id = Id::uadd; }
81         void visit(NegExp *)        { id = Id::neg; }
82         void visit(ComExp *)        { id = Id::com; }
83         void visit(CastExp *)       { id = Id::_cast; }
84         void visit(InExp *)         { id = Id::opIn; }
85         void visit(PostExp *e)      { id = (e->op == TOKplusplus) ? Id::postinc : Id::postdec; }
86         void visit(AddExp *)        { id = Id::add; }
87         void visit(MinExp *)        { id = Id::sub; }
88         void visit(MulExp *)        { id = Id::mul; }
89         void visit(DivExp *)        { id = Id::div; }
90         void visit(ModExp *)        { id = Id::mod; }
91         void visit(PowExp *)        { id = Id::pow; }
92         void visit(ShlExp *)        { id = Id::shl; }
93         void visit(ShrExp *)        { id = Id::shr; }
94         void visit(UshrExp *)       { id = Id::ushr; }
95         void visit(AndExp *)        { id = Id::iand; }
96         void visit(OrExp *)         { id = Id::ior; }
97         void visit(XorExp *)        { id = Id::ixor; }
98         void visit(CatExp *)        { id = Id::cat; }
99         void visit(AssignExp *)     { id = Id::assign; }
100         void visit(AddAssignExp *)  { id = Id::addass; }
101         void visit(MinAssignExp *)  { id = Id::subass; }
102         void visit(MulAssignExp *)  { id = Id::mulass; }
103         void visit(DivAssignExp *)  { id = Id::divass; }
104         void visit(ModAssignExp *)  { id = Id::modass; }
105         void visit(AndAssignExp *)  { id = Id::andass; }
106         void visit(OrAssignExp *)   { id = Id::orass; }
107         void visit(XorAssignExp *)  { id = Id::xorass; }
108         void visit(ShlAssignExp *)  { id = Id::shlass; }
109         void visit(ShrAssignExp *)  { id = Id::shrass; }
110         void visit(UshrAssignExp *) { id = Id::ushrass; }
111         void visit(CatAssignExp *)  { id = Id::catass; }
112         void visit(PowAssignExp *)  { id = Id::powass; }
113         void visit(EqualExp *)      { id = Id::eq; }
114         void visit(CmpExp *)        { id = Id::cmp; }
115         void visit(ArrayExp *)      { id = Id::index; }
116         void visit(PtrExp *)        { id = Id::opStar; }
117     };
118     OpIdVisitor v;
119     e->accept(&v);
120     return v.id;
121 }
122 
123 /***********************************
124  * Get Identifier for reverse operator overload,
125  * NULL if not supported for this operator.
126  */
127 
opId_r(Expression * e)128 static Identifier *opId_r(Expression *e)
129 {
130     class OpIdRVisitor : public Visitor
131     {
132     public:
133         Identifier *id;
134         void visit(Expression *) { id = NULL; }
135         void visit(InExp *)      { id = Id::opIn_r; }
136         void visit(AddExp *)     { id = Id::add_r; }
137         void visit(MinExp *)     { id = Id::sub_r; }
138         void visit(MulExp *)     { id = Id::mul_r; }
139         void visit(DivExp *)     { id = Id::div_r; }
140         void visit(ModExp *)     { id = Id::mod_r; }
141         void visit(PowExp *)     { id = Id::pow_r; }
142         void visit(ShlExp *)     { id = Id::shl_r; }
143         void visit(ShrExp *)     { id = Id::shr_r; }
144         void visit(UshrExp *)    { id = Id::ushr_r; }
145         void visit(AndExp *)     { id = Id::iand_r; }
146         void visit(OrExp *)      { id = Id::ior_r; }
147         void visit(XorExp *)     { id = Id::ixor_r; }
148         void visit(CatExp *)     { id = Id::cat_r; }
149     };
150     OpIdRVisitor v;
151     e->accept(&v);
152     return v.id;
153 }
154 
155 /************************************
156  * If type is a class or struct, return the symbol for it,
157  * else NULL
158  */
isAggregate(Type * t)159 AggregateDeclaration *isAggregate(Type *t)
160 {
161     t = t->toBasetype();
162     if (t->ty == Tclass)
163     {
164         return ((TypeClass *)t)->sym;
165     }
166     else if (t->ty == Tstruct)
167     {
168         return ((TypeStruct *)t)->sym;
169     }
170     return NULL;
171 }
172 
173 /*******************************************
174  * Helper function to turn operator into template argument list
175  */
opToArg(Scope * sc,TOK op)176 Objects *opToArg(Scope *sc, TOK op)
177 {
178     /* Remove the = from op=
179      */
180     switch (op)
181     {
182         case TOKaddass: op = TOKadd; break;
183         case TOKminass: op = TOKmin; break;
184         case TOKmulass: op = TOKmul; break;
185         case TOKdivass: op = TOKdiv; break;
186         case TOKmodass: op = TOKmod; break;
187         case TOKandass: op = TOKand; break;
188         case TOKorass:  op = TOKor;  break;
189         case TOKxorass: op = TOKxor; break;
190         case TOKshlass: op = TOKshl; break;
191         case TOKshrass: op = TOKshr; break;
192         case TOKushrass: op = TOKushr; break;
193         case TOKcatass: op = TOKcat; break;
194         case TOKpowass: op = TOKpow; break;
195         default:                     break;
196     }
197     Expression *e = new StringExp(Loc(), const_cast<char *>(Token::toChars(op)));
198     e = semantic(e, sc);
199     Objects *tiargs = new Objects();
200     tiargs->push(e);
201     return tiargs;
202 }
203 
204 /************************************
205  * Operator overload.
206  * Check for operator overload, if so, replace
207  * with function call.
208  * Return NULL if not an operator overload.
209  */
210 
op_overload(Expression * e,Scope * sc)211 Expression *op_overload(Expression *e, Scope *sc)
212 {
213     class OpOverload : public Visitor
214     {
215     public:
216         Scope *sc;
217         Expression *result;
218 
219         OpOverload(Scope *sc)
220             : sc(sc)
221         {
222             result = NULL;
223         }
224 
225         void visit(Expression *)
226         {
227             assert(0);
228         }
229 
230         void visit(UnaExp *e)
231         {
232             //printf("UnaExp::op_overload() (%s)\n", e->toChars());
233 
234             if (e->e1->op == TOKarray)
235             {
236                 ArrayExp *ae = (ArrayExp *)e->e1;
237                 ae->e1 = semantic(ae->e1, sc);
238                 ae->e1 = resolveProperties(sc, ae->e1);
239                 Expression *ae1old = ae->e1;
240 
241                 const bool maybeSlice =
242                     (ae->arguments->dim == 0 ||
243                      (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval));
244                 IntervalExp *ie = NULL;
245                 if (maybeSlice && ae->arguments->dim)
246                 {
247                     assert((*ae->arguments)[0]->op == TOKinterval);
248                     ie = (IntervalExp *)(*ae->arguments)[0];
249                 }
250 
251                 while (true)
252                 {
253                     if (ae->e1->op == TOKerror)
254                     {
255                         result = ae->e1;
256                         return;
257                     }
258                     Expression *e0 = NULL;
259                     Expression *ae1save = ae->e1;
260                     ae->lengthVar = NULL;
261 
262                     Type *t1b = ae->e1->type->toBasetype();
263                     AggregateDeclaration *ad = isAggregate(t1b);
264                     if (!ad)
265                         break;
266                     if (search_function(ad, Id::opIndexUnary))
267                     {
268                         // Deal with $
269                         result = resolveOpDollar(sc, ae, &e0);
270                         if (!result)    // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
271                             goto Lfallback;
272                         if (result->op == TOKerror)
273                             return;
274 
275                         /* Rewrite op(a[arguments]) as:
276                          *      a.opIndexUnary!(op)(arguments)
277                          */
278                         Expressions *a = (Expressions *)ae->arguments->copy();
279                         Objects *tiargs = opToArg(sc, e->op);
280                         result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexUnary, tiargs);
281                         result = new CallExp(e->loc, result, a);
282                         if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
283                             result = trySemantic(result, sc);
284                         else
285                             result = semantic(result, sc);
286                         if (result)
287                         {
288                             result = Expression::combine(e0, result);
289                             return;
290                         }
291                     }
292                 Lfallback:
293                     if (maybeSlice && search_function(ad, Id::opSliceUnary))
294                     {
295                         // Deal with $
296                         result = resolveOpDollar(sc, ae, ie, &e0);
297                         if (result->op == TOKerror)
298                             return;
299 
300                         /* Rewrite op(a[i..j]) as:
301                          *      a.opSliceUnary!(op)(i, j)
302                          */
303                         Expressions *a = new Expressions();
304                         if (ie)
305                         {
306                             a->push(ie->lwr);
307                             a->push(ie->upr);
308                         }
309                         Objects *tiargs = opToArg(sc, e->op);
310                         result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceUnary, tiargs);
311                         result = new CallExp(e->loc, result, a);
312                         result = semantic(result, sc);
313                         result = Expression::combine(e0, result);
314                         return;
315                     }
316 
317                     // Didn't find it. Forward to aliasthis
318                     if (ad->aliasthis && t1b != ae->att1)
319                     {
320                         if (!ae->att1 && t1b->checkAliasThisRec())
321                             ae->att1 = t1b;
322 
323                         /* Rewrite op(a[arguments]) as:
324                          *      op(a.aliasthis[arguments])
325                          */
326                         ae->e1 = resolveAliasThis(sc, ae1save, true);
327                         if (ae->e1)
328                             continue;
329                     }
330                     break;
331                 }
332                 ae->e1 = ae1old;    // recovery
333                 ae->lengthVar = NULL;
334             }
335 
336             e->e1 = semantic(e->e1, sc);
337             e->e1 = resolveProperties(sc, e->e1);
338             if (e->e1->op == TOKerror)
339             {
340                 result = e->e1;
341                 return;
342             }
343 
344             AggregateDeclaration *ad = isAggregate(e->e1->type);
345             if (ad)
346             {
347                 Dsymbol *fd = NULL;
348         #if 1 // Old way, kept for compatibility with D1
349                 if (e->op != TOKpreplusplus && e->op != TOKpreminusminus)
350                 {
351                     fd = search_function(ad, opId(e));
352                     if (fd)
353                     {
354                         // Rewrite +e1 as e1.add()
355                         result = build_overload(e->loc, sc, e->e1, NULL, fd);
356                         return;
357                     }
358                 }
359         #endif
360 
361                 /* Rewrite as:
362                  *      e1.opUnary!(op)()
363                  */
364                 fd = search_function(ad, Id::opUnary);
365                 if (fd)
366                 {
367                     Objects *tiargs = opToArg(sc, e->op);
368                     result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
369                     result = new CallExp(e->loc, result);
370                     result = semantic(result, sc);
371                     return;
372                 }
373 
374                 // Didn't find it. Forward to aliasthis
375                 if (ad->aliasthis && e->e1->type != e->att1)
376                 {
377                     /* Rewrite op(e1) as:
378                      *      op(e1.aliasthis)
379                      */
380                     //printf("att una %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars());
381                     Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
382                     UnaExp *ue = (UnaExp *)e->copy();
383                     if (!ue->att1 && e->e1->type->checkAliasThisRec())
384                         ue->att1 = e->e1->type;
385                     ue->e1 = e1;
386                     result = trySemantic(ue, sc);
387                     return;
388                 }
389             }
390         }
391 
392         void visit(ArrayExp *ae)
393         {
394             //printf("ArrayExp::op_overload() (%s)\n", ae->toChars());
395             ae->e1 = semantic(ae->e1, sc);
396             ae->e1 = resolveProperties(sc, ae->e1);
397             Expression *ae1old = ae->e1;
398 
399             const bool maybeSlice =
400                 (ae->arguments->dim == 0 ||
401                  (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval));
402             IntervalExp *ie = NULL;
403             if (maybeSlice && ae->arguments->dim)
404             {
405                 assert((*ae->arguments)[0]->op == TOKinterval);
406                 ie = (IntervalExp *)(*ae->arguments)[0];
407             }
408 
409             while (true)
410             {
411                 if (ae->e1->op == TOKerror)
412                 {
413                     result = ae->e1;
414                     return;
415                 }
416                 Expression *e0 = NULL;
417                 Expression *ae1save = ae->e1;
418                 ae->lengthVar = NULL;
419 
420                 Type *t1b = ae->e1->type->toBasetype();
421                 AggregateDeclaration *ad = isAggregate(t1b);
422                 if (!ad)
423                 {
424                     // If the non-aggregate expression ae->e1 is indexable or sliceable,
425                     // convert it to the corresponding concrete expression.
426                     if (t1b->ty == Tpointer ||
427                         t1b->ty == Tsarray ||
428                         t1b->ty == Tarray ||
429                         t1b->ty == Taarray ||
430                         t1b->ty == Ttuple ||
431                         t1b->ty == Tvector ||
432                         ae->e1->op == TOKtype)
433                     {
434                         // Convert to SliceExp
435                         if (maybeSlice)
436                         {
437                             result = new SliceExp(ae->loc, ae->e1, ie);
438                             result = semantic(result, sc);
439                             return;
440                         }
441                         // Convert to IndexExp
442                         if (ae->arguments->dim == 1)
443                         {
444                             result = new IndexExp(ae->loc, ae->e1, (*ae->arguments)[0]);
445                             result = semantic(result, sc);
446                             return;
447                         }
448                     }
449                     break;
450                 }
451                 if (search_function(ad, Id::index))
452                 {
453                     // Deal with $
454                     result = resolveOpDollar(sc, ae, &e0);
455                     if (!result)    // a[i..j] might be: a.opSlice(i, j)
456                         goto Lfallback;
457                     if (result->op == TOKerror)
458                         return;
459 
460                     /* Rewrite e1[arguments] as:
461                      *      e1.opIndex(arguments)
462                      */
463                     Expressions *a = (Expressions *)ae->arguments->copy();
464                     result = new DotIdExp(ae->loc, ae->e1, Id::index);
465                     result = new CallExp(ae->loc, result, a);
466                     if (maybeSlice) // a[] might be: a.opSlice()
467                         result = trySemantic(result, sc);
468                     else
469                         result = semantic(result, sc);
470                     if (result)
471                     {
472                         result = Expression::combine(e0, result);
473                         return;
474                     }
475                 }
476             Lfallback:
477                 if (maybeSlice && ae->e1->op == TOKtype)
478                 {
479                     result = new SliceExp(ae->loc, ae->e1, ie);
480                     result = semantic(result, sc);
481                     result = Expression::combine(e0, result);
482                     return;
483                 }
484                 if (maybeSlice && search_function(ad, Id::slice))
485                 {
486                     // Deal with $
487                     result = resolveOpDollar(sc, ae, ie, &e0);
488                     if (result->op == TOKerror)
489                         return;
490 
491                     /* Rewrite a[i..j] as:
492                      *      a.opSlice(i, j)
493                      */
494                     Expressions *a = new Expressions();
495                     if (ie)
496                     {
497                         a->push(ie->lwr);
498                         a->push(ie->upr);
499                     }
500                     result = new DotIdExp(ae->loc, ae->e1, Id::slice);
501                     result = new CallExp(ae->loc, result, a);
502                     result = semantic(result, sc);
503                     result = Expression::combine(e0, result);
504                     return;
505                 }
506 
507                 // Didn't find it. Forward to aliasthis
508                 if (ad->aliasthis && t1b != ae->att1)
509                 {
510                     if (!ae->att1 && t1b->checkAliasThisRec())
511                         ae->att1 = t1b;
512                     //printf("att arr e1 = %s\n", this->e1->type->toChars());
513 
514                     /* Rewrite op(a[arguments]) as:
515                      *      op(a.aliasthis[arguments])
516                      */
517                     ae->e1 = resolveAliasThis(sc, ae1save, true);
518                     if (ae->e1)
519                         continue;
520                 }
521                 break;
522             }
523             ae->e1 = ae1old;    // recovery
524             ae->lengthVar = NULL;
525         }
526 
527         /***********************************************
528          * This is mostly the same as UnaryExp::op_overload(), but has
529          * a different rewrite.
530          */
531         void visit(CastExp *e)
532         {
533             //printf("CastExp::op_overload() (%s)\n", e->toChars());
534             AggregateDeclaration *ad = isAggregate(e->e1->type);
535             if (ad)
536             {
537                 Dsymbol *fd = NULL;
538                 /* Rewrite as:
539                  *      e1.opCast!(T)()
540                  */
541                 fd = search_function(ad, Id::_cast);
542                 if (fd)
543                 {
544         #if 1 // Backwards compatibility with D1 if opCast is a function, not a template
545                     if (fd->isFuncDeclaration())
546                     {
547                         // Rewrite as:  e1.opCast()
548                         result = build_overload(e->loc, sc, e->e1, NULL, fd);
549                         return;
550                     }
551         #endif
552                     Objects *tiargs = new Objects();
553                     tiargs->push(e->to);
554                     result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
555                     result = new CallExp(e->loc, result);
556                     result = semantic(result, sc);
557                     return;
558                 }
559 
560                 // Didn't find it. Forward to aliasthis
561                 if (ad->aliasthis)
562                 {
563                     /* Rewrite op(e1) as:
564                      *      op(e1.aliasthis)
565                      */
566                     Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
567                     result = e->copy();
568                     ((UnaExp *)result)->e1 = e1;
569                     result = trySemantic(result, sc);
570                     return;
571                 }
572             }
573         }
574 
575         void visit(BinExp *e)
576         {
577             //printf("BinExp::op_overload() (%s)\n", e->toChars());
578 
579             Identifier *id = opId(e);
580             Identifier *id_r = opId_r(e);
581 
582             Expressions args1;
583             Expressions args2;
584             int argsset = 0;
585 
586             AggregateDeclaration *ad1 = isAggregate(e->e1->type);
587             AggregateDeclaration *ad2 = isAggregate(e->e2->type);
588 
589             if (e->op == TOKassign && ad1 == ad2)
590             {
591                 StructDeclaration *sd = ad1->isStructDeclaration();
592                 if (sd && !sd->hasIdentityAssign)
593                 {
594                     /* This is bitwise struct assignment. */
595                     return;
596                 }
597             }
598 
599             Dsymbol *s = NULL;
600             Dsymbol *s_r = NULL;
601 
602         #if 1 // the old D1 scheme
603             if (ad1 && id)
604             {
605                 s = search_function(ad1, id);
606             }
607             if (ad2 && id_r)
608             {
609                 s_r = search_function(ad2, id_r);
610 
611                 // Bugzilla 12778: If both x.opBinary(y) and y.opBinaryRight(x) found,
612                 // and they are exactly same symbol, x.opBinary(y) should be preferred.
613                 if (s_r && s_r == s)
614                     s_r = NULL;
615             }
616         #endif
617 
618             Objects *tiargs = NULL;
619             if (e->op == TOKplusplus || e->op == TOKminusminus)
620             {
621                 // Bug4099 fix
622                 if (ad1 && search_function(ad1, Id::opUnary))
623                     return;
624             }
625             if (!s && !s_r && e->op != TOKequal && e->op != TOKnotequal && e->op != TOKassign &&
626                 e->op != TOKplusplus && e->op != TOKminusminus)
627             {
628                 /* Try the new D2 scheme, opBinary and opBinaryRight
629                  */
630                 if (ad1)
631                 {
632                     s = search_function(ad1, Id::opBinary);
633                     if (s && !s->isTemplateDeclaration())
634                     {
635                         e->e1->error("%s.opBinary isn't a template", e->e1->toChars());
636                         result = new ErrorExp();
637                         return;
638                     }
639                 }
640                 if (ad2)
641                 {
642                     s_r = search_function(ad2, Id::opBinaryRight);
643                     if (s_r && !s_r->isTemplateDeclaration())
644                     {
645                         e->e2->error("%s.opBinaryRight isn't a template", e->e2->toChars());
646                         result = new ErrorExp();
647                         return;
648                     }
649                     if (s_r && s_r == s)    // Bugzilla 12778
650                         s_r = NULL;
651                 }
652 
653                 // Set tiargs, the template argument list, which will be the operator string
654                 if (s || s_r)
655                 {
656                     id = Id::opBinary;
657                     id_r = Id::opBinaryRight;
658                     tiargs = opToArg(sc, e->op);
659                 }
660             }
661 
662             if (s || s_r)
663             {
664                 /* Try:
665                  *      a.opfunc(b)
666                  *      b.opfunc_r(a)
667                  * and see which is better.
668                  */
669 
670                 args1.setDim(1);
671                 args1[0] = e->e1;
672                 expandTuples(&args1);
673                 args2.setDim(1);
674                 args2[0] = e->e2;
675                 expandTuples(&args2);
676                 argsset = 1;
677 
678                 Match m;
679                 memset(&m, 0, sizeof(m));
680                 m.last = MATCHnomatch;
681 
682                 if (s)
683                 {
684                     functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
685                     if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
686                     {
687                         result = new ErrorExp();
688                         return;
689                     }
690                 }
691 
692                 FuncDeclaration *lastf = m.lastf;
693 
694                 if (s_r)
695                 {
696                     functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
697                     if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
698                     {
699                         result = new ErrorExp();
700                         return;
701                     }
702                 }
703 
704                 if (m.count > 1)
705                 {
706                     // Error, ambiguous
707                     e->error("overloads %s and %s both match argument list for %s",
708                             m.lastf->type->toChars(),
709                             m.nextf->type->toChars(),
710                             m.lastf->toChars());
711                 }
712                 else if (m.last <= MATCHnomatch)
713                 {
714                     m.lastf = m.anyf;
715                     if (tiargs)
716                         goto L1;
717                 }
718 
719                 if (e->op == TOKplusplus || e->op == TOKminusminus)
720                 {
721                     // Kludge because operator overloading regards e++ and e--
722                     // as unary, but it's implemented as a binary.
723                     // Rewrite (e1 ++ e2) as e1.postinc()
724                     // Rewrite (e1 -- e2) as e1.postdec()
725                     result = build_overload(e->loc, sc, e->e1, NULL, m.lastf ? m.lastf : s);
726                 }
727                 else if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch))
728                 {
729                     // Rewrite (e1 op e2) as e1.opfunc(e2)
730                     result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
731                 }
732                 else
733                 {
734                     // Rewrite (e1 op e2) as e2.opfunc_r(e1)
735                     result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
736                 }
737                 return;
738             }
739 
740         L1:
741         #if 1 // Retained for D1 compatibility
742             if (isCommutative(e->op) && !tiargs)
743             {
744                 s = NULL;
745                 s_r = NULL;
746                 if (ad1 && id_r)
747                 {
748                     s_r = search_function(ad1, id_r);
749                 }
750                 if (ad2 && id)
751                 {
752                     s = search_function(ad2, id);
753                     if (s && s == s_r)  // Bugzilla 12778
754                         s = NULL;
755                 }
756 
757                 if (s || s_r)
758                 {
759                     /* Try:
760                      *  a.opfunc_r(b)
761                      *  b.opfunc(a)
762                      * and see which is better.
763                      */
764 
765                     if (!argsset)
766                     {
767                         args1.setDim(1);
768                         args1[0] = e->e1;
769                         expandTuples(&args1);
770                         args2.setDim(1);
771                         args2[0] = e->e2;
772                         expandTuples(&args2);
773                     }
774 
775                     Match m;
776                     memset(&m, 0, sizeof(m));
777                     m.last = MATCHnomatch;
778 
779                     if (s_r)
780                     {
781                         functionResolve(&m, s_r, e->loc, sc, tiargs, e->e1->type, &args2);
782                         if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
783                         {
784                             result = new ErrorExp();
785                             return;
786                         }
787                     }
788 
789                     FuncDeclaration *lastf = m.lastf;
790 
791                     if (s)
792                     {
793                         functionResolve(&m, s, e->loc, sc, tiargs, e->e2->type, &args1);
794                         if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
795                         {
796                             result = new ErrorExp();
797                             return;
798                         }
799                     }
800 
801                     if (m.count > 1)
802                     {
803                         // Error, ambiguous
804                         e->error("overloads %s and %s both match argument list for %s",
805                                 m.lastf->type->toChars(),
806                                 m.nextf->type->toChars(),
807                                 m.lastf->toChars());
808                     }
809                     else if (m.last <= MATCHnomatch)
810                     {
811                         m.lastf = m.anyf;
812                     }
813 
814                     if ((lastf && m.lastf == lastf) || (!s && m.last <= MATCHnomatch))
815                     {
816                         // Rewrite (e1 op e2) as e1.opfunc_r(e2)
817                         result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s_r);
818                     }
819                     else
820                     {
821                         // Rewrite (e1 op e2) as e2.opfunc(e1)
822                         result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s);
823                     }
824 
825                     // When reversing operands of comparison operators,
826                     // need to reverse the sense of the op
827                     switch (e->op)
828                     {
829                         case TOKlt:     e->op = TOKgt;     break;
830                         case TOKgt:     e->op = TOKlt;     break;
831                         case TOKle:     e->op = TOKge;     break;
832                         case TOKge:     e->op = TOKle;     break;
833                         default:                           break;
834                     }
835 
836                     return;
837                 }
838             }
839         #endif
840 
841             // Try alias this on first operand
842             if (ad1 && ad1->aliasthis &&
843                 !(e->op == TOKassign && ad2 && ad1 == ad2))   // See Bugzilla 2943
844             {
845                 /* Rewrite (e1 op e2) as:
846                  *      (e1.aliasthis op e2)
847                  */
848                 if (e->att1 && e->e1->type == e->att1)
849                     return;
850                 //printf("att bin e1 = %s\n", this->e1->type->toChars());
851                 Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
852                 BinExp *be = (BinExp *)e->copy();
853                 if (!be->att1 && e->e1->type->checkAliasThisRec())
854                     be->att1 = e->e1->type;
855                 be->e1 = e1;
856                 result = trySemantic(be, sc);
857                 return;
858             }
859 
860             // Try alias this on second operand
861             /* Bugzilla 2943: make sure that when we're copying the struct, we don't
862              * just copy the alias this member
863              */
864             if (ad2 && ad2->aliasthis &&
865                 !(e->op == TOKassign && ad1 && ad1 == ad2))
866             {
867                 /* Rewrite (e1 op e2) as:
868                  *      (e1 op e2.aliasthis)
869                  */
870                 if (e->att2 && e->e2->type == e->att2)
871                     return;
872                 //printf("att bin e2 = %s\n", e->e2->type->toChars());
873                 Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
874                 BinExp *be = (BinExp *)e->copy();
875                 if (!be->att2 && e->e2->type->checkAliasThisRec())
876                     be->att2 = e->e2->type;
877                 be->e2 = e2;
878                 result = trySemantic(be, sc);
879                 return;
880             }
881             return;
882         }
883 
884         static bool needsDirectEq(Type *t1, Type *t2, Scope *sc)
885         {
886             Type *t1n = t1->nextOf()->toBasetype();
887             Type *t2n = t2->nextOf()->toBasetype();
888             if (((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) &&
889                  (t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) ||
890                 (t1n->ty == Tvoid || t2n->ty == Tvoid))
891             {
892                 return false;
893             }
894             if (t1n->constOf() != t2n->constOf())
895                 return true;
896 
897             Type *t = t1n;
898             while (t->toBasetype()->nextOf())
899                 t = t->nextOf()->toBasetype();
900             if (t->ty != Tstruct)
901                 return false;
902 
903             if (global.params.useTypeInfo && Type::dtypeinfo)
904                 semanticTypeInfo(sc, t);
905 
906             return ((TypeStruct *)t)->sym->hasIdentityEquals;
907         }
908 
909         void visit(EqualExp *e)
910         {
911             //printf("EqualExp::op_overload() (%s)\n", e->toChars());
912 
913             Type *t1 = e->e1->type->toBasetype();
914             Type *t2 = e->e2->type->toBasetype();
915 
916             /* Check for array equality.
917              */
918             if ((t1->ty == Tarray || t1->ty == Tsarray) &&
919                 (t2->ty == Tarray || t2->ty == Tsarray))
920             {
921                 if (needsDirectEq(t1, t2, sc))
922                 {
923                     /* Rewrite as:
924                      *      __ArrayEq(e1, e2)
925                      */
926                     Expression *eeq = new IdentifierExp(e->loc, Id::__ArrayEq);
927                     result = new CallExp(e->loc, eeq, e->e1, e->e2);
928                     if (e->op == TOKnotequal)
929                         result = new NotExp(e->loc, result);
930                     result = trySemantic(result, sc); // for better error message
931                     if (!result)
932                     {
933                         e->error("cannot compare %s and %s", t1->toChars(), t2->toChars());
934                         result = new ErrorExp();
935                     }
936                     return;
937                 }
938             }
939 
940             /* Check for class equality with null literal or typeof(null).
941              */
942             if ((t1->ty == Tclass && e->e2->op == TOKnull) ||
943                 (t2->ty == Tclass && e->e1->op == TOKnull))
944             {
945                 e->error("use '%s' instead of '%s' when comparing with null",
946                     Token::toChars(e->op == TOKequal ? TOKidentity : TOKnotidentity),
947                     Token::toChars(e->op));
948                 result = new ErrorExp();
949                 return;
950             }
951             if ((t1->ty == Tclass && t2->ty == Tnull) ||
952                 (t1->ty == Tnull && t2->ty == Tclass))
953             {
954                 // Comparing a class with typeof(null) should not call opEquals
955                 return;
956             }
957 
958             /* Check for class equality.
959              */
960             if (t1->ty == Tclass && t2->ty == Tclass)
961             {
962                 ClassDeclaration *cd1 = t1->isClassHandle();
963                 ClassDeclaration *cd2 = t2->isClassHandle();
964 
965                 if (!(cd1->cpp || cd2->cpp))
966                 {
967                     /* Rewrite as:
968                      *      .object.opEquals(e1, e2)
969                      */
970                     Expression *e1x = e->e1;
971                     Expression *e2x = e->e2;
972 
973                     /* The explicit cast is necessary for interfaces,
974                      * see Bugzilla 4088.
975                      */
976                     Type *to = ClassDeclaration::object->getType();
977                     if (cd1->isInterfaceDeclaration())
978                         e1x = new CastExp(e->loc, e->e1, t1->isMutable() ? to : to->constOf());
979                     if (cd2->isInterfaceDeclaration())
980                         e2x = new CastExp(e->loc, e->e2, t2->isMutable() ? to : to->constOf());
981 
982                     result = new IdentifierExp(e->loc, Id::empty);
983                     result = new DotIdExp(e->loc, result, Id::object);
984                     result = new DotIdExp(e->loc, result, Id::eq);
985                     result = new CallExp(e->loc, result, e1x, e2x);
986                     if (e->op == TOKnotequal)
987                         result = new NotExp(e->loc, result);
988                     result = semantic(result, sc);
989                     return;
990                 }
991             }
992 
993             result = compare_overload(e, sc, Id::eq);
994             if (result)
995             {
996                 if (result->op == TOKcall && e->op == TOKnotequal)
997                 {
998                     result = new NotExp(result->loc, result);
999                     result = semantic(result, sc);
1000                 }
1001                 return;
1002             }
1003 
1004             /* Check for pointer equality.
1005              */
1006             if (t1->ty == Tpointer || t2->ty == Tpointer)
1007             {
1008                 /* Rewrite:
1009                  *      ptr1 == ptr2
1010                  * as:
1011                  *      ptr1 is ptr2
1012                  *
1013                  * This is just a rewriting for deterministic AST representation
1014                  * as the backend input.
1015                  */
1016                 TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
1017                 result = new IdentityExp(op2, e->loc, e->e1, e->e2);
1018                 result = semantic(result, sc);
1019                 return;
1020             }
1021 
1022             /* Check for struct equality without opEquals.
1023              */
1024             if (t1->ty == Tstruct && t2->ty == Tstruct)
1025             {
1026                 StructDeclaration *sd = ((TypeStruct *)t1)->sym;
1027                 if (sd != ((TypeStruct *)t2)->sym)
1028                     return;
1029 
1030                 if (!needOpEquals(sd))
1031                 {
1032                     // Use bitwise equality.
1033                     TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
1034                     result = new IdentityExp(op2, e->loc, e->e1, e->e2);
1035                     result = semantic(result, sc);
1036                     return;
1037                 }
1038 
1039                 /* Do memberwise equality.
1040                  * Rewrite:
1041                  *      e1 == e2
1042                  * as:
1043                  *      e1.tupleof == e2.tupleof
1044                  *
1045                  * If sd is a nested struct, and if it's nested in a class, it will
1046                  * also compare the parent class's equality. Otherwise, compares
1047                  * the identity of parent context through void*.
1048                  */
1049                 if (e->att1 && t1 == e->att1)
1050                     return;
1051                 if (e->att2 && t2 == e->att2)
1052                     return;
1053 
1054                 e = (EqualExp *)e->copy();
1055                 if (!e->att1)
1056                     e->att1 = t1;
1057                 if (!e->att2)
1058                     e->att2 = t2;
1059                 e->e1 = new DotIdExp(e->loc, e->e1, Id::_tupleof);
1060                 e->e2 = new DotIdExp(e->loc, e->e2, Id::_tupleof);
1061                 result = semantic(e, sc);
1062 
1063                 /* Bugzilla 15292, if the rewrite result is same with the original,
1064                  * the equality is unresolvable because it has recursive definition.
1065                  */
1066                 if (result->op == e->op &&
1067                     ((EqualExp *)result)->e1->type->toBasetype() == t1)
1068                 {
1069                     e->error("cannot compare %s because its auto generated member-wise equality has recursive definition",
1070                         t1->toChars());
1071                     result = new ErrorExp();
1072                 }
1073                 return;
1074             }
1075 
1076             /* Check for tuple equality.
1077              */
1078             if (e->e1->op == TOKtuple && e->e2->op == TOKtuple)
1079             {
1080                 TupleExp *tup1 = (TupleExp *)e->e1;
1081                 TupleExp *tup2 = (TupleExp *)e->e2;
1082                 size_t dim = tup1->exps->dim;
1083                 if (dim != tup2->exps->dim)
1084                 {
1085                     e->error("mismatched tuple lengths, %d and %d",
1086                         (int)dim, (int)tup2->exps->dim);
1087                     result = new ErrorExp();
1088                     return;
1089                 }
1090 
1091                 if (dim == 0)
1092                 {
1093                     // zero-length tuple comparison should always return true or false.
1094                     result = new IntegerExp(e->loc, (e->op == TOKequal), Type::tbool);
1095                 }
1096                 else
1097                 {
1098                     for (size_t i = 0; i < dim; i++)
1099                     {
1100                         Expression *ex1 = (*tup1->exps)[i];
1101                         Expression *ex2 = (*tup2->exps)[i];
1102                         EqualExp *eeq = new EqualExp(e->op, e->loc, ex1, ex2);
1103                         eeq->att1 = e->att1;
1104                         eeq->att2 = e->att2;
1105 
1106                         if (!result)
1107                             result = eeq;
1108                         else if (e->op == TOKequal)
1109                             result = new AndAndExp(e->loc, result, eeq);
1110                         else
1111                             result = new OrOrExp(e->loc, result, eeq);
1112                     }
1113                     assert(result);
1114                 }
1115                 result = Expression::combine(Expression::combine(tup1->e0, tup2->e0), result);
1116                 result = semantic(result, sc);
1117                 return;
1118             }
1119         }
1120 
1121         void visit(CmpExp *e)
1122         {
1123             //printf("CmpExp::op_overload() (%s)\n", e->toChars());
1124 
1125             result = compare_overload(e, sc, Id::cmp);
1126         }
1127 
1128         /*********************************
1129          * Operator overloading for op=
1130          */
1131         void visit(BinAssignExp *e)
1132         {
1133             //printf("BinAssignExp::op_overload() (%s)\n", e->toChars());
1134 
1135             if (e->e1->op == TOKarray)
1136             {
1137                 ArrayExp *ae = (ArrayExp *)e->e1;
1138                 ae->e1 = semantic(ae->e1, sc);
1139                 ae->e1 = resolveProperties(sc, ae->e1);
1140                 Expression *ae1old = ae->e1;
1141 
1142                 const bool maybeSlice =
1143                     (ae->arguments->dim == 0 ||
1144                      (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval));
1145                 IntervalExp *ie = NULL;
1146                 if (maybeSlice && ae->arguments->dim)
1147                 {
1148                     assert((*ae->arguments)[0]->op == TOKinterval);
1149                     ie = (IntervalExp *)(*ae->arguments)[0];
1150                 }
1151 
1152                 while (true)
1153                 {
1154                     if (ae->e1->op == TOKerror)
1155                     {
1156                         result = ae->e1;
1157                         return;
1158                     }
1159                     Expression *e0 = NULL;
1160                     Expression *ae1save = ae->e1;
1161                     ae->lengthVar = NULL;
1162 
1163                     Type *t1b = ae->e1->type->toBasetype();
1164                     AggregateDeclaration *ad = isAggregate(t1b);
1165                     if (!ad)
1166                         break;
1167                     if (search_function(ad, Id::opIndexOpAssign))
1168                     {
1169                         // Deal with $
1170                         result = resolveOpDollar(sc, ae, &e0);
1171                         if (!result)    // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
1172                             goto Lfallback;
1173                         if (result->op == TOKerror)
1174                             return;
1175 
1176                         result = semantic(e->e2, sc);
1177                         if (result->op == TOKerror)
1178                             return;
1179                         e->e2 = result;
1180 
1181                         /* Rewrite a[arguments] op= e2 as:
1182                          *      a.opIndexOpAssign!(op)(e2, arguments)
1183                          */
1184                         Expressions *a = (Expressions *)ae->arguments->copy();
1185                         a->insert(0, e->e2);
1186                         Objects *tiargs = opToArg(sc, e->op);
1187                         result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexOpAssign, tiargs);
1188                         result = new CallExp(e->loc, result, a);
1189                         if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
1190                             result = trySemantic(result, sc);
1191                         else
1192                             result = semantic(result, sc);
1193                         if (result)
1194                         {
1195                             result = Expression::combine(e0, result);
1196                             return;
1197                         }
1198                     }
1199                 Lfallback:
1200                     if (maybeSlice && search_function(ad, Id::opSliceOpAssign))
1201                     {
1202                         // Deal with $
1203                         result = resolveOpDollar(sc, ae, ie, &e0);
1204                         if (result->op == TOKerror)
1205                             return;
1206 
1207                         result = semantic(e->e2, sc);
1208                         if (result->op == TOKerror)
1209                             return;
1210                         e->e2 = result;
1211 
1212                         /* Rewrite (a[i..j] op= e2) as:
1213                          *      a.opSliceOpAssign!(op)(e2, i, j)
1214                          */
1215                         Expressions *a = new Expressions();
1216                         a->push(e->e2);
1217                         if (ie)
1218                         {
1219                             a->push(ie->lwr);
1220                             a->push(ie->upr);
1221                         }
1222                         Objects *tiargs = opToArg(sc, e->op);
1223                         result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceOpAssign, tiargs);
1224                         result = new CallExp(e->loc, result, a);
1225                         result = semantic(result, sc);
1226                         result = Expression::combine(e0, result);
1227                         return;
1228                     }
1229 
1230                     // Didn't find it. Forward to aliasthis
1231                     if (ad->aliasthis && t1b != ae->att1)
1232                     {
1233                         if (!ae->att1 && t1b->checkAliasThisRec())
1234                             ae->att1 = t1b;
1235 
1236                         /* Rewrite (a[arguments] op= e2) as:
1237                          *      a.aliasthis[arguments] op= e2
1238                          */
1239                         ae->e1 = resolveAliasThis(sc, ae1save, true);
1240                         if (ae->e1)
1241                             continue;
1242                     }
1243                     break;
1244                 }
1245                 ae->e1 = ae1old;    // recovery
1246                 ae->lengthVar = NULL;
1247             }
1248 
1249             result = binSemanticProp(e, sc);
1250             if (result)
1251                 return;
1252 
1253             // Don't attempt 'alias this' if an error occured
1254             if (e->e1->type->ty == Terror || e->e2->type->ty == Terror)
1255             {
1256                 result = new ErrorExp();
1257                 return;
1258             }
1259 
1260             Identifier *id = opId(e);
1261 
1262             Expressions args2;
1263 
1264             AggregateDeclaration *ad1 = isAggregate(e->e1->type);
1265 
1266             Dsymbol *s = NULL;
1267 
1268         #if 1 // the old D1 scheme
1269             if (ad1 && id)
1270             {
1271                 s = search_function(ad1, id);
1272             }
1273         #endif
1274 
1275             Objects *tiargs = NULL;
1276             if (!s)
1277             {
1278                 /* Try the new D2 scheme, opOpAssign
1279                  */
1280                 if (ad1)
1281                 {
1282                     s = search_function(ad1, Id::opOpAssign);
1283                     if (s && !s->isTemplateDeclaration())
1284                     {
1285                         e->error("%s.opOpAssign isn't a template", e->e1->toChars());
1286                         result = new ErrorExp();
1287                         return;
1288                     }
1289                 }
1290 
1291                 // Set tiargs, the template argument list, which will be the operator string
1292                 if (s)
1293                 {
1294                     id = Id::opOpAssign;
1295                     tiargs = opToArg(sc, e->op);
1296                 }
1297             }
1298 
1299             if (s)
1300             {
1301                 /* Try:
1302                  *      a.opOpAssign(b)
1303                  */
1304 
1305                 args2.setDim(1);
1306                 args2[0] = e->e2;
1307                 expandTuples(&args2);
1308 
1309                 Match m;
1310                 memset(&m, 0, sizeof(m));
1311                 m.last = MATCHnomatch;
1312 
1313                 if (s)
1314                 {
1315                     functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
1316                     if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
1317                     {
1318                         result = new ErrorExp();
1319                         return;
1320                     }
1321                 }
1322 
1323                 if (m.count > 1)
1324                 {
1325                     // Error, ambiguous
1326                     e->error("overloads %s and %s both match argument list for %s",
1327                             m.lastf->type->toChars(),
1328                             m.nextf->type->toChars(),
1329                             m.lastf->toChars());
1330                 }
1331                 else if (m.last <= MATCHnomatch)
1332                 {
1333                     m.lastf = m.anyf;
1334                     if (tiargs)
1335                         goto L1;
1336                 }
1337 
1338                 // Rewrite (e1 op e2) as e1.opOpAssign(e2)
1339                 result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
1340                 return;
1341             }
1342 
1343         L1:
1344 
1345             // Try alias this on first operand
1346             if (ad1 && ad1->aliasthis)
1347             {
1348                 /* Rewrite (e1 op e2) as:
1349                  *      (e1.aliasthis op e2)
1350                  */
1351                 if (e->att1 && e->e1->type == e->att1)
1352                     return;
1353                 //printf("att %s e1 = %s\n", Token::toChars(e->op), e->e1->type->toChars());
1354                 Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
1355                 BinExp *be = (BinExp *)e->copy();
1356                 if (!be->att1 && e->e1->type->checkAliasThisRec())
1357                     be->att1 = e->e1->type;
1358                 be->e1 = e1;
1359                 result = trySemantic(be, sc);
1360                 return;
1361             }
1362 
1363             // Try alias this on second operand
1364             AggregateDeclaration *ad2 = isAggregate(e->e2->type);
1365             if (ad2 && ad2->aliasthis)
1366             {
1367                 /* Rewrite (e1 op e2) as:
1368                  *      (e1 op e2.aliasthis)
1369                  */
1370                 if (e->att2 && e->e2->type == e->att2)
1371                     return;
1372                 //printf("att %s e2 = %s\n", Token::toChars(e->op), e->e2->type->toChars());
1373                 Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
1374                 BinExp *be = (BinExp *)e->copy();
1375                 if (!be->att2 && e->e2->type->checkAliasThisRec())
1376                     be->att2 = e->e2->type;
1377                 be->e2 = e2;
1378                 result = trySemantic(be, sc);
1379                 return;
1380             }
1381         }
1382     };
1383 
1384     OpOverload v(sc);
1385     e->accept(&v);
1386     return v.result;
1387 }
1388 
1389 /******************************************
1390  * Common code for overloading of EqualExp and CmpExp
1391  */
compare_overload(BinExp * e,Scope * sc,Identifier * id)1392 Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id)
1393 {
1394     //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), e->toChars());
1395 
1396     AggregateDeclaration *ad1 = isAggregate(e->e1->type);
1397     AggregateDeclaration *ad2 = isAggregate(e->e2->type);
1398 
1399     Dsymbol *s = NULL;
1400     Dsymbol *s_r = NULL;
1401 
1402     if (ad1)
1403     {
1404         s = search_function(ad1, id);
1405     }
1406     if (ad2)
1407     {
1408         s_r = search_function(ad2, id);
1409         if (s == s_r)
1410             s_r = NULL;
1411     }
1412 
1413     Objects *tiargs = NULL;
1414 
1415     if (s || s_r)
1416     {
1417         /* Try:
1418          *      a.opEquals(b)
1419          *      b.opEquals(a)
1420          * and see which is better.
1421          */
1422 
1423         Expressions args1;
1424         Expressions args2;
1425 
1426         args1.setDim(1);
1427         args1[0] = e->e1;
1428         expandTuples(&args1);
1429         args2.setDim(1);
1430         args2[0] = e->e2;
1431         expandTuples(&args2);
1432 
1433         Match m;
1434         memset(&m, 0, sizeof(m));
1435         m.last = MATCHnomatch;
1436 
1437         if (0 && s && s_r)
1438         {
1439             printf("s  : %s\n", s->toPrettyChars());
1440             printf("s_r: %s\n", s_r->toPrettyChars());
1441         }
1442 
1443         if (s)
1444         {
1445             functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
1446             if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
1447                 return new ErrorExp();
1448         }
1449 
1450         FuncDeclaration *lastf = m.lastf;
1451         int count = m.count;
1452 
1453         if (s_r)
1454         {
1455             functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
1456             if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
1457                 return new ErrorExp();
1458         }
1459 
1460         if (m.count > 1)
1461         {
1462             /* The following if says "not ambiguous" if there's one match
1463              * from s and one from s_r, in which case we pick s.
1464              * This doesn't follow the spec, but is a workaround for the case
1465              * where opEquals was generated from templates and we cannot figure
1466              * out if both s and s_r came from the same declaration or not.
1467              * The test case is:
1468              *   import std.typecons;
1469              *   void main() {
1470              *    assert(tuple("has a", 2u) == tuple("has a", 1));
1471              *   }
1472              */
1473             if (!(m.lastf == lastf && m.count == 2 && count == 1))
1474             {
1475                 // Error, ambiguous
1476                 e->error("overloads %s and %s both match argument list for %s",
1477                     m.lastf->type->toChars(),
1478                     m.nextf->type->toChars(),
1479                     m.lastf->toChars());
1480             }
1481         }
1482         else if (m.last <= MATCHnomatch)
1483         {
1484             m.lastf = m.anyf;
1485         }
1486 
1487         Expression *result;
1488         if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch))
1489         {
1490             // Rewrite (e1 op e2) as e1.opfunc(e2)
1491             result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
1492         }
1493         else
1494         {
1495             // Rewrite (e1 op e2) as e2.opfunc_r(e1)
1496             result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
1497 
1498             // When reversing operands of comparison operators,
1499             // need to reverse the sense of the op
1500             switch (e->op)
1501             {
1502                 case TOKlt:     e->op = TOKgt;     break;
1503                 case TOKgt:     e->op = TOKlt;     break;
1504                 case TOKle:     e->op = TOKge;     break;
1505                 case TOKge:     e->op = TOKle;     break;
1506 
1507                 // The rest are symmetric
1508                 default:
1509                     break;
1510             }
1511         }
1512 
1513         return result;
1514     }
1515 
1516     // Try alias this on first operand
1517     if (ad1 && ad1->aliasthis)
1518     {
1519         /* Rewrite (e1 op e2) as:
1520          *      (e1.aliasthis op e2)
1521          */
1522         if (e->att1 && e->e1->type == e->att1)
1523             return NULL;
1524         //printf("att cmp_bin e1 = %s\n", e->e1->type->toChars());
1525         Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
1526         BinExp *be = (BinExp *)e->copy();
1527         if (!be->att1 && e->e1->type->checkAliasThisRec())
1528             be->att1 = e->e1->type;
1529         be->e1 = e1;
1530         return trySemantic(be, sc);
1531     }
1532 
1533     // Try alias this on second operand
1534     if (ad2 && ad2->aliasthis)
1535     {
1536         /* Rewrite (e1 op e2) as:
1537          *      (e1 op e2.aliasthis)
1538          */
1539         if (e->att2 && e->e2->type == e->att2)
1540             return NULL;
1541         //printf("att cmp_bin e2 = %s\n", e->e2->type->toChars());
1542         Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
1543         BinExp *be = (BinExp *)e->copy();
1544         if (!be->att2 && e->e2->type->checkAliasThisRec())
1545             be->att2 = e->e2->type;
1546         be->e2 = e2;
1547         return trySemantic(be, sc);
1548     }
1549 
1550     return NULL;
1551 }
1552 
1553 /***********************************
1554  * Utility to build a function call out of this reference and argument.
1555  */
1556 
build_overload(Loc loc,Scope * sc,Expression * ethis,Expression * earg,Dsymbol * d)1557 Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg,
1558         Dsymbol *d)
1559 {
1560     assert(d);
1561     Expression *e;
1562 
1563     //printf("build_overload(id = '%s')\n", id->toChars());
1564     //earg->print();
1565     //earg->type->print();
1566     Declaration *decl = d->isDeclaration();
1567     if (decl)
1568         e = new DotVarExp(loc, ethis, decl, false);
1569     else
1570         e = new DotIdExp(loc, ethis, d->ident);
1571     e = new CallExp(loc, e, earg);
1572 
1573     e = semantic(e, sc);
1574     return e;
1575 }
1576 
1577 /***************************************
1578  * Search for function funcid in aggregate ad.
1579  */
1580 
search_function(ScopeDsymbol * ad,Identifier * funcid)1581 Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid)
1582 {
1583     Dsymbol *s = ad->search(Loc(), funcid);
1584     if (s)
1585     {
1586         //printf("search_function: s = '%s'\n", s->kind());
1587         Dsymbol *s2 = s->toAlias();
1588         //printf("search_function: s2 = '%s'\n", s2->kind());
1589         FuncDeclaration *fd = s2->isFuncDeclaration();
1590         if (fd && fd->type->ty == Tfunction)
1591             return fd;
1592 
1593         TemplateDeclaration *td = s2->isTemplateDeclaration();
1594         if (td)
1595             return td;
1596     }
1597     return NULL;
1598 }
1599 
1600 
inferAggregate(ForeachStatement * fes,Scope * sc,Dsymbol * & sapply)1601 bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
1602 {
1603     //printf("inferAggregate(%s)\n", fes->aggr->toChars());
1604     Identifier *idapply = (fes->op == TOKforeach) ? Id::apply : Id::applyReverse;
1605     Identifier *idfront = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
1606     int sliced = 0;
1607     Type *tab;
1608     Type *att = NULL;
1609     Expression *aggr = fes->aggr;
1610     AggregateDeclaration *ad;
1611 
1612     while (1)
1613     {
1614         aggr = semantic(aggr, sc);
1615         aggr = resolveProperties(sc, aggr);
1616         aggr = aggr->optimize(WANTvalue);
1617         if (!aggr->type || aggr->op == TOKerror)
1618             goto Lerr;
1619 
1620         tab = aggr->type->toBasetype();
1621         switch (tab->ty)
1622         {
1623             case Tarray:
1624             case Tsarray:
1625             case Ttuple:
1626             case Taarray:
1627                 break;
1628 
1629             case Tclass:
1630                 ad = ((TypeClass *)tab)->sym;
1631                 goto Laggr;
1632 
1633             case Tstruct:
1634                 ad = ((TypeStruct *)tab)->sym;
1635                 goto Laggr;
1636 
1637             Laggr:
1638                 if (!sliced)
1639                 {
1640                     sapply = search_function(ad, idapply);
1641                     if (sapply)
1642                     {
1643                         // opApply aggregate
1644                         break;
1645                     }
1646 
1647                     if (fes->aggr->op != TOKtype)
1648                     {
1649                         Expression *rinit = new ArrayExp(fes->aggr->loc, fes->aggr);
1650                         rinit = trySemantic(rinit, sc);
1651                         if (rinit)                  // if application of [] succeeded
1652                         {
1653                             aggr = rinit;
1654                             sliced = 1;
1655                             continue;
1656                         }
1657                     }
1658                 }
1659 
1660                 if (ad->search(Loc(), idfront))
1661                 {
1662                     // range aggregate
1663                     break;
1664                 }
1665 
1666                 if (ad->aliasthis)
1667                 {
1668                     if (att == tab)
1669                         goto Lerr;
1670                     if (!att && tab->checkAliasThisRec())
1671                         att = tab;
1672                     aggr = resolveAliasThis(sc, aggr);
1673                     continue;
1674                 }
1675                 goto Lerr;
1676 
1677             case Tdelegate:
1678                 if (aggr->op == TOKdelegate)
1679                 {
1680                     sapply = ((DelegateExp *)aggr)->func;
1681                 }
1682                 break;
1683 
1684             case Terror:
1685                 break;
1686 
1687             default:
1688                 goto Lerr;
1689         }
1690         break;
1691     }
1692     fes->aggr = aggr;
1693     return true;
1694 
1695 Lerr:
1696     return false;
1697 }
1698 
1699 /*****************************************
1700  * Given array of parameters and an aggregate type,
1701  * if any of the parameter types are missing, attempt to infer
1702  * them from the aggregate type.
1703  */
1704 
inferApplyArgTypes(ForeachStatement * fes,Scope * sc,Dsymbol * & sapply)1705 bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
1706 {
1707     if (!fes->parameters || !fes->parameters->dim)
1708         return false;
1709 
1710     if (sapply)     // prefer opApply
1711     {
1712         for (size_t u = 0; u < fes->parameters->dim; u++)
1713         {
1714             Parameter *p = (*fes->parameters)[u];
1715             if (p->type)
1716             {
1717                 p->type = p->type->semantic(fes->loc, sc);
1718                 p->type = p->type->addStorageClass(p->storageClass);
1719             }
1720         }
1721 
1722         Expression *ethis;
1723         Type *tab = fes->aggr->type->toBasetype();
1724         if (tab->ty == Tclass || tab->ty == Tstruct)
1725             ethis = fes->aggr;
1726         else
1727         {   assert(tab->ty == Tdelegate && fes->aggr->op == TOKdelegate);
1728             ethis = ((DelegateExp *)fes->aggr)->e1;
1729         }
1730 
1731         /* Look for like an
1732          *  int opApply(int delegate(ref Type [, ...]) dg);
1733          * overload
1734          */
1735         FuncDeclaration *fd = sapply->isFuncDeclaration();
1736         if (fd)
1737         {
1738             sapply = inferApplyArgTypesX(ethis, fd, fes->parameters);
1739         }
1740         return sapply != NULL;
1741     }
1742 
1743     /* Return if no parameters need types.
1744      */
1745     for (size_t u = 0; u < fes->parameters->dim; u++)
1746     {
1747         Parameter *p = (*fes->parameters)[u];
1748         if (!p->type)
1749             break;
1750     }
1751 
1752     AggregateDeclaration *ad;
1753 
1754     Parameter *p = (*fes->parameters)[0];
1755     Type *taggr = fes->aggr->type;
1756     assert(taggr);
1757     Type *tab = taggr->toBasetype();
1758     switch (tab->ty)
1759     {
1760         case Tarray:
1761         case Tsarray:
1762         case Ttuple:
1763             if (fes->parameters->dim == 2)
1764             {
1765                 if (!p->type)
1766                 {
1767                     p->type = Type::tsize_t;    // key type
1768                     p->type = p->type->addStorageClass(p->storageClass);
1769                 }
1770                 p = (*fes->parameters)[1];
1771             }
1772             if (!p->type && tab->ty != Ttuple)
1773             {
1774                 p->type = tab->nextOf();        // value type
1775                 p->type = p->type->addStorageClass(p->storageClass);
1776             }
1777             break;
1778 
1779         case Taarray:
1780         {
1781             TypeAArray *taa = (TypeAArray *)tab;
1782 
1783             if (fes->parameters->dim == 2)
1784             {
1785                 if (!p->type)
1786                 {
1787                     p->type = taa->index;       // key type
1788                     p->type = p->type->addStorageClass(p->storageClass);
1789                     if (p->storageClass & STCref) // key must not be mutated via ref
1790                         p->type = p->type->addMod(MODconst);
1791                 }
1792                 p = (*fes->parameters)[1];
1793             }
1794             if (!p->type)
1795             {
1796                 p->type = taa->next;            // value type
1797                 p->type = p->type->addStorageClass(p->storageClass);
1798             }
1799             break;
1800         }
1801 
1802         case Tclass:
1803             ad = ((TypeClass *)tab)->sym;
1804             goto Laggr;
1805 
1806         case Tstruct:
1807             ad = ((TypeStruct *)tab)->sym;
1808             goto Laggr;
1809 
1810         Laggr:
1811             if (fes->parameters->dim == 1)
1812             {
1813                 if (!p->type)
1814                 {
1815                     /* Look for a front() or back() overload
1816                      */
1817                     Identifier *id = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
1818                     Dsymbol *s = ad->search(Loc(), id);
1819                     FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
1820                     if (fd)
1821                     {
1822                         // Resolve inout qualifier of front type
1823                         p->type = fd->type->nextOf();
1824                         if (p->type)
1825                         {
1826                             p->type = p->type->substWildTo(tab->mod);
1827                             p->type = p->type->addStorageClass(p->storageClass);
1828                         }
1829                     }
1830                     else if (s && s->isTemplateDeclaration())
1831                         ;
1832                     else if (s && s->isDeclaration())
1833                         p->type = ((Declaration *)s)->type;
1834                     else
1835                         break;
1836                 }
1837                 break;
1838             }
1839             break;
1840 
1841         case Tdelegate:
1842         {
1843             if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), fes->parameters))
1844                 return false;
1845             break;
1846         }
1847 
1848         default:
1849             break;              // ignore error, caught later
1850     }
1851     return true;
1852 }
1853 
inferApplyArgTypesX(Expression * ethis,FuncDeclaration * fstart,Parameters * parameters)1854 static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters)
1855 {
1856   struct ParamOpOver
1857   {
1858     Parameters *parameters;
1859     MOD mod;
1860     MATCH match;
1861     FuncDeclaration *fd_best;
1862     FuncDeclaration *fd_ambig;
1863 
1864     static int fp(void *param, Dsymbol *s)
1865     {
1866         FuncDeclaration *f = s->isFuncDeclaration();
1867         if (!f)
1868             return 0;
1869         ParamOpOver *p = (ParamOpOver *)param;
1870         TypeFunction *tf = (TypeFunction *)f->type;
1871         MATCH m = MATCHexact;
1872 
1873         if (f->isThis())
1874         {
1875             if (!MODimplicitConv(p->mod, tf->mod))
1876                 m = MATCHnomatch;
1877             else if (p->mod != tf->mod)
1878                 m = MATCHconst;
1879         }
1880         if (!inferApplyArgTypesY(tf, p->parameters, 1))
1881             m = MATCHnomatch;
1882 
1883         if (m > p->match)
1884         {
1885             p->fd_best = f;
1886             p->fd_ambig = NULL;
1887             p->match = m;
1888         }
1889         else if (m == p->match)
1890             p->fd_ambig = f;
1891         return 0;
1892     }
1893   };
1894     ParamOpOver p;
1895     p.parameters = parameters;
1896     p.mod = ethis->type->mod;
1897     p.match = MATCHnomatch;
1898     p.fd_best = NULL;
1899     p.fd_ambig = NULL;
1900     overloadApply(fstart, &p, &ParamOpOver::fp);
1901     if (p.fd_best)
1902     {
1903         inferApplyArgTypesY((TypeFunction *)p.fd_best->type, parameters);
1904         if (p.fd_ambig)
1905         {   ::error(ethis->loc, "%s.%s matches more than one declaration:\n%s:     %s\nand:\n%s:     %s",
1906                     ethis->toChars(), fstart->ident->toChars(),
1907                     p.fd_best ->loc.toChars(), p.fd_best ->type->toChars(),
1908                     p.fd_ambig->loc.toChars(), p.fd_ambig->type->toChars());
1909             p.fd_best = NULL;
1910         }
1911     }
1912     return p.fd_best;
1913 }
1914 
1915 /******************************
1916  * Infer parameters from type of function.
1917  * Returns:
1918  *      1 match for this function
1919  *      0 no match for this function
1920  */
1921 
inferApplyArgTypesY(TypeFunction * tf,Parameters * parameters,int flags)1922 static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags)
1923 {   size_t nparams;
1924     Parameter *p;
1925 
1926     if (Parameter::dim(tf->parameters) != 1)
1927         goto Lnomatch;
1928     p = Parameter::getNth(tf->parameters, 0);
1929     if (p->type->ty != Tdelegate)
1930         goto Lnomatch;
1931     tf = (TypeFunction *)p->type->nextOf();
1932     assert(tf->ty == Tfunction);
1933 
1934     /* We now have tf, the type of the delegate. Match it against
1935      * the parameters, filling in missing parameter types.
1936      */
1937     nparams = Parameter::dim(tf->parameters);
1938     if (nparams == 0 || tf->varargs)
1939         goto Lnomatch;          // not enough parameters
1940     if (parameters->dim != nparams)
1941         goto Lnomatch;          // not enough parameters
1942 
1943     for (size_t u = 0; u < nparams; u++)
1944     {
1945         p = (*parameters)[u];
1946         Parameter *param = Parameter::getNth(tf->parameters, u);
1947         if (p->type)
1948         {
1949             if (!p->type->equals(param->type))
1950                 goto Lnomatch;
1951         }
1952         else if (!flags)
1953         {
1954             p->type = param->type;
1955             p->type = p->type->addStorageClass(p->storageClass);
1956         }
1957     }
1958     return 1;
1959 
1960 Lnomatch:
1961     return 0;
1962 }
1963 
1964