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