1:
2: // Compiler implementation of the D programming language
3: // Copyright (c) 1999-2010 by Digital Mars
4: // All Rights Reserved
5: // written by Walter Bright
6: // http://www.digitalmars.com
7: // License for redistribution is by either the Artistic License
8: // in artistic.txt, or the GNU General Public License in gnu.txt.
9: // See the included readme.txt for details.
10:
11: #include <stdio.h>
12: #include <stdlib.h>
13: #include <ctype.h>
14: static char __file__[] = __FILE__; /* for tassert.h */
15: #include "tassert.h"
16: #if _MSC_VER
17: #include <complex>
18: #else
19: #include <complex.h>
20: #endif
21:
22: #ifdef __APPLE__
23: #define integer_t dmd_integer_t
24: #endif
25:
26: #include "rmem.h"
27:
28: //#include "port.h"
29: #include "mtype.h"
30: #include "init.h"
31: #include "expression.h"
32: #include "id.h"
33: #include "declaration.h"
34: #include "aggregate.h"
35: #include "template.h"
36:
37: static void inferApplyArgTypesX(FuncDeclaration *fstart, Parameters *arguments);
38: static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments);
39: static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments);
40: static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments);
41:
42: /******************************** Expression **************************/
43:
44:
45: /***********************************
46: * Determine if operands of binary op can be reversed
47: * to fit operator overload.
48: */
49:
50: int Expression::isCommutative()
51: {
52: return FALSE; // default is no reverse
53: }
54:
55: /***********************************
56: * Get Identifier for operator overload.
57: */
58:
59: Identifier *Expression::opId()
60: {
61: assert(0);
62: return NULL;
63: }
64:
65: /***********************************
66: * Get Identifier for reverse operator overload,
67: * NULL if not supported for this operator.
68: */
69:
70: Identifier *Expression::opId_r()
71: {
72: return NULL;
73: }
74:
75: /************************* Operators *****************************/
76:
77: Identifier *UAddExp::opId() { return Id::uadd; }
78:
79: Identifier *NegExp::opId() { return Id::neg; }
80:
81: Identifier *ComExp::opId() { return Id::com; }
82:
83: Identifier *CastExp::opId() { return Id::cast; }
84:
85: Identifier *InExp::opId() { return Id::opIn; }
86: Identifier *InExp::opId_r() { return Id::opIn_r; }
87:
88: Identifier *PostExp::opId() { return (op == TOKplusplus)
89: ? Id::postinc
90: : Id::postdec; }
91:
92: int AddExp::isCommutative() { return TRUE; }
93: Identifier *AddExp::opId() { return Id::add; }
94: Identifier *AddExp::opId_r() { return Id::add_r; }
95:
96: Identifier *MinExp::opId() { return Id::sub; }
97: Identifier *MinExp::opId_r() { return Id::sub_r; }
98:
99: int MulExp::isCommutative() { return TRUE; }
100: Identifier *MulExp::opId() { return Id::mul; }
101: Identifier *MulExp::opId_r() { return Id::mul_r; }
102:
103: Identifier *DivExp::opId() { return Id::div; }
104: Identifier *DivExp::opId_r() { return Id::div_r; }
105:
106: Identifier *ModExp::opId() { return Id::mod; }
107: Identifier *ModExp::opId_r() { return Id::mod_r; }
108:
109: #if DMDV2
110: Identifier *PowExp::opId() { return Id::pow; }
111: Identifier *PowExp::opId_r() { return Id::pow_r; }
112: #endif
113:
114: Identifier *ShlExp::opId() { return Id::shl; }
115: Identifier *ShlExp::opId_r() { return Id::shl_r; }
116:
117: Identifier *ShrExp::opId() { return Id::shr; }
118: Identifier *ShrExp::opId_r() { return Id::shr_r; }
119:
120: Identifier *UshrExp::opId() { return Id::ushr; }
121: Identifier *UshrExp::opId_r() { return Id::ushr_r; }
122:
123: int AndExp::isCommutative() { return TRUE; }
124: Identifier *AndExp::opId() { return Id::iand; }
125: Identifier *AndExp::opId_r() { return Id::iand_r; }
126:
127: int OrExp::isCommutative() { return TRUE; }
128: Identifier *OrExp::opId() { return Id::ior; }
129: Identifier *OrExp::opId_r() { return Id::ior_r; }
130:
131: int XorExp::isCommutative() { return TRUE; }
132: Identifier *XorExp::opId() { return Id::ixor; }
133: Identifier *XorExp::opId_r() { return Id::ixor_r; }
134:
135: Identifier *CatExp::opId() { return Id::cat; }
136: Identifier *CatExp::opId_r() { return Id::cat_r; }
137:
138: Identifier * AssignExp::opId() { return Id::assign; }
139: Identifier * AddAssignExp::opId() { return Id::addass; }
140: Identifier * MinAssignExp::opId() { return Id::subass; }
141: Identifier * MulAssignExp::opId() { return Id::mulass; }
142: Identifier * DivAssignExp::opId() { return Id::divass; }
143: Identifier * ModAssignExp::opId() { return Id::modass; }
144: Identifier * AndAssignExp::opId() { return Id::andass; }
145: Identifier * OrAssignExp::opId() { return Id::orass; }
146: Identifier * XorAssignExp::opId() { return Id::xorass; }
147: Identifier * ShlAssignExp::opId() { return Id::shlass; }
148: Identifier * ShrAssignExp::opId() { return Id::shrass; }
149: Identifier *UshrAssignExp::opId() { return Id::ushrass; }
150: Identifier * CatAssignExp::opId() { return Id::catass; }
151: Identifier * PowAssignExp::opId() { return Id::powass; }
152:
153: int EqualExp::isCommutative() { return TRUE; }
154: Identifier *EqualExp::opId() { return Id::eq; }
155:
156: int CmpExp::isCommutative() { return TRUE; }
157: Identifier *CmpExp::opId() { return Id::cmp; }
158:
159: Identifier *ArrayExp::opId() { return Id::index; }
160: Identifier *PtrExp::opId() { return Id::opStar; }
161:
162: /************************************
163: * If type is a class or struct, return the symbol for it,
164: * else NULL
165: */
166: AggregateDeclaration *isAggregate(Type *t)
167: {
168: t = t->toBasetype();
169: if (t->ty == Tclass)
170: {
171: return ((TypeClass *)t)->sym;
172: }
173: else if (t->ty == Tstruct)
174: {
175: return ((TypeStruct *)t)->sym;
176: }
177: return NULL;
178: }
179:
180: /*******************************************
181: * Helper function to turn operator into template argument list
182: */
183: Objects *opToArg(Scope *sc, enum TOK op)
184: {
185: /* Remove the = from op=
186: */
187: switch (op)
188: {
189: case TOKaddass: op = TOKadd; break;
190: case TOKminass: op = TOKmin; break;
191: case TOKmulass: op = TOKmul; break;
192: case TOKdivass: op = TOKdiv; break;
193: case TOKmodass: op = TOKmod; break;
194: case TOKandass: op = TOKand; break;
195: case TOKorass: op = TOKor; break;
196: case TOKxorass: op = TOKxor; break;
197: case TOKshlass: op = TOKshl; break;
198: case TOKshrass: op = TOKshr; break;
199: case TOKushrass: op = TOKushr; break;
200: case TOKcatass: op = TOKcat; break;
201: case TOKpowass: op = TOKpow; break;
202: }
203: Expression *e = new StringExp(0, (char *)Token::toChars(op));
warning C6211: Leaking memory 'e' due to an exception. Consider using a local catch block to clean up memory: Lines: 187, 189, 203, 204, 205
204: e = e->semantic(sc);
205: Objects *targsi = new Objects();
206: targsi->push(e);
207: return targsi;
208: }
209:
210: /************************************
211: * Operator overload.
212: * Check for operator overload, if so, replace
213: * with function call.
214: * Return NULL if not an operator overload.
215: */
216:
217: Expression *UnaExp::op_overload(Scope *sc)
218: {
219: //printf("UnaExp::op_overload() (%s)\n", toChars());
220:
221: #if DMDV2
222: if (e1->op == TOKarray)
223: {
224: ArrayExp *ae = (ArrayExp *)e1;
225: ae->e1 = ae->e1->semantic(sc);
226: ae->e1 = resolveProperties(sc, ae->e1);
227:
228: AggregateDeclaration *ad = isAggregate(ae->e1->type);
229: if (ad)
230: {
231: /* Rewrite as:
232: * a.opIndexUnary!("+")(args);
233: */
234: Dsymbol *fd = search_function(ad, Id::opIndexUnary);
235: if (fd)
236: {
237: Objects *targsi = opToArg(sc, op);
238: Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi);
239: e = new CallExp(loc, e, ae->arguments);
240: e = e->semantic(sc);
241: return e;
242: }
243:
244: // Didn't find it. Forward to aliasthis
245: if (ad->aliasthis)
246: {
247: /* Rewrite op(a[arguments]) as:
248: * op(a.aliasthis[arguments])
249: */
250: Expression *e1 = ae->copy();
251: ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident);
252: Expression *e = copy();
253: ((UnaExp *)e)->e1 = e1;
254: e = e->trySemantic(sc);
255: return e;
256: }
257: }
258: }
259: else if (e1->op == TOKslice)
260: {
261: SliceExp *se = (SliceExp *)e1;
262: se->e1 = se->e1->semantic(sc);
263: se->e1 = resolveProperties(sc, se->e1);
264:
265: AggregateDeclaration *ad = isAggregate(se->e1->type);
266: if (ad)
267: {
268: /* Rewrite as:
269: * a.opSliceUnary!("+")(lwr, upr);
270: */
271: Dsymbol *fd = search_function(ad, Id::opSliceUnary);
272: if (fd)
273: {
274: Expressions *a = new Expressions();
275: if (se->lwr)
276: { a->push(se->lwr);
277: a->push(se->upr);
278: }
279:
280: Objects *targsi = opToArg(sc, op);
281: Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi);
282: e = new CallExp(loc, e, a);
283: e = e->semantic(sc);
284: return e;
285: }
286:
287: // Didn't find it. Forward to aliasthis
288: if (ad->aliasthis)
289: {
290: /* Rewrite op(a[lwr..upr]) as:
291: * op(a.aliasthis[lwr..upr])
292: */
293: Expression *e1 = se->copy();
294: ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident);
295: Expression *e = copy();
296: ((UnaExp *)e)->e1 = e1;
297: e = e->trySemantic(sc);
298: return e;
299: }
300: }
301: }
302: #endif
303:
304: e1 = e1->semantic(sc);
305: e1 = resolveProperties(sc, e1);
306:
307: AggregateDeclaration *ad = isAggregate(e1->type);
308: if (ad)
309: {
310: Dsymbol *fd = NULL;
311: #if 1 // Old way, kept for compatibility with D1
312: if (op != TOKpreplusplus && op != TOKpreminusminus)
313: { fd = search_function(ad, opId());
314: if (fd)
315: {
316: if (op == TOKarray)
317: {
318: /* Rewrite op e1[arguments] as:
319: * e1.fd(arguments)
320: */
321: Expression *e = new DotIdExp(loc, e1, fd->ident);
322: ArrayExp *ae = (ArrayExp *)this;
323: e = new CallExp(loc, e, ae->arguments);
324: e = e->semantic(sc);
325: return e;
326: }
327: else
328: {
329: // Rewrite +e1 as e1.add()
330: return build_overload(loc, sc, e1, NULL, fd);
331: }
332: }
333: }
334: #endif
335:
336: #if DMDV2
337: /* Rewrite as:
338: * e1.opUnary!("+")();
339: */
340: fd = search_function(ad, Id::opUnary);
341: if (fd)
342: {
343: Objects *targsi = opToArg(sc, op);
344: Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi);
345: e = new CallExp(loc, e);
346: e = e->semantic(sc);
347: return e;
348: }
349:
350: // Didn't find it. Forward to aliasthis
351: if (ad->aliasthis)
352: {
353: /* Rewrite op(e1) as:
354: * op(e1.aliasthis)
355: */
356: Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident);
357: Expression *e = copy();
358: ((UnaExp *)e)->e1 = e1;
359: e = e->trySemantic(sc);
360: return e;
361: }
362: #endif
363: }
364: return NULL;
365: }
366:
367: Expression *ArrayExp::op_overload(Scope *sc)
368: {
369: //printf("ArrayExp::op_overload() (%s)\n", toChars());
370: AggregateDeclaration *ad = isAggregate(e1->type);
371: if (ad)
372: {
373: Dsymbol *fd = search_function(ad, opId());
374: if (fd)
375: {
376: /* Rewrite op e1[arguments] as:
377: * e1.opIndex(arguments)
378: */
379: Expression *e = new DotIdExp(loc, e1, fd->ident);
380: e = new CallExp(loc, e, arguments);
381: e = e->semantic(sc);
382: return e;
383: }
384:
385: // Didn't find it. Forward to aliasthis
386: if (ad->aliasthis)
387: {
388: /* Rewrite op(e1) as:
389: * op(e1.aliasthis)
390: */
391: Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident);
392: Expression *e = copy();
393: ((UnaExp *)e)->e1 = e1;
394: e = e->trySemantic(sc);
395: return e;
396: }
397: }
398: return NULL;
399: }
400:
401: /***********************************************
402: * This is mostly the same as UnaryExp::op_overload(), but has
403: * a different rewrite.
404: */
405: Expression *CastExp::op_overload(Scope *sc)
406: {
407: //printf("CastExp::op_overload() (%s)\n", toChars());
408: AggregateDeclaration *ad = isAggregate(e1->type);
409: if (ad)
410: {
411: Dsymbol *fd = NULL;
412: /* Rewrite as:
413: * e1.opCast!(T)();
414: */
415: fd = search_function(ad, Id::cast);
416: if (fd)
417: {
418: #if 1 // Backwards compatibility with D1 if opCast is a function, not a template
419: if (fd->isFuncDeclaration())
420: { // Rewrite as: e1.opCast()
421: return build_overload(loc, sc, e1, NULL, fd);
422: }
423: #endif
424: Objects *targsi = new Objects();
425: targsi->push(to);
426: Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi);
427: e = new CallExp(loc, e);
428: e = e->semantic(sc);
429: return e;
430: }
431:
432: // Didn't find it. Forward to aliasthis
433: if (ad->aliasthis)
434: {
435: /* Rewrite op(e1) as:
436: * op(e1.aliasthis)
437: */
438: Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident);
439: Expression *e = copy();
440: ((UnaExp *)e)->e1 = e1;
441: e = e->trySemantic(sc);
442: return e;
443: }
444: }
445: return NULL;
446: }
447:
448: Expression *BinExp::op_overload(Scope *sc)
449: {
450: //printf("BinExp::op_overload() (%s)\n", toChars());
451:
452: Identifier *id = opId();
453: Identifier *id_r = opId_r();
454:
455: Expressions args1;
456: Expressions args2;
457: int argsset = 0;
458:
459: AggregateDeclaration *ad1 = isAggregate(e1->type);
460: AggregateDeclaration *ad2 = isAggregate(e2->type);
461:
462: Dsymbol *s = NULL;
463: Dsymbol *s_r = NULL;
464:
465: #if 1 // the old D1 scheme
466: if (ad1 && id)
467: {
468: s = search_function(ad1, id);
469: }
470: if (ad2 && id_r)
471: {
472: s_r = search_function(ad2, id_r);
473: }
474: #endif
475:
476: Objects *targsi = NULL;
477: #if DMDV2
478: if (!s && !s_r && op != TOKequal && op != TOKnotequal && op != TOKassign &&
479: op != TOKplusplus && op != TOKminusminus)
480: {
481: /* Try the new D2 scheme, opBinary and opBinaryRight
482: */
483: if (ad1)
484: s = search_function(ad1, Id::opBinary);
485: if (ad2)
486: s_r = search_function(ad2, Id::opBinaryRight);
487:
488: // Set targsi, the template argument list, which will be the operator string
489: if (s || s_r)
490: {
491: id = Id::opBinary;
492: id_r = Id::opBinaryRight;
493: targsi = opToArg(sc, op);
494: }
495: }
496: #endif
497:
498: if (s || s_r)
499: {
500: /* Try:
501: * a.opfunc(b)
502: * b.opfunc_r(a)
503: * and see which is better.
504: */
505:
506: args1.setDim(1);
507: args1.tdata()[0] = e1;
508: args2.setDim(1);
509: args2.tdata()[0] = e2;
510: argsset = 1;
511:
512: Match m;
513: memset(&m, 0, sizeof(m));
514: m.last = MATCHnomatch;
515:
516: if (s)
517: {
518: FuncDeclaration *fd = s->isFuncDeclaration();
519: if (fd)
520: {
521: overloadResolveX(&m, fd, NULL, &args2);
522: }
523: else
524: { TemplateDeclaration *td = s->isTemplateDeclaration();
525: templateResolve(&m, td, sc, loc, targsi, e1, &args2);
526: }
527: }
528:
529: FuncDeclaration *lastf = m.lastf;
530:
531: if (s_r)
532: {
533: FuncDeclaration *fd = s_r->isFuncDeclaration();
534: if (fd)
535: {
536: overloadResolveX(&m, fd, NULL, &args1);
537: }
538: else
539: { TemplateDeclaration *td = s_r->isTemplateDeclaration();
540: templateResolve(&m, td, sc, loc, targsi, e2, &args1);
541: }
542: }
543:
544: if (m.count > 1)
545: {
546: // Error, ambiguous
547: error("overloads %s and %s both match argument list for %s",
548: m.lastf->type->toChars(),
549: m.nextf->type->toChars(),
550: m.lastf->toChars());
551: }
552: else if (m.last == MATCHnomatch)
553: {
554: m.lastf = m.anyf;
555: if (targsi)
556: goto L1;
557: }
558:
559: Expression *e;
560: if (op == TOKplusplus || op == TOKminusminus)
561: // Kludge because operator overloading regards e++ and e--
562: // as unary, but it's implemented as a binary.
563: // Rewrite (e1 ++ e2) as e1.postinc()
564: // Rewrite (e1 -- e2) as e1.postdec()
565: e = build_overload(loc, sc, e1, NULL, m.lastf ? m.lastf : s);
566: else if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch)
567: // Rewrite (e1 op e2) as e1.opfunc(e2)
568: e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
569: else
570: // Rewrite (e1 op e2) as e2.opfunc_r(e1)
571: e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r);
572: return e;
573: }
574:
575: L1:
576: #if 1 // Retained for D1 compatibility
577: if (isCommutative() && !targsi)
578: {
579: s = NULL;
580: s_r = NULL;
581: if (ad1 && id_r)
582: {
583: s_r = search_function(ad1, id_r);
584: }
585: if (ad2 && id)
586: {
587: s = search_function(ad2, id);
588: }
589:
590: if (s || s_r)
591: {
592: /* Try:
593: * a.opfunc_r(b)
594: * b.opfunc(a)
595: * and see which is better.
596: */
597:
598: if (!argsset)
599: { args1.setDim(1);
600: args1.tdata()[0] = e1;
601: args2.setDim(1);
602: args2.tdata()[0] = e2;
603: }
604:
605: Match m;
606: memset(&m, 0, sizeof(m));
607: m.last = MATCHnomatch;
608:
609: if (s_r)
610: {
611: FuncDeclaration *fd = s_r->isFuncDeclaration();
612: if (fd)
613: {
614: overloadResolveX(&m, fd, NULL, &args2);
615: }
616: else
617: { TemplateDeclaration *td = s_r->isTemplateDeclaration();
618: templateResolve(&m, td, sc, loc, targsi, e1, &args2);
619: }
620: }
621: FuncDeclaration *lastf = m.lastf;
622:
623: if (s)
624: {
625: FuncDeclaration *fd = s->isFuncDeclaration();
626: if (fd)
627: {
628: overloadResolveX(&m, fd, NULL, &args1);
629: }
630: else
631: { TemplateDeclaration *td = s->isTemplateDeclaration();
632: templateResolve(&m, td, sc, loc, targsi, e2, &args1);
633: }
634: }
635:
636: if (m.count > 1)
637: {
638: // Error, ambiguous
639: error("overloads %s and %s both match argument list for %s",
640: m.lastf->type->toChars(),
641: m.nextf->type->toChars(),
642: m.lastf->toChars());
643: }
644: else if (m.last == MATCHnomatch)
645: {
646: m.lastf = m.anyf;
647: }
648:
649: Expression *e;
650: if (lastf && m.lastf == lastf || !s && m.last == MATCHnomatch)
651: // Rewrite (e1 op e2) as e1.opfunc_r(e2)
652: e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s_r);
653: else
654: // Rewrite (e1 op e2) as e2.opfunc(e1)
655: e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s);
656:
657: // When reversing operands of comparison operators,
658: // need to reverse the sense of the op
659: switch (op)
660: {
661: case TOKlt: op = TOKgt; break;
662: case TOKgt: op = TOKlt; break;
663: case TOKle: op = TOKge; break;
664: case TOKge: op = TOKle; break;
665:
666: // Floating point compares
667: case TOKule: op = TOKuge; break;
668: case TOKul: op = TOKug; break;
669: case TOKuge: op = TOKule; break;
670: case TOKug: op = TOKul; break;
671:
672: // These are symmetric
673: case TOKunord:
674: case TOKlg:
675: case TOKleg:
676: case TOKue:
677: break;
678: }
679:
680: return e;
681: }
682: }
683: #endif
684:
685: #if DMDV2
686: // Try alias this on first operand
687: if (ad1 && ad1->aliasthis &&
688: !(op == TOKassign && ad2 && ad1 == ad2)) // See Bugzilla 2943
689: {
690: /* Rewrite (e1 op e2) as:
691: * (e1.aliasthis op e2)
692: */
693: Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
694: Expression *e = copy();
695: ((BinExp *)e)->e1 = e1;
696: e = e->trySemantic(sc);
697: return e;
698: }
699:
700: // Try alias this on second operand
701: if (ad2 && ad2->aliasthis &&
702: /* Bugzilla 2943: make sure that when we're copying the struct, we don't
703: * just copy the alias this member
704: */
705: !(op == TOKassign && ad1 && ad1 == ad2))
706: {
707: /* Rewrite (e1 op e2) as:
708: * (e1 op e2.aliasthis)
709: */
710: Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
711: Expression *e = copy();
712: ((BinExp *)e)->e2 = e2;
713: e = e->trySemantic(sc);
714: return e;
715: }
716: #endif
717: return NULL;
718: }
719:
720: /******************************************
721: * Common code for overloading of EqualExp and CmpExp
722: */
723: Expression *BinExp::compare_overload(Scope *sc, Identifier *id)
724: {
725: //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), toChars());
726:
727: AggregateDeclaration *ad1 = isAggregate(e1->type);
728: AggregateDeclaration *ad2 = isAggregate(e2->type);
729:
730: Dsymbol *s = NULL;
731: Dsymbol *s_r = NULL;
732:
733: if (ad1)
734: {
735: s = search_function(ad1, id);
736: }
737: if (ad2)
738: {
739: s_r = search_function(ad2, id);
740: if (s == s_r)
741: s_r = NULL;
742: }
743:
744: Objects *targsi = NULL;
745:
746: if (s || s_r)
747: {
748: /* Try:
749: * a.opEquals(b)
750: * b.opEquals(a)
751: * and see which is better.
752: */
753:
754: Expressions args1;
755: Expressions args2;
756:
757: args1.setDim(1);
758: args1.tdata()[0] = e1;
759: args2.setDim(1);
760: args2.tdata()[0] = e2;
761:
762: Match m;
763: memset(&m, 0, sizeof(m));
764: m.last = MATCHnomatch;
765:
766: if (0 && s && s_r)
767: {
768: printf("s : %s\n", s->toPrettyChars());
769: printf("s_r: %s\n", s_r->toPrettyChars());
770: }
771:
772: if (s)
773: {
774: FuncDeclaration *fd = s->isFuncDeclaration();
775: if (fd)
776: {
777: overloadResolveX(&m, fd, NULL, &args2);
778: }
779: else
780: { TemplateDeclaration *td = s->isTemplateDeclaration();
781: templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
782: }
783: }
784:
785: FuncDeclaration *lastf = m.lastf;
786: int count = m.count;
787:
788: if (s_r)
789: {
790: FuncDeclaration *fd = s_r->isFuncDeclaration();
791: if (fd)
792: {
793: overloadResolveX(&m, fd, NULL, &args1);
794: }
795: else
796: { TemplateDeclaration *td = s_r->isTemplateDeclaration();
797: templateResolve(&m, td, sc, loc, targsi, NULL, &args1);
798: }
799: }
800:
801: if (m.count > 1)
802: {
803: /* The following if says "not ambiguous" if there's one match
804: * from s and one from s_r, in which case we pick s.
805: * This doesn't follow the spec, but is a workaround for the case
806: * where opEquals was generated from templates and we cannot figure
807: * out if both s and s_r came from the same declaration or not.
808: * The test case is:
809: * import std.typecons;
810: * void main() {
811: * assert(tuple("has a", 2u) == tuple("has a", 1));
812: * }
813: */
814: if (!(m.lastf == lastf && m.count == 2 && count == 1))
815: {
816: // Error, ambiguous
817: error("overloads %s and %s both match argument list for %s",
818: m.lastf->type->toChars(),
819: m.nextf->type->toChars(),
820: m.lastf->toChars());
821: }
822: }
823: else if (m.last == MATCHnomatch)
824: {
825: m.lastf = m.anyf;
826: }
827:
828: Expression *e;
829: if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch)
830: // Rewrite (e1 op e2) as e1.opfunc(e2)
831: e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
832: else
833: { // Rewrite (e1 op e2) as e2.opfunc_r(e1)
834: e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r);
835:
836: // When reversing operands of comparison operators,
837: // need to reverse the sense of the op
838: switch (op)
839: {
840: case TOKlt: op = TOKgt; break;
841: case TOKgt: op = TOKlt; break;
842: case TOKle: op = TOKge; break;
843: case TOKge: op = TOKle; break;
844:
845: // Floating point compares
846: case TOKule: op = TOKuge; break;
847: case TOKul: op = TOKug; break;
848: case TOKuge: op = TOKule; break;
849: case TOKug: op = TOKul; break;
850:
851: // The rest are symmetric
852: default:
853: break;
854: }
855: }
856:
857: return e;
858: }
859:
860: // Try alias this on first operand
861: if (ad1 && ad1->aliasthis)
862: {
863: /* Rewrite (e1 op e2) as:
864: * (e1.aliasthis op e2)
865: */
866: Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
867: Expression *e = copy();
868: ((BinExp *)e)->e1 = e1;
869: e = e->trySemantic(sc);
870: return e;
871: }
872:
873: // Try alias this on second operand
874: if (ad2 && ad2->aliasthis)
875: {
876: /* Rewrite (e1 op e2) as:
877: * (e1 op e2.aliasthis)
878: */
879: Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
880: Expression *e = copy();
881: ((BinExp *)e)->e2 = e2;
882: e = e->trySemantic(sc);
883: return e;
884: }
885:
886: return NULL;
887: }
888:
889: Expression *EqualExp::op_overload(Scope *sc)
890: {
891: //printf("EqualExp::op_overload() (%s)\n", toChars());
892:
893: Type *t1 = e1->type->toBasetype();
894: Type *t2 = e2->type->toBasetype();
895: if (t1->ty == Tclass && t2->ty == Tclass)
896: {
897: /* Rewrite as:
898: * .object.opEquals(e1, e2)
899: */
900: Expression *e = new IdentifierExp(loc, Id::empty);
901: e = new DotIdExp(loc, e, Id::object);
902: e = new DotIdExp(loc, e, Id::eq);
903: e = new CallExp(loc, e, e1, e2);
904: e = e->semantic(sc);
905: return e;
906: }
907:
908: return compare_overload(sc, Id::eq);
909: }
910:
911: Expression *CmpExp::op_overload(Scope *sc)
912: {
913: //printf("CmpExp::op_overload() (%s)\n", toChars());
914:
915: return compare_overload(sc, Id::cmp);
916: }
917:
918: /*********************************
919: * Operator overloading for op=
920: */
921: Expression *BinAssignExp::op_overload(Scope *sc)
922: {
923: //printf("BinAssignExp::op_overload() (%s)\n", toChars());
924:
925: #if DMDV2
926: if (e1->op == TOKarray)
927: {
928: ArrayExp *ae = (ArrayExp *)e1;
929: ae->e1 = ae->e1->semantic(sc);
930: ae->e1 = resolveProperties(sc, ae->e1);
931:
932: AggregateDeclaration *ad = isAggregate(ae->e1->type);
933: if (ad)
934: {
935: /* Rewrite a[args]+=e2 as:
936: * a.opIndexOpAssign!("+")(e2, args);
937: */
938: Dsymbol *fd = search_function(ad, Id::opIndexOpAssign);
939: if (fd)
940: {
941: Expressions *a = new Expressions();
warning C6211: Leaking memory 'a' due to an exception. Consider using a local catch block to clean up memory: Lines: 926, 928, 929, 930, 932, 933, 938, 939, 941, 942, 943, 946, 947
942: a->push(e2);
943: for (int i = 0; i < ae->arguments->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
944: a->push(ae->arguments->tdata()[i]);
945:
946: Objects *targsi = opToArg(sc, op);
947: Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi);
948: e = new CallExp(loc, e, a);
949: e = e->semantic(sc);
950: return e;
951: }
952:
953: // Didn't find it. Forward to aliasthis
954: if (ad->aliasthis)
955: {
956: /* Rewrite a[arguments] op= e2 as:
957: * a.aliasthis[arguments] op= e2
958: */
959: Expression *e1 = ae->copy();
960: ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident);
961: Expression *e = copy();
962: ((UnaExp *)e)->e1 = e1;
963: e = e->trySemantic(sc);
964: return e;
965: }
966: }
967: }
968: else if (e1->op == TOKslice)
969: {
970: SliceExp *se = (SliceExp *)e1;
971: se->e1 = se->e1->semantic(sc);
972: se->e1 = resolveProperties(sc, se->e1);
973:
974: AggregateDeclaration *ad = isAggregate(se->e1->type);
975: if (ad)
976: {
977: /* Rewrite a[lwr..upr]+=e2 as:
978: * a.opSliceOpAssign!("+")(e2, lwr, upr);
979: */
980: Dsymbol *fd = search_function(ad, Id::opSliceOpAssign);
981: if (fd)
982: {
983: Expressions *a = new Expressions();
984: a->push(e2);
985: if (se->lwr)
986: { a->push(se->lwr);
987: a->push(se->upr);
988: }
989:
990: Objects *targsi = opToArg(sc, op);
991: Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi);
992: e = new CallExp(loc, e, a);
993: e = e->semantic(sc);
994: return e;
995: }
996:
997: // Didn't find it. Forward to aliasthis
998: if (ad->aliasthis)
999: {
1000: /* Rewrite a[lwr..upr] op= e2 as:
1001: * a.aliasthis[lwr..upr] op= e2
1002: */
1003: Expression *e1 = se->copy();
1004: ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident);
1005: Expression *e = copy();
1006: ((UnaExp *)e)->e1 = e1;
1007: e = e->trySemantic(sc);
1008: return e;
1009: }
1010: }
1011: }
1012: #endif
1013:
1014: BinExp::semantic(sc);
1015: e1 = resolveProperties(sc, e1);
1016: e2 = resolveProperties(sc, e2);
1017:
1018: Identifier *id = opId();
1019:
1020: Expressions args2;
1021:
1022: AggregateDeclaration *ad1 = isAggregate(e1->type);
1023:
1024: Dsymbol *s = NULL;
1025:
1026: #if 1 // the old D1 scheme
1027: if (ad1 && id)
1028: {
1029: s = search_function(ad1, id);
1030: }
1031: #endif
1032:
1033: Objects *targsi = NULL;
1034: #if DMDV2
1035: if (!s)
1036: { /* Try the new D2 scheme, opOpAssign
1037: */
1038: if (ad1)
1039: s = search_function(ad1, Id::opOpAssign);
1040:
1041: // Set targsi, the template argument list, which will be the operator string
1042: if (s)
1043: {
1044: id = Id::opOpAssign;
1045: targsi = opToArg(sc, op);
1046: }
1047: }
1048: #endif
1049:
1050: if (s)
1051: {
1052: /* Try:
1053: * a.opOpAssign(b)
1054: */
1055:
1056: args2.setDim(1);
1057: args2.tdata()[0] = e2;
1058:
1059: Match m;
1060: memset(&m, 0, sizeof(m));
1061: m.last = MATCHnomatch;
1062:
1063: if (s)
1064: {
1065: FuncDeclaration *fd = s->isFuncDeclaration();
1066: if (fd)
1067: {
1068: overloadResolveX(&m, fd, NULL, &args2);
1069: }
1070: else
1071: { TemplateDeclaration *td = s->isTemplateDeclaration();
1072: templateResolve(&m, td, sc, loc, targsi, e1, &args2);
1073: }
1074: }
1075:
1076: if (m.count > 1)
1077: {
1078: // Error, ambiguous
1079: error("overloads %s and %s both match argument list for %s",
1080: m.lastf->type->toChars(),
1081: m.nextf->type->toChars(),
1082: m.lastf->toChars());
1083: }
1084: else if (m.last == MATCHnomatch)
1085: {
1086: m.lastf = m.anyf;
1087: if (targsi)
1088: goto L1;
1089: }
1090:
1091: // Rewrite (e1 op e2) as e1.opOpAssign(e2)
1092: return build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
1093: }
1094:
1095: L1:
1096:
1097: #if DMDV2
1098: // Try alias this on first operand
1099: if (ad1 && ad1->aliasthis)
1100: {
1101: /* Rewrite (e1 op e2) as:
1102: * (e1.aliasthis op e2)
1103: */
1104: Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
1105: Expression *e = copy();
1106: ((BinExp *)e)->e1 = e1;
1107: e = e->trySemantic(sc);
1108: return e;
1109: }
1110:
1111: // Try alias this on second operand
1112: AggregateDeclaration *ad2 = isAggregate(e2->type);
1113: if (ad2 && ad2->aliasthis)
1114: {
1115: /* Rewrite (e1 op e2) as:
1116: * (e1 op e2.aliasthis)
1117: */
1118: Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
1119: Expression *e = copy();
1120: ((BinExp *)e)->e2 = e2;
1121: e = e->trySemantic(sc);
1122: return e;
1123: }
1124: #endif
1125: return NULL;
1126: }
1127:
1128: /***********************************
1129: * Utility to build a function call out of this reference and argument.
1130: */
1131:
1132: Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg,
1133: Dsymbol *d)
1134: {
1135: assert(d);
1136: Expression *e;
1137:
1138: //printf("build_overload(id = '%s')\n", id->toChars());
1139: //earg->print();
1140: //earg->type->print();
1141: Declaration *decl = d->isDeclaration();
1142: if (decl)
1143: e = new DotVarExp(loc, ethis, decl, 0);
1144: else
1145: e = new DotIdExp(loc, ethis, d->ident);
1146: e = new CallExp(loc, e, earg);
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 = arguments->tdata()[u];
1198: if (!arg->type)
1199: break;
1200: }
1201:
1202: Dsymbol *s;
1203: AggregateDeclaration *ad;
1204:
1205: Parameter *arg = arguments->tdata()[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 = arguments->tdata()[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 = arguments->tdata()[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);
warning C6246: Local declaration of 's' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1202' of 'c:\projects\extern\d\dmd\src\opover.c': Lines: 1202
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 = arguments->tdata()[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 = td->parameters->tdata()[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: }
1447:
1448: