root/trunk/src/opover.c

Revision 735, 40.6 kB (checked in by walter, 2 years ago)

fix alias this problem

  • Property svn:eol-style set to native
Line 
1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2010 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // License for redistribution is by either the Artistic License
7 // in artistic.txt, or the GNU General Public License in gnu.txt.
8 // See the included readme.txt for details.
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <assert.h>
14 #if _MSC_VER
15 #include <complex>
16 #else
17 #include <complex.h>
18 #endif
19
20 #ifdef __APPLE__
21 #define integer_t dmd_integer_t
22 #endif
23
24 #include "rmem.h"
25
26 //#include "port.h"
27 #include "mtype.h"
28 #include "init.h"
29 #include "expression.h"
30 #include "id.h"
31 #include "declaration.h"
32 #include "aggregate.h"
33 #include "template.h"
34
35 static void inferApplyArgTypesX(FuncDeclaration *fstart, Parameters *arguments);
36 static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments);
37 static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments);
38 static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments);
39
40 /******************************** Expression **************************/
41
42
43 /***********************************
44  * Determine if operands of binary op can be reversed
45  * to fit operator overload.
46  */
47
48 int Expression::isCommutative()
49 {
50     return FALSE;       // default is no reverse
51 }
52
53 /***********************************
54  * Get Identifier for operator overload.
55  */
56
57 Identifier *Expression::opId()
58 {
59     assert(0);
60     return NULL;
61 }
62
63 /***********************************
64  * Get Identifier for reverse operator overload,
65  * NULL if not supported for this operator.
66  */
67
68 Identifier *Expression::opId_r()
69 {
70     return NULL;
71 }
72
73 /************************* Operators *****************************/
74
75 Identifier *UAddExp::opId()   { return Id::uadd; }
76
77 Identifier *NegExp::opId()   { return Id::neg; }
78
79 Identifier *ComExp::opId()   { return Id::com; }
80
81 Identifier *CastExp::opId()   { return Id::cast; }
82
83 Identifier *InExp::opId()     { return Id::opIn; }
84 Identifier *InExp::opId_r()     { return Id::opIn_r; }
85
86 Identifier *PostExp::opId() { return (op == TOKplusplus)
87                                 ? Id::postinc
88                                 : Id::postdec; }
89
90 int AddExp::isCommutative()  { return TRUE; }
91 Identifier *AddExp::opId()   { return Id::add; }
92 Identifier *AddExp::opId_r() { return Id::add_r; }
93
94 Identifier *MinExp::opId()   { return Id::sub; }
95 Identifier *MinExp::opId_r() { return Id::sub_r; }
96
97 int MulExp::isCommutative()  { return TRUE; }
98 Identifier *MulExp::opId()   { return Id::mul; }
99 Identifier *MulExp::opId_r() { return Id::mul_r; }
100
101 Identifier *DivExp::opId()   { return Id::div; }
102 Identifier *DivExp::opId_r() { return Id::div_r; }
103
104 Identifier *ModExp::opId()   { return Id::mod; }
105 Identifier *ModExp::opId_r() { return Id::mod_r; }
106
107 #if DMDV2
108 Identifier *PowExp::opId()   { return Id::pow; }
109 Identifier *PowExp::opId_r() { return Id::pow_r; }
110 #endif
111
112 Identifier *ShlExp::opId()   { return Id::shl; }
113 Identifier *ShlExp::opId_r() { return Id::shl_r; }
114
115 Identifier *ShrExp::opId()   { return Id::shr; }
116 Identifier *ShrExp::opId_r() { return Id::shr_r; }
117
118 Identifier *UshrExp::opId()   { return Id::ushr; }
119 Identifier *UshrExp::opId_r() { return Id::ushr_r; }
120
121 int AndExp::isCommutative()  { return TRUE; }
122 Identifier *AndExp::opId()   { return Id::iand; }
123 Identifier *AndExp::opId_r() { return Id::iand_r; }
124
125 int OrExp::isCommutative()  { return TRUE; }
126 Identifier *OrExp::opId()   { return Id::ior; }
127 Identifier *OrExp::opId_r() { return Id::ior_r; }
128
129 int XorExp::isCommutative()  { return TRUE; }
130 Identifier *XorExp::opId()   { return Id::ixor; }
131 Identifier *XorExp::opId_r() { return Id::ixor_r; }
132
133 Identifier *CatExp::opId()   { return Id::cat; }
134 Identifier *CatExp::opId_r() { return Id::cat_r; }
135
136 Identifier *    AssignExp::opId()  { return Id::assign;  }
137 Identifier * AddAssignExp::opId()  { return Id::addass;  }
138 Identifier * MinAssignExp::opId()  { return Id::subass;  }
139 Identifier * MulAssignExp::opId()  { return Id::mulass;  }
140 Identifier * DivAssignExp::opId()  { return Id::divass;  }
141 Identifier * ModAssignExp::opId()  { return Id::modass;  }
142 Identifier * AndAssignExp::opId()  { return Id::andass;  }
143 Identifier *  OrAssignExp::opId()  { return Id::orass;   }
144 Identifier * XorAssignExp::opId()  { return Id::xorass;  }
145 Identifier * ShlAssignExp::opId()  { return Id::shlass;  }
146 Identifier * ShrAssignExp::opId()  { return Id::shrass;  }
147 Identifier *UshrAssignExp::opId()  { return Id::ushrass; }
148 Identifier * CatAssignExp::opId()  { return Id::catass;  }
149 Identifier * PowAssignExp::opId()  { return Id::powass;  }
150
151 int EqualExp::isCommutative()  { return TRUE; }
152 Identifier *EqualExp::opId()   { return Id::eq; }
153
154 int CmpExp::isCommutative()  { return TRUE; }
155 Identifier *CmpExp::opId()   { return Id::cmp; }
156
157 Identifier *ArrayExp::opId()    { return Id::index; }
158 Identifier *PtrExp::opId()      { return Id::opStar; }
159
160 /************************************
161  * If type is a class or struct, return the symbol for it,
162  * else NULL
163  */
164 AggregateDeclaration *isAggregate(Type *t)
165 {
166     t = t->toBasetype();
167     if (t->ty == Tclass)
168     {
169         return ((TypeClass *)t)->sym;
170     }
171     else if (t->ty == Tstruct)
172     {
173         return ((TypeStruct *)t)->sym;
174     }
175     return NULL;
176 }
177
178 /*******************************************
179  * Helper function to turn operator into template argument list
180  */
181 Objects *opToArg(Scope *sc, enum TOK op)
182 {
183     /* Remove the = from op=
184      */
185     switch (op)
186     {
187         case TOKaddass: op = TOKadd; break;
188         case TOKminass: op = TOKmin; break;
189         case TOKmulass: op = TOKmul; break;
190         case TOKdivass: op = TOKdiv; break;
191         case TOKmodass: op = TOKmod; break;
192         case TOKandass: op = TOKand; break;
193         case TOKorass:  op = TOKor;  break;
194         case TOKxorass: op = TOKxor; break;
195         case TOKshlass: op = TOKshl; break;
196         case TOKshrass: op = TOKshr; break;
197         case TOKushrass: op = TOKushr; break;
198         case TOKcatass: op = TOKcat; break;
199         case TOKpowass: op = TOKpow; break;
200     }
201     Expression *e = new StringExp(0, (char *)Token::toChars(op));
202     e = e->semantic(sc);
203     Objects *targsi = new Objects();
204     targsi->push(e);
205     return targsi;
206 }
207
208 /************************************
209  * Operator overload.
210  * Check for operator overload, if so, replace
211  * with function call.
212  * Return NULL if not an operator overload.
213  */
214
215 Expression *UnaExp::op_overload(Scope *sc)
216 {
217     //printf("UnaExp::op_overload() (%s)\n", toChars());
218
219 #if DMDV2
220     if (e1->op == TOKarray)
221     {
222         ArrayExp *ae = (ArrayExp *)e1;
223         ae->e1 = ae->e1->semantic(sc);
224         ae->e1 = resolveProperties(sc, ae->e1);
225
226         AggregateDeclaration *ad = isAggregate(ae->e1->type);
227         if (ad)
228         {
229             /* Rewrite as:
230              *  a.opIndexUnary!("+")(args);
231              */
232             Dsymbol *fd = search_function(ad, Id::opIndexUnary);
233             if (fd)
234             {
235                 Objects *targsi = opToArg(sc, op);
236                 Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi);
237                 e = new CallExp(loc, e, ae->arguments);
238                 e = e->semantic(sc);
239                 return e;
240             }
241
242             // Didn't find it. Forward to aliasthis
243             if (ad->aliasthis)
244             {
245                 /* Rewrite op(a[arguments]) as:
246                  *      op(a.aliasthis[arguments])
247                  */
248                 Expression *e1 = ae->copy();
249                 ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident);
250                 Expression *e = copy();
251                 ((UnaExp *)e)->e1 = e1;
252                 e = e->trySemantic(sc);
253                 return e;
254             }
255         }
256     }
257     else if (e1->op == TOKslice)
258     {
259         SliceExp *se = (SliceExp *)e1;
260         se->e1 = se->e1->semantic(sc);
261         se->e1 = resolveProperties(sc, se->e1);
262
263         AggregateDeclaration *ad = isAggregate(se->e1->type);
264         if (ad)
265         {
266             /* Rewrite as:
267              *  a.opSliceUnary!("+")(lwr, upr);
268              */
269             Dsymbol *fd = search_function(ad, Id::opSliceUnary);
270             if (fd)
271             {
272                 Expressions *a = new Expressions();
273                 if (se->lwr)
274                 {   a->push(se->lwr);
275                     a->push(se->upr);
276                 }
277
278                 Objects *targsi = opToArg(sc, op);
279                 Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi);
280                 e = new CallExp(loc, e, a);
281                 e = e->semantic(sc);
282                 return e;
283             }
284
285             // Didn't find it. Forward to aliasthis
286             if (ad->aliasthis)
287             {
288                 /* Rewrite op(a[lwr..upr]) as:
289                  *      op(a.aliasthis[lwr..upr])
290                  */
291                 Expression *e1 = se->copy();
292                 ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident);
293                 Expression *e = copy();
294                 ((UnaExp *)e)->e1 = e1;
295                 e = e->trySemantic(sc);
296                 return e;
297             }
298         }
299     }
300 #endif
301
302     e1 = e1->semantic(sc);
303     e1 = resolveProperties(sc, e1);
304
305     AggregateDeclaration *ad = isAggregate(e1->type);
306     if (ad)
307     {
308         Dsymbol *fd = NULL;
309 #if 1 // Old way, kept for compatibility with D1
310         if (op != TOKpreplusplus && op != TOKpreminusminus)
311         {   fd = search_function(ad, opId());
312             if (fd)
313             {
314                 if (op == TOKarray)
315                 {
316                     /* Rewrite op e1[arguments] as:
317                      *    e1.fd(arguments)
318                      */
319                     Expression *e = new DotIdExp(loc, e1, fd->ident);
320                     ArrayExp *ae = (ArrayExp *)this;
321                     e = new CallExp(loc, e, ae->arguments);
322                     e = e->semantic(sc);
323                     return e;
324                 }
325                 else
326                 {
327                     // Rewrite +e1 as e1.add()
328                     return build_overload(loc, sc, e1, NULL, fd->ident);
329                 }
330             }
331         }
332 #endif
333
334 #if DMDV2
335         /* Rewrite as:
336          *      e1.opUnary!("+")();
337          */
338         fd = search_function(ad, Id::opUnary);
339         if (fd)
340         {
341             Objects *targsi = opToArg(sc, op);
342             Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi);
343             e = new CallExp(loc, e);
344             e = e->semantic(sc);
345             return e;
346         }
347
348         // Didn't find it. Forward to aliasthis
349         if (ad->aliasthis)
350         {
351             /* Rewrite op(e1) as:
352              *  op(e1.aliasthis)
353              */
354             Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident);
355             Expression *e = copy();
356             ((UnaExp *)e)->e1 = e1;
357             e = e->trySemantic(sc);
358             return e;
359         }
360 #endif
361     }
362     return NULL;
363 }
364
365 Expression *ArrayExp::op_overload(Scope *sc)
366 {
367     //printf("ArrayExp::op_overload() (%s)\n", toChars());
368     AggregateDeclaration *ad = isAggregate(e1->type);
369     if (ad)
370     {
371         Dsymbol *fd = search_function(ad, opId());
372         if (fd)
373         {
374             /* Rewrite op e1[arguments] as:
375              *    e1.opIndex(arguments)
376              */
377             Expression *e = new DotIdExp(loc, e1, fd->ident);
378             e = new CallExp(loc, e, arguments);
379             e = e->semantic(sc);
380             return e;
381         }
382
383         // Didn't find it. Forward to aliasthis
384         if (ad->aliasthis)
385         {
386             /* Rewrite op(e1) as:
387              *  op(e1.aliasthis)
388              */
389             Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident);
390             Expression *e = copy();
391             ((UnaExp *)e)->e1 = e1;
392             e = e->trySemantic(sc);
393             return e;
394         }
395     }
396     return NULL;
397 }
398
399 /***********************************************
400  * This is mostly the same as UnaryExp::op_overload(), but has
401  * a different rewrite.
402  */
403 Expression *CastExp::op_overload(Scope *sc)
404 {
405     //printf("CastExp::op_overload() (%s)\n", toChars());
406     AggregateDeclaration *ad = isAggregate(e1->type);
407     if (ad)
408     {
409         Dsymbol *fd = NULL;
410         /* Rewrite as:
411          *      e1.opCast!(T)();
412          */
413         fd = search_function(ad, Id::cast);
414         if (fd)
415         {
416 #if 1 // Backwards compatibility with D1 if opCast is a function, not a template
417             if (fd->isFuncDeclaration())
418             {   // Rewrite as:  e1.opCast()
419                 return build_overload(loc, sc, e1, NULL, fd->ident);
420             }
421 #endif
422             Objects *targsi = new Objects();
423             targsi->push(to);
424             Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi);
425             e = new CallExp(loc, e);
426             e = e->semantic(sc);
427             return e;
428         }
429
430         // Didn't find it. Forward to aliasthis
431         if (ad->aliasthis)
432         {
433             /* Rewrite op(e1) as:
434              *  op(e1.aliasthis)
435              */
436             Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident);
437             Expression *e = copy();
438             ((UnaExp *)e)->e1 = e1;
439             e = e->trySemantic(sc);
440             return e;
441         }
442     }
443     return NULL;
444 }
445
446 Expression *BinExp::op_overload(Scope *sc)
447 {
448     //printf("BinExp::op_overload() (%s)\n", toChars());
449
450     Identifier *id = opId();
451     Identifier *id_r = opId_r();
452
453     Expressions args1;
454     Expressions args2;
455     int argsset = 0;
456
457     AggregateDeclaration *ad1 = isAggregate(e1->type);
458     AggregateDeclaration *ad2 = isAggregate(e2->type);
459
460     Dsymbol *s = NULL;
461     Dsymbol *s_r = NULL;
462
463 #if 1 // the old D1 scheme
464     if (ad1 && id)
465     {
466         s = search_function(ad1, id);
467     }
468     if (ad2 && id_r)
469     {
470         s_r = search_function(ad2, id_r);
471     }
472 #endif
473
474     Objects *targsi = NULL;
475 #if DMDV2
476     if (!s && !s_r && op != TOKequal && op != TOKnotequal && op != TOKassign)
477     {   /* Try the new D2 scheme, opBinary and opBinaryRight
478          */
479         if (ad1)
480             s = search_function(ad1, Id::opBinary);
481         if (ad2)
482             s_r = search_function(ad2, Id::opBinaryRight);
483
484         // Set targsi, the template argument list, which will be the operator string
485         if (s || s_r)
486         {
487             id = Id::opBinary;
488             id_r = Id::opBinaryRight;
489             targsi = opToArg(sc, op);
490         }
491     }
492 #endif
493
494     if (s || s_r)
495     {
496         /* Try:
497          *      a.opfunc(b)
498          *      b.opfunc_r(a)
499          * and see which is better.
500          */
501
502         args1.setDim(1);
503         args1.data[0] = (void*) e1;
504         args2.setDim(1);
505         args2.data[0] = (void*) e2;
506         argsset = 1;
507
508         Match m;
509         memset(&m, 0, sizeof(m));
510         m.last = MATCHnomatch;
511
512         if (s)
513         {
514             FuncDeclaration *fd = s->isFuncDeclaration();
515             if (fd)
516             {
517                 overloadResolveX(&m, fd, NULL, &args2);
518             }
519             else
520             {   TemplateDeclaration *td = s->isTemplateDeclaration();
521                 templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
522             }
523         }
524
525         FuncDeclaration *lastf = m.lastf;
526
527         if (s_r)
528         {
529             FuncDeclaration *fd = s_r->isFuncDeclaration();
530             if (fd)
531             {
532                 overloadResolveX(&m, fd, NULL, &args1);
533             }
534             else
535             {   TemplateDeclaration *td = s_r->isTemplateDeclaration();
536                 templateResolve(&m, td, sc, loc, targsi, NULL, &args1);
537             }
538         }
539
540         if (m.count > 1)
541         {
542             // Error, ambiguous
543             error("overloads %s and %s both match argument list for %s",
544                     m.lastf->type->toChars(),
545                     m.nextf->type->toChars(),
546                     m.lastf->toChars());
547         }
548         else if (m.last == MATCHnomatch)
549         {
550             m.lastf = m.anyf;
551             if (targsi)
552                 goto L1;
553         }
554
555         Expression *e;
556         if (op == TOKplusplus || op == TOKminusminus)
557             // Kludge because operator overloading regards e++ and e--
558             // as unary, but it's implemented as a binary.
559             // Rewrite (e1 ++ e2) as e1.postinc()
560             // Rewrite (e1 -- e2) as e1.postdec()
561             e = build_overload(loc, sc, e1, NULL, id);
562         else if (lastf && m.lastf == lastf || m.last == MATCHnomatch)
563             // Rewrite (e1 op e2) as e1.opfunc(e2)
564             e = build_overload(loc, sc, e1, e2, id, targsi);
565         else
566             // Rewrite (e1 op e2) as e2.opfunc_r(e1)
567             e = build_overload(loc, sc, e2, e1, id_r, targsi);
568         return e;
569     }
570
571 L1:
572 #if 1 // Retained for D1 compatibility
573     if (isCommutative() && !targsi)
574     {
575         s = NULL;
576         s_r = NULL;
577         if (ad1 && id_r)
578         {
579             s_r = search_function(ad1, id_r);
580         }
581         if (ad2 && id)
582         {
583             s = search_function(ad2, id);
584         }
585
586         if (s || s_r)
587         {
588             /* Try:
589              *  a.opfunc_r(b)
590              *  b.opfunc(a)
591              * and see which is better.
592              */
593
594             if (!argsset)
595             {   args1.setDim(1);
596                 args1.data[0] = (void*) e1;
597                 args2.setDim(1);
598                 args2.data[0] = (void*) e2;
599             }
600
601             Match m;
602             memset(&m, 0, sizeof(m));
603             m.last = MATCHnomatch;
604
605             if (s_r)
606             {
607                 FuncDeclaration *fd = s_r->isFuncDeclaration();
608                 if (fd)
609                 {
610                     overloadResolveX(&m, fd, NULL, &args2);
611                 }
612                 else
613                 {   TemplateDeclaration *td = s_r->isTemplateDeclaration();
614                     templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
615                 }
616             }
617             FuncDeclaration *lastf = m.lastf;
618
619             if (s)
620             {
621                 FuncDeclaration *fd = s->isFuncDeclaration();
622                 if (fd)
623                 {
624                     overloadResolveX(&m, fd, NULL, &args1);
625                 }
626                 else
627                 {   TemplateDeclaration *td = s->isTemplateDeclaration();
628                     templateResolve(&m, td, sc, loc, targsi, NULL, &args1);
629                 }
630             }
631
632             if (m.count > 1)
633             {
634                 // Error, ambiguous
635                 error("overloads %s and %s both match argument list for %s",
636                         m.lastf->type->toChars(),
637                         m.nextf->type->toChars(),
638                         m.lastf->toChars());
639             }
640             else if (m.last == MATCHnomatch)
641             {
642                 m.lastf = m.anyf;
643             }
644
645             Expression *e;
646             if (lastf && m.lastf == lastf ||
647                 id_r && m.last == MATCHnomatch)
648                 // Rewrite (e1 op e2) as e1.opfunc_r(e2)
649                 e = build_overload(loc, sc, e1, e2, id_r, targsi);
650             else
651                 // Rewrite (e1 op e2) as e2.opfunc(e1)
652                 e = build_overload(loc, sc, e2, e1, id, targsi);
653
654             // When reversing operands of comparison operators,
655             // need to reverse the sense of the op
656             switch (op)
657             {
658                 case TOKlt:     op = TOKgt;     break;
659                 case TOKgt:     op = TOKlt;     break;
660                 case TOKle:     op = TOKge;     break;
661                 case TOKge:     op = TOKle;     break;
662
663                 // Floating point compares
664                 case TOKule:    op = TOKuge;     break;
665                 case TOKul:     op = TOKug;      break;
666                 case TOKuge:    op = TOKule;     break;
667                 case TOKug:     op = TOKul;      break;
668
669                 // These are symmetric
670                 case TOKunord:
671                 case TOKlg:
672                 case TOKleg:
673                 case TOKue:
674                     break;
675             }
676
677             return e;
678         }
679     }
680 #endif
681
682 #if DMDV2
683     // Try alias this on first operand
684     if (ad1 && ad1->aliasthis &&
685         !(op == TOKassign && ad2 && ad1 == ad2))   // See Bugzilla 2943
686     {
687         /* Rewrite (e1 op e2) as:
688          *      (e1.aliasthis op e2)
689          */
690         Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
691         Expression *e = copy();
692         ((BinExp *)e)->e1 = e1;
693         e = e->trySemantic(sc);
694         return e;
695     }
696
697     // Try alias this on second operand
698     if (ad2 && ad2->aliasthis &&
699         /* Bugzilla 2943: make sure that when we're copying the struct, we don't
700          * just copy the alias this member
701          */
702         !(op == TOKassign && ad1 && ad1 == ad2))
703     {
704         /* Rewrite (e1 op e2) as:
705          *      (e1 op e2.aliasthis)
706          */
707         Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
708         Expression *e = copy();
709         ((BinExp *)e)->e2 = e2;
710         e = e->trySemantic(sc);
711         return e;
712     }
713 #endif
714     return NULL;
715 }
716
717 /******************************************
718  * Common code for overloading of EqualExp and CmpExp
719  */
720 Expression *BinExp::compare_overload(Scope *sc, Identifier *id)
721 {
722     //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), toChars());
723
724     AggregateDeclaration *ad1 = isAggregate(e1->type);
725     AggregateDeclaration *ad2 = isAggregate(e2->type);
726
727     Dsymbol *s = NULL;
728     Dsymbol *s_r = NULL;
729
730     if (ad1)
731     {
732         s = search_function(ad1, id);
733     }
734     if (ad2)
735     {
736         s_r = search_function(ad2, id);
737         if (s == s_r)
738             s_r = NULL;
739     }
740
741     Objects *targsi = NULL;
742
743     if (s || s_r)
744     {
745         /* Try:
746          *      a.opEquals(b)
747          *      b.opEquals(a)
748          * and see which is better.
749          */
750
751         Expressions args1;
752         Expressions args2;
753
754         args1.setDim(1);
755         args1.data[0] = (void*) e1;
756         args2.setDim(1);
757         args2.data[0] = (void*) e2;
758
759         Match m;
760         memset(&m, 0, sizeof(m));
761         m.last = MATCHnomatch;
762
763         if (0 && s && s_r)
764         {
765             printf("s  : %s\n", s->toPrettyChars());
766             printf("s_r: %s\n", s_r->toPrettyChars());
767         }
768
769         if (s)
770         {
771             FuncDeclaration *fd = s->isFuncDeclaration();
772             if (fd)
773             {
774                 overloadResolveX(&m, fd, NULL, &args2);
775             }
776             else
777             {   TemplateDeclaration *td = s->isTemplateDeclaration();
778                 templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
779             }
780         }
781
782         FuncDeclaration *lastf = m.lastf;
783         int count = m.count;
784
785         if (s_r)
786         {
787             FuncDeclaration *fd = s_r->isFuncDeclaration();
788             if (fd)
789             {
790                 overloadResolveX(&m, fd, NULL, &args1);
791             }
792             else
793             {   TemplateDeclaration *td = s_r->isTemplateDeclaration();
794                 templateResolve(&m, td, sc, loc, targsi, NULL, &args1);
795             }
796         }
797
798         if (m.count > 1)
799         {
800             /* The following if says "not ambiguous" if there's one match
801              * from s and one from s_r, in which case we pick s.
802              * This doesn't follow the spec, but is a workaround for the case
803              * where opEquals was generated from templates and we cannot figure
804              * out if both s and s_r came from the same declaration or not.
805              * The test case is:
806              *   import std.typecons;
807              *   void main() {
808              *    assert(tuple("has a", 2u) == tuple("has a", 1));
809              *   }
810              */
811             if (!(m.lastf == lastf && m.count == 2 && count == 1))
812             {
813                 // Error, ambiguous
814                 error("overloads %s and %s both match argument list for %s",
815                     m.lastf->type->toChars(),
816                     m.nextf->type->toChars(),
817                     m.lastf->toChars());
818             }
819         }
820         else if (m.last == MATCHnomatch)
821         {
822             m.lastf = m.anyf;
823         }
824
825         Expression *e;
826         if (lastf && m.lastf == lastf || m.last == MATCHnomatch)
827             // Rewrite (e1 op e2) as e1.opfunc(e2)
828             e = build_overload(loc, sc, e1, e2, id, targsi);
829         else
830         {   // Rewrite (e1 op e2) as e2.opfunc_r(e1)
831             e = build_overload(loc, sc, e2, e1, id, targsi);
832
833             // When reversing operands of comparison operators,
834             // need to reverse the sense of the op
835             switch (op)
836             {
837                 case TOKlt:     op = TOKgt;     break;
838                 case TOKgt:     op = TOKlt;     break;
839                 case TOKle:     op = TOKge;     break;
840                 case TOKge:     op = TOKle;     break;
841
842                 // Floating point compares
843                 case TOKule:    op = TOKuge;     break;
844                 case TOKul:     op = TOKug;      break;
845                 case TOKuge:    op = TOKule;     break;
846                 case TOKug:     op = TOKul;      break;
847
848                 // The rest are symmetric
849                 default:
850                     break;
851             }
852         }
853
854         return e;
855     }
856
857     // Try alias this on first operand
858     if (ad1 && ad1->aliasthis)
859     {
860         /* Rewrite (e1 op e2) as:
861          *      (e1.aliasthis op e2)
862          */
863         Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
864         Expression *e = copy();
865         ((BinExp *)e)->e1 = e1;
866         e = e->trySemantic(sc);
867         return e;
868     }
869
870     // Try alias this on second operand
871     if (ad2 && ad2->aliasthis)
872     {
873         /* Rewrite (e1 op e2) as:
874          *      (e1 op e2.aliasthis)
875          */
876         Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
877         Expression *e = copy();
878         ((BinExp *)e)->e2 = e2;
879         e = e->trySemantic(sc);
880         return e;
881     }
882
883     return NULL;
884 }
885
886 Expression *EqualExp::op_overload(Scope *sc)
887 {
888     //printf("EqualExp::op_overload() (%s)\n", toChars());
889
890     Type *t1 = e1->type->toBasetype();
891     Type *t2 = e2->type->toBasetype();
892     if (t1->ty == Tclass && t2->ty == Tclass)
893     {
894         /* Rewrite as:
895          *      .object.opEquals(e1, e2)
896          */
897         Expression *e = new IdentifierExp(loc, Id::empty);
898         e = new DotIdExp(loc, e, Id::object);
899         e = new DotIdExp(loc, e, Id::eq);
900         e = new CallExp(loc, e, e1, e2);
901         e = e->semantic(sc);
902         return e;
903     }
904
905     return compare_overload(sc, Id::eq);
906 }
907
908 Expression *CmpExp::op_overload(Scope *sc)
909 {
910     //printf("CmpExp::op_overload() (%s)\n", toChars());
911
912     return compare_overload(sc, Id::cmp);
913 }
914
915 /*********************************
916  * Operator overloading for op=
917  */
918 Expression *BinAssignExp::op_overload(Scope *sc)
919 {
920     //printf("BinAssignExp::op_overload() (%s)\n", toChars());
921
922 #if DMDV2
923     if (e1->op == TOKarray)
924     {
925         ArrayExp *ae = (ArrayExp *)e1;
926         ae->e1 = ae->e1->semantic(sc);
927         ae->e1 = resolveProperties(sc, ae->e1);
928
929         AggregateDeclaration *ad = isAggregate(ae->e1->type);
930         if (ad)
931         {
932             /* Rewrite a[args]+=e2 as:
933              *  a.opIndexOpAssign!("+")(e2, args);
934              */
935             Dsymbol *fd = search_function(ad, Id::opIndexOpAssign);
936             if (fd)
937             {
938                 Expressions *a = new Expressions();
939                 a->push(e2);
940                 for (int i = 0; i < ae->arguments->dim; i++)
941                     a->push(ae->arguments->data[i]);
942
943                 Objects *targsi = opToArg(sc, op);
944                 Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi);
945                 e = new CallExp(loc, e, a);
946                 e = e->semantic(sc);
947                 return e;
948             }
949
950             // Didn't find it. Forward to aliasthis
951             if (ad->aliasthis)
952             {
953                 /* Rewrite a[arguments] op= e2 as:
954                  *      a.aliasthis[arguments] op= e2
955                  */
956                 Expression *e1 = ae->copy();
957                 ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident);
958                 Expression *e = copy();
959                 ((UnaExp *)e)->e1 = e1;
960                 e = e->trySemantic(sc);
961                 return e;
962             }
963         }
964     }
965     else if (e1->op == TOKslice)
966     {
967         SliceExp *se = (SliceExp *)e1;
968         se->e1 = se->e1->semantic(sc);
969         se->e1 = resolveProperties(sc, se->e1);
970
971         AggregateDeclaration *ad = isAggregate(se->e1->type);
972         if (ad)
973         {
974             /* Rewrite a[lwr..upr]+=e2 as:
975              *  a.opSliceOpAssign!("+")(e2, lwr, upr);
976              */
977             Dsymbol *fd = search_function(ad, Id::opSliceOpAssign);
978             if (fd)
979             {
980                 Expressions *a = new Expressions();
981                 a->push(e2);
982                 if (se->lwr)
983                 {   a->push(se->lwr);
984                     a->push(se->upr);
985                 }
986
987                 Objects *targsi = opToArg(sc, op);
988                 Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi);
989                 e = new CallExp(loc, e, a);
990                 e = e->semantic(sc);
991                 return e;
992             }
993
994             // Didn't find it. Forward to aliasthis
995             if (ad->aliasthis)
996             {
997                 /* Rewrite a[lwr..upr] op= e2 as:
998                  *      a.aliasthis[lwr..upr] op= e2
999                  */
1000                 Expression *e1 = se->copy();
1001                 ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident);
1002                 Expression *e = copy();
1003                 ((UnaExp *)e)->e1 = e1;
1004                 e = e->trySemantic(sc);
1005                 return e;
1006             }
1007         }
1008     }
1009 #endif
1010
1011     BinExp::semantic(sc);
1012     e2 = resolveProperties(sc, e2);
1013
1014     Identifier *id = opId();
1015
1016     Expressions args2;
1017
1018     AggregateDeclaration *ad1 = isAggregate(e1->type);
1019
1020     Dsymbol *s = NULL;
1021
1022 #if 1 // the old D1 scheme
1023     if (ad1 && id)
1024     {
1025         s = search_function(ad1, id);
1026     }
1027 #endif
1028
1029     Objects *targsi = NULL;
1030 #if DMDV2
1031     if (!s)
1032     {   /* Try the new D2 scheme, opOpAssign
1033          */
1034         if (ad1)
1035             s = search_function(ad1, Id::opOpAssign);
1036
1037         // Set targsi, the template argument list, which will be the operator string
1038         if (s)
1039         {
1040             id = Id::opOpAssign;
1041             targsi = opToArg(sc, op);
1042         }
1043     }
1044 #endif
1045
1046     if (s)
1047     {
1048         /* Try:
1049          *      a.opOpAssign(b)
1050          */
1051
1052         args2.setDim(1);
1053         args2.data[0] = (void*) e2;
1054
1055         Match m;
1056         memset(&m, 0, sizeof(m));
1057         m.last = MATCHnomatch;
1058
1059         if (s)
1060         {
1061             FuncDeclaration *fd = s->isFuncDeclaration();
1062             if (fd)
1063             {
1064                 overloadResolveX(&m, fd, NULL, &args2);
1065             }
1066             else
1067             {   TemplateDeclaration *td = s->isTemplateDeclaration();
1068                 templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
1069             }
1070         }
1071
1072         if (m.count > 1)
1073         {
1074             // Error, ambiguous
1075             error("overloads %s and %s both match argument list for %s",
1076                     m.lastf->type->toChars(),
1077                     m.nextf->type->toChars(),
1078                     m.lastf->toChars());
1079         }
1080         else if (m.last == MATCHnomatch)
1081         {
1082             m.lastf = m.anyf;
1083             if (targsi)
1084                 goto L1;
1085         }
1086
1087         Expression *e;
1088         // Rewrite (e1 op e2) as e1.opOpAssign(e2)
1089         e = build_overload(loc, sc, e1, e2, id, targsi);
1090         return e;
1091     }
1092
1093 L1:
1094
1095 #if DMDV2
1096     // Try alias this on first operand
1097     if (ad1 && ad1->aliasthis)
1098     {
1099         /* Rewrite (e1 op e2) as:
1100          *      (e1.aliasthis op e2)
1101          */
1102         Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
1103         Expression *e = copy();
1104         ((BinExp *)e)->e1 = e1;
1105         e = e->trySemantic(sc);
1106         return e;
1107     }
1108
1109     // Try alias this on second operand
1110     AggregateDeclaration *ad2 = isAggregate(e2->type);
1111     if (ad2 && ad2->aliasthis)
1112     {
1113         /* Rewrite (e1 op e2) as:
1114          *      (e1 op e2.aliasthis)
1115          */
1116         Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
1117         Expression *e = copy();
1118         ((BinExp *)e)->e2 = e2;
1119         e = e->trySemantic(sc);
1120         return e;
1121     }
1122 #endif
1123     return NULL;
1124 }
1125
1126 /***********************************
1127  * Utility to build a function call out of this reference and argument.
1128  */
1129
1130 Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg,
1131         Identifier *id, Objects *targsi)
1132 {
1133     Expression *e;
1134
1135     //printf("build_overload(id = '%s')\n", id->toChars());
1136     //earg->print();
1137     //earg->type->print();
1138     if (targsi)
1139         e = new DotTemplateInstanceExp(loc, ethis, id, targsi);
1140     else
1141         e = new DotIdExp(loc, ethis, id);
1142
1143     if (earg)
1144         e = new CallExp(loc, e, earg);
1145     else
1146         e = new CallExp(loc, e);
1147
1148     e = e->semantic(sc);
1149     return e;
1150 }
1151
1152 /***************************************
1153  * Search for function funcid in aggregate ad.
1154  */
1155
1156 Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid)
1157 {
1158     Dsymbol *s;
1159     FuncDeclaration *fd;
1160     TemplateDeclaration *td;
1161
1162     s = ad->search(0, funcid, 0);
1163     if (s)
1164     {   Dsymbol *s2;
1165
1166         //printf("search_function: s = '%s'\n", s->kind());
1167         s2 = s->toAlias();
1168         //printf("search_function: s2 = '%s'\n", s2->kind());
1169         fd = s2->isFuncDeclaration();
1170         if (fd && fd->type->ty == Tfunction)
1171             return fd;
1172
1173         td = s2->isTemplateDeclaration();
1174         if (td)
1175             return td;
1176     }
1177     return NULL;
1178 }
1179
1180
1181 /*****************************************
1182  * Given array of arguments and an aggregate type,
1183  * if any of the argument types are missing, attempt to infer
1184  * them from the aggregate type.
1185  */
1186
1187 void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr)
1188 {
1189     if (!arguments || !arguments->dim)
1190         return;
1191
1192     /* Return if no arguments need types.
1193      */
1194     for (size_t u = 0; 1; u++)
1195     {   if (u == arguments->dim)
1196             return;
1197         Parameter *arg = (Parameter *)arguments->data[u];
1198         if (!arg->type)
1199             break;
1200     }
1201
1202     Dsymbol *s;
1203     AggregateDeclaration *ad;
1204
1205     Parameter *arg = (Parameter *)arguments->data[0];
1206     Type *taggr = aggr->type;
1207     if (!taggr)
1208         return;
1209     Type *tab = taggr->toBasetype();
1210     switch (tab->ty)
1211     {
1212         case Tarray:
1213         case Tsarray:
1214         case Ttuple:
1215             if (arguments->dim == 2)
1216             {
1217                 if (!arg->type)
1218                     arg->type = Type::tsize_t;  // key type
1219                 arg = (Parameter *)arguments->data[1];
1220             }
1221             if (!arg->type && tab->ty != Ttuple)
1222                 arg->type = tab->nextOf();      // value type
1223             break;
1224
1225         case Taarray:
1226         {   TypeAArray *taa = (TypeAArray *)tab;
1227
1228             if (arguments->dim == 2)
1229             {
1230                 if (!arg->type)
1231                     arg->type = taa->index;     // key type
1232                 arg = (Parameter *)arguments->data[1];
1233             }
1234             if (!arg->type)
1235                 arg->type = taa->next;          // value type
1236             break;
1237         }
1238
1239         case Tclass:
1240             ad = ((TypeClass *)tab)->sym;
1241             goto Laggr;
1242
1243         case Tstruct:
1244             ad = ((TypeStruct *)tab)->sym;
1245             goto Laggr;
1246
1247         Laggr:
1248             s = search_function(ad,
1249                         (op == TOKforeach_reverse) ? Id::applyReverse
1250                                                    : Id::apply);
1251             if (s)
1252                 goto Lapply;                    // prefer opApply
1253
1254             if (arguments->dim == 1)
1255             {
1256                 if (!arg->type)
1257                 {
1258                     /* Look for a head() or rear() overload
1259                      */
1260                     Identifier *id = (op == TOKforeach) ? Id::Fhead : Id::Ftoe;
1261                     Dsymbol *s = search_function(ad, id);
1262                     FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
1263                     if (!fd)
1264                     {   if (s && s->isTemplateDeclaration())
1265                             break;
1266                         goto Lapply;
1267                     }
1268                     arg->type = fd->type->nextOf();
1269                 }
1270                 break;
1271             }
1272
1273         Lapply:
1274         {   /* Look for an
1275              *  int opApply(int delegate(ref Type [, ...]) dg);
1276              * overload
1277              */
1278             if (s)
1279             {
1280                 FuncDeclaration *fd = s->isFuncDeclaration();
1281                 if (fd)
1282                 {   inferApplyArgTypesX(fd, arguments);
1283                     break;
1284                 }
1285 #if 0
1286                 TemplateDeclaration *td = s->isTemplateDeclaration();
1287                 if (td)
1288                 {   inferApplyArgTypesZ(td, arguments);
1289                     break;
1290                 }
1291 #endif
1292             }
1293             break;
1294         }
1295
1296         case Tdelegate:
1297         {
1298             if (0 && aggr->op == TOKdelegate)
1299             {   DelegateExp *de = (DelegateExp *)aggr;
1300
1301                 FuncDeclaration *fd = de->func->isFuncDeclaration();
1302                 if (fd)
1303                     inferApplyArgTypesX(fd, arguments);
1304             }
1305             else
1306             {
1307                 inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments);
1308             }
1309             break;
1310         }
1311
1312         default:
1313             break;              // ignore error, caught later
1314     }
1315 }
1316
1317 /********************************
1318  * Recursive helper function,
1319  * analogous to func.overloadResolveX().
1320  */
1321
1322 int fp3(void *param, FuncDeclaration *f)
1323 {
1324     Parameters *arguments = (Parameters *)param;
1325     TypeFunction *tf = (TypeFunction *)f->type;
1326     if (inferApplyArgTypesY(tf, arguments) == 1)
1327         return 0;
1328     if (arguments->dim == 0)
1329         return 1;
1330     return 0;
1331 }
1332
1333 static void inferApplyArgTypesX(FuncDeclaration *fstart, Parameters *arguments)
1334 {
1335     overloadApply(fstart, &fp3, arguments);
1336 }
1337
1338 /******************************
1339  * Infer arguments from type of function.
1340  * Returns:
1341  *      0 match for this function
1342  *      1 no match for this function
1343  */
1344
1345 static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments)
1346 {   size_t nparams;
1347     Parameter *p;
1348
1349     if (Parameter::dim(tf->parameters) != 1)
1350         goto Lnomatch;
1351     p = Parameter::getNth(tf->parameters, 0);
1352     if (p->type->ty != Tdelegate)
1353         goto Lnomatch;
1354     tf = (TypeFunction *)p->type->nextOf();
1355     assert(tf->ty == Tfunction);
1356
1357     /* We now have tf, the type of the delegate. Match it against
1358      * the arguments, filling in missing argument types.
1359      */
1360     nparams = Parameter::dim(tf->parameters);
1361     if (nparams == 0 || tf->varargs)
1362         goto Lnomatch;          // not enough parameters
1363     if (arguments->dim != nparams)
1364         goto Lnomatch;          // not enough parameters
1365
1366     for (size_t u = 0; u < nparams; u++)
1367     {
1368         Parameter *arg = (Parameter *)arguments->data[u];
1369         Parameter *param = Parameter::getNth(tf->parameters, u);
1370         if (arg->type)
1371         {   if (!arg->type->equals(param->type))
1372             {
1373                 /* Cannot resolve argument types. Indicate an
1374                  * error by setting the number of arguments to 0.
1375                  */
1376                 arguments->dim = 0;
1377                 goto Lmatch;
1378             }
1379             continue;
1380         }
1381         arg->type = param->type;
1382     }
1383   Lmatch:
1384     return 0;
1385
1386   Lnomatch:
1387     return 1;
1388 }
1389
1390 /*******************************************
1391  * Infer foreach arg types from a template function opApply which looks like:
1392  *    int opApply(alias int func(ref uint))() { ... }
1393  */
1394
1395 #if 0
1396 void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments)
1397 {
1398     for (TemplateDeclaration *td = tstart; td; td = td->overnext)
1399     {
1400         if (!td->scope)
1401         {
1402             error("forward reference to template %s", td->toChars());
1403             return;
1404         }
1405         if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration())
1406         {
1407             error("is not a function template");
1408             return;
1409         }
1410         if (!td->parameters || td->parameters->dim != 1)
1411             continue;
1412         TemplateParameter *tp = (TemplateParameter *)td->parameters->data[0];
1413         TemplateAliasParameter *tap = tp->isTemplateAliasParameter();
1414         if (!tap || !tap->specType || tap->specType->ty != Tfunction)
1415             continue;
1416         TypeFunction *tf = (TypeFunction *)tap->specType;
1417         if (inferApplyArgTypesY(tf, arguments) == 0)    // found it
1418             return;
1419     }
1420 }
1421 #endif
1422
1423 /**************************************
1424  */
1425
1426 static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments)
1427 {
1428     FuncDeclaration *fd;
1429
1430     assert(td);
1431     fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, arguments, 1);
1432     if (!fd)
1433         return;
1434     m->anyf = fd;
1435     if (m->last >= MATCHexact)
1436     {
1437         m->nextf = fd;
1438         m->count++;
1439     }
1440     else
1441     {
1442         m->last = MATCHexact;
1443         m->lastf = fd;
1444         m->count = 1;
1445     }
1446 }
Note: See TracBrowser for help on using the browser.