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