1 /** 2 * Semantic analysis for cast-expressions. 3 * 4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d) 8 * Documentation: https://dlang.org/phobos/dmd_dcast.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dcast.d 10 */ 11 12 module dmd.dcast; 13 14 import core.stdc.stdio; 15 import core.stdc.string; 16 import dmd.aggregate; 17 import dmd.aliasthis; 18 import dmd.arrayop; 19 import dmd.arraytypes; 20 import dmd.dclass; 21 import dmd.declaration; 22 import dmd.dscope; 23 import dmd.dstruct; 24 import dmd.dsymbol; 25 import dmd.errors; 26 import dmd.escape; 27 import dmd.expression; 28 import dmd.expressionsem; 29 import dmd.func; 30 import dmd.globals; 31 import dmd.impcnvtab; 32 import dmd.id; 33 import dmd.init; 34 import dmd.intrange; 35 import dmd.mtype; 36 import dmd.opover; 37 import dmd.root.ctfloat; 38 import dmd.root.outbuffer; 39 import dmd.root.rmem; 40 import dmd.tokens; 41 import dmd.typesem; 42 import dmd.utf; 43 import dmd.visitor; 44 45 enum LOG = false; 46 47 /************************************** 48 * Do an implicit cast. 49 * Issue error if it can't be done. 50 */ 51 Expression implicitCastTo(Expression e, Scope* sc, Type t) 52 { 53 extern (C++) final class ImplicitCastTo : Visitor 54 { 55 alias visit = Visitor.visit; 56 public: 57 Type t; 58 Scope* sc; 59 Expression result; 60 61 extern (D) this(Scope* sc, Type t) 62 { 63 this.sc = sc; 64 this.t = t; 65 } 66 67 override void visit(Expression e) 68 { 69 //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); 70 71 if (const match = e.implicitConvTo(t)) 72 { 73 if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t))) 74 { 75 /* Do not emit CastExp for const conversions and 76 * unique conversions on rvalue. 77 */ 78 result = e.copy(); 79 result.type = t; 80 return; 81 } 82 83 auto ad = isAggregate(e.type); 84 if (ad && ad.aliasthis) 85 { 86 auto ts = ad.type.isTypeStruct(); 87 const adMatch = ts 88 ? ts.implicitConvToWithoutAliasThis(t) 89 : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t); 90 91 if (!adMatch) 92 { 93 Type tob = t.toBasetype(); 94 Type t1b = e.type.toBasetype(); 95 if (ad != isAggregate(tob)) 96 { 97 if (t1b.ty == Tclass && tob.ty == Tclass) 98 { 99 ClassDeclaration t1cd = t1b.isClassHandle(); 100 ClassDeclaration tocd = tob.isClassHandle(); 101 int offset; 102 if (tocd.isBaseOf(t1cd, &offset)) 103 { 104 result = new CastExp(e.loc, e, t); 105 result.type = t; 106 return; 107 } 108 } 109 110 /* Forward the cast to our alias this member, rewrite to: 111 * cast(to)e1.aliasthis 112 */ 113 result = resolveAliasThis(sc, e); 114 result = result.castTo(sc, t); 115 return; 116 } 117 } 118 } 119 120 result = e.castTo(sc, t); 121 return; 122 } 123 124 result = e.optimize(WANTvalue); 125 if (result != e) 126 { 127 result.accept(this); 128 return; 129 } 130 131 if (t.ty != Terror && e.type.ty != Terror) 132 { 133 if (!t.deco) 134 { 135 e.error("forward reference to type `%s`", t.toChars()); 136 } 137 else 138 { 139 //printf("type %p ty %d deco %p\n", type, type.ty, type.deco); 140 //type = type.typeSemantic(loc, sc); 141 //printf("type %s t %s\n", type.deco, t.deco); 142 auto ts = toAutoQualChars(e.type, t); 143 e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", 144 e.toChars(), ts[0], ts[1]); 145 } 146 } 147 result = new ErrorExp(); 148 } 149 150 override void visit(StringExp e) 151 { 152 //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); 153 visit(cast(Expression)e); 154 if (auto se = result.isStringExp()) 155 { 156 // Retain polysemous nature if it started out that way 157 se.committed = e.committed; 158 } 159 } 160 161 override void visit(ErrorExp e) 162 { 163 result = e; 164 } 165 166 override void visit(FuncExp e) 167 { 168 //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); 169 FuncExp fe; 170 if (e.matchType(t, sc, &fe) > MATCH.nomatch) 171 { 172 result = fe; 173 return; 174 } 175 visit(cast(Expression)e); 176 } 177 178 override void visit(ArrayLiteralExp e) 179 { 180 visit(cast(Expression)e); 181 182 Type tb = result.type.toBasetype(); 183 if (auto ta = tb.isTypeDArray()) 184 if (global.params.useTypeInfo && Type.dtypeinfo) 185 semanticTypeInfo(sc, ta.next); 186 } 187 188 override void visit(SliceExp e) 189 { 190 visit(cast(Expression)e); 191 192 if (auto se = result.isSliceExp()) 193 if (auto ale = se.e1.isArrayLiteralExp()) 194 { 195 Type tb = t.toBasetype(); 196 Type tx = (tb.ty == Tsarray) 197 ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0) 198 : tb.nextOf().arrayOf(); 199 se.e1 = ale.implicitCastTo(sc, tx); 200 } 201 } 202 } 203 204 scope ImplicitCastTo v = new ImplicitCastTo(sc, t); 205 e.accept(v); 206 return v.result; 207 } 208 209 /******************************************* 210 * Return MATCH level of implicitly converting e to type t. 211 * Don't do the actual cast; don't change e. 212 */ 213 MATCH implicitConvTo(Expression e, Type t) 214 { 215 extern (C++) final class ImplicitConvTo : Visitor 216 { 217 alias visit = Visitor.visit; 218 public: 219 Type t; 220 MATCH result; 221 222 extern (D) this(Type t) 223 { 224 this.t = t; 225 result = MATCH.nomatch; 226 } 227 228 override void visit(Expression e) 229 { 230 version (none) 231 { 232 printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 233 } 234 //static int nest; if (++nest == 10) assert(0); 235 if (t == Type.terror) 236 return; 237 if (!e.type) 238 { 239 e.error("`%s` is not an expression", e.toChars()); 240 e.type = Type.terror; 241 } 242 243 Expression ex = e.optimize(WANTvalue); 244 if (ex.type.equals(t)) 245 { 246 result = MATCH.exact; 247 return; 248 } 249 if (ex != e) 250 { 251 //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars()); 252 result = ex.implicitConvTo(t); 253 return; 254 } 255 256 MATCH match = e.type.implicitConvTo(t); 257 if (match != MATCH.nomatch) 258 { 259 result = match; 260 return; 261 } 262 263 /* See if we can do integral narrowing conversions 264 */ 265 if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic()) 266 { 267 IntRange src = getIntRange(e); 268 IntRange target = IntRange.fromType(t); 269 if (target.contains(src)) 270 { 271 result = MATCH.convert; 272 return; 273 } 274 } 275 } 276 277 /****** 278 * Given expression e of type t, see if we can implicitly convert e 279 * to type tprime, where tprime is type t with mod bits added. 280 * Returns: 281 * match level 282 */ 283 static MATCH implicitMod(Expression e, Type t, MOD mod) 284 { 285 Type tprime; 286 if (t.ty == Tpointer) 287 tprime = t.nextOf().castMod(mod).pointerTo(); 288 else if (t.ty == Tarray) 289 tprime = t.nextOf().castMod(mod).arrayOf(); 290 else if (t.ty == Tsarray) 291 tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size()); 292 else 293 tprime = t.castMod(mod); 294 295 return e.implicitConvTo(tprime); 296 } 297 298 static MATCH implicitConvToAddMin(BinExp e, Type t) 299 { 300 /* Is this (ptr +- offset)? If so, then ask ptr 301 * if the conversion can be done. 302 * This is to support doing things like implicitly converting a mutable unique 303 * pointer to an immutable pointer. 304 */ 305 306 Type tb = t.toBasetype(); 307 Type typeb = e.type.toBasetype(); 308 309 if (typeb.ty != Tpointer || tb.ty != Tpointer) 310 return MATCH.nomatch; 311 312 Type t1b = e.e1.type.toBasetype(); 313 Type t2b = e.e2.type.toBasetype(); 314 if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb)) 315 { 316 // ptr + offset 317 // ptr - offset 318 MATCH m = e.e1.implicitConvTo(t); 319 return (m > MATCH.constant) ? MATCH.constant : m; 320 } 321 if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb)) 322 { 323 // offset + ptr 324 MATCH m = e.e2.implicitConvTo(t); 325 return (m > MATCH.constant) ? MATCH.constant : m; 326 } 327 328 return MATCH.nomatch; 329 } 330 331 override void visit(AddExp e) 332 { 333 version (none) 334 { 335 printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 336 } 337 visit(cast(Expression)e); 338 if (result == MATCH.nomatch) 339 result = implicitConvToAddMin(e, t); 340 } 341 342 override void visit(MinExp e) 343 { 344 version (none) 345 { 346 printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 347 } 348 visit(cast(Expression)e); 349 if (result == MATCH.nomatch) 350 result = implicitConvToAddMin(e, t); 351 } 352 353 override void visit(IntegerExp e) 354 { 355 version (none) 356 { 357 printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 358 } 359 MATCH m = e.type.implicitConvTo(t); 360 if (m >= MATCH.constant) 361 { 362 result = m; 363 return; 364 } 365 366 TY ty = e.type.toBasetype().ty; 367 TY toty = t.toBasetype().ty; 368 TY oldty = ty; 369 370 if (m == MATCH.nomatch && t.ty == Tenum) 371 return; 372 373 if (auto tv = t.isTypeVector()) 374 { 375 TypeBasic tb = tv.elementType(); 376 if (tb.ty == Tvoid) 377 return; 378 toty = tb.ty; 379 } 380 381 switch (ty) 382 { 383 case Tbool: 384 case Tint8: 385 case Tchar: 386 case Tuns8: 387 case Tint16: 388 case Tuns16: 389 case Twchar: 390 ty = Tint32; 391 break; 392 393 case Tdchar: 394 ty = Tuns32; 395 break; 396 397 default: 398 break; 399 } 400 401 // Only allow conversion if no change in value 402 immutable dinteger_t value = e.toInteger(); 403 404 bool isLosslesslyConvertibleToFP(T)() 405 { 406 if (e.type.isunsigned()) 407 { 408 const f = cast(T) value; 409 return cast(dinteger_t) f == value; 410 } 411 412 const f = cast(T) cast(sinteger_t) value; 413 return cast(sinteger_t) f == cast(sinteger_t) value; 414 } 415 416 switch (toty) 417 { 418 case Tbool: 419 if ((value & 1) != value) 420 return; 421 break; 422 423 case Tint8: 424 if (ty == Tuns64 && value & ~0x7FU) 425 return; 426 else if (cast(byte)value != value) 427 return; 428 break; 429 430 case Tchar: 431 if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) 432 return; 433 goto case Tuns8; 434 case Tuns8: 435 //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); 436 if (cast(ubyte)value != value) 437 return; 438 break; 439 440 case Tint16: 441 if (ty == Tuns64 && value & ~0x7FFFU) 442 return; 443 else if (cast(short)value != value) 444 return; 445 break; 446 447 case Twchar: 448 if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) 449 return; 450 goto case Tuns16; 451 case Tuns16: 452 if (cast(ushort)value != value) 453 return; 454 break; 455 456 case Tint32: 457 if (ty == Tuns32) 458 { 459 } 460 else if (ty == Tuns64 && value & ~0x7FFFFFFFU) 461 return; 462 else if (cast(int)value != value) 463 return; 464 break; 465 466 case Tuns32: 467 if (ty == Tint32) 468 { 469 } 470 else if (cast(uint)value != value) 471 return; 472 break; 473 474 case Tdchar: 475 if (value > 0x10FFFFU) 476 return; 477 break; 478 479 case Tfloat32: 480 if (!isLosslesslyConvertibleToFP!float) 481 return; 482 break; 483 484 case Tfloat64: 485 if (!isLosslesslyConvertibleToFP!double) 486 return; 487 break; 488 489 case Tfloat80: 490 if (!isLosslesslyConvertibleToFP!real_t) 491 return; 492 break; 493 494 case Tpointer: 495 //printf("type = %s\n", type.toBasetype()->toChars()); 496 //printf("t = %s\n", t.toBasetype()->toChars()); 497 if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty) 498 { 499 /* Allow things like: 500 * const char* P = cast(char *)3; 501 * char* q = P; 502 */ 503 break; 504 } 505 goto default; 506 507 default: 508 visit(cast(Expression)e); 509 return; 510 } 511 512 //printf("MATCH.convert\n"); 513 result = MATCH.convert; 514 } 515 516 override void visit(ErrorExp e) 517 { 518 // no match 519 } 520 521 override void visit(NullExp e) 522 { 523 version (none) 524 { 525 printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", e.toChars(), e.type.toChars(), t.toChars(), e.committed); 526 } 527 if (e.type.equals(t)) 528 { 529 result = MATCH.exact; 530 return; 531 } 532 533 /* Allow implicit conversions from immutable to mutable|const, 534 * and mutable to immutable. It works because, after all, a null 535 * doesn't actually point to anything. 536 */ 537 if (t.equivalent(e.type)) 538 { 539 result = MATCH.constant; 540 return; 541 } 542 543 visit(cast(Expression)e); 544 } 545 546 override void visit(StructLiteralExp e) 547 { 548 version (none) 549 { 550 printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 551 } 552 visit(cast(Expression)e); 553 if (result != MATCH.nomatch) 554 return; 555 if (e.type.ty == t.ty && e.type.ty == Tstruct && (cast(TypeStruct)e.type).sym == (cast(TypeStruct)t).sym) 556 { 557 result = MATCH.constant; 558 foreach (i, el; (*e.elements)[]) 559 { 560 if (!el) 561 continue; 562 Type te = e.sd.fields[i].type.addMod(t.mod); 563 MATCH m2 = el.implicitConvTo(te); 564 //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2); 565 if (m2 < result) 566 result = m2; 567 } 568 } 569 } 570 571 override void visit(StringExp e) 572 { 573 version (none) 574 { 575 printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars()); 576 } 577 if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) 578 return; 579 580 if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer)) 581 return visit(cast(Expression)e); 582 583 TY tyn = e.type.nextOf().ty; 584 585 if (!tyn.isSomeChar) 586 return visit(cast(Expression)e); 587 588 switch (t.ty) 589 { 590 case Tsarray: 591 if (e.type.ty == Tsarray) 592 { 593 TY tynto = t.nextOf().ty; 594 if (tynto == tyn) 595 { 596 if ((cast(TypeSArray)e.type).dim.toInteger() == (cast(TypeSArray)t).dim.toInteger()) 597 { 598 result = MATCH.exact; 599 } 600 return; 601 } 602 if (tynto.isSomeChar) 603 { 604 if (e.committed && tynto != tyn) 605 return; 606 size_t fromlen = e.numberOfCodeUnits(tynto); 607 size_t tolen = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); 608 if (tolen < fromlen) 609 return; 610 if (tolen != fromlen) 611 { 612 // implicit length extending 613 result = MATCH.convert; 614 return; 615 } 616 } 617 if (!e.committed && tynto.isSomeChar) 618 { 619 result = MATCH.exact; 620 return; 621 } 622 } 623 else if (e.type.ty == Tarray) 624 { 625 TY tynto = t.nextOf().ty; 626 if (tynto.isSomeChar) 627 { 628 if (e.committed && tynto != tyn) 629 return; 630 size_t fromlen = e.numberOfCodeUnits(tynto); 631 size_t tolen = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); 632 if (tolen < fromlen) 633 return; 634 if (tolen != fromlen) 635 { 636 // implicit length extending 637 result = MATCH.convert; 638 return; 639 } 640 } 641 if (tynto == tyn) 642 { 643 result = MATCH.exact; 644 return; 645 } 646 if (!e.committed && tynto.isSomeChar) 647 { 648 result = MATCH.exact; 649 return; 650 } 651 } 652 goto case; /+ fall through +/ 653 case Tarray: 654 case Tpointer: 655 Type tn = t.nextOf(); 656 MATCH m = MATCH.exact; 657 if (e.type.nextOf().mod != tn.mod) 658 { 659 // https://issues.dlang.org/show_bug.cgi?id=16183 660 if (!tn.isConst() && !tn.isImmutable()) 661 return; 662 m = MATCH.constant; 663 } 664 if (!e.committed) 665 { 666 switch (tn.ty) 667 { 668 case Tchar: 669 if (e.postfix == 'w' || e.postfix == 'd') 670 m = MATCH.convert; 671 result = m; 672 return; 673 case Twchar: 674 if (e.postfix != 'w') 675 m = MATCH.convert; 676 result = m; 677 return; 678 case Tdchar: 679 if (e.postfix != 'd') 680 m = MATCH.convert; 681 result = m; 682 return; 683 case Tenum: 684 if ((cast(TypeEnum)tn).sym.isSpecial()) 685 { 686 /* Allow string literal -> const(wchar_t)[] 687 */ 688 if (TypeBasic tob = tn.toBasetype().isTypeBasic()) 689 result = tn.implicitConvTo(tob); 690 return; 691 } 692 break; 693 default: 694 break; 695 } 696 } 697 break; 698 699 default: 700 break; 701 } 702 703 visit(cast(Expression)e); 704 } 705 706 override void visit(ArrayLiteralExp e) 707 { 708 version (none) 709 { 710 printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 711 } 712 Type tb = t.toBasetype(); 713 Type typeb = e.type.toBasetype(); 714 715 if ((tb.ty == Tarray || tb.ty == Tsarray) && 716 (typeb.ty == Tarray || typeb.ty == Tsarray)) 717 { 718 result = MATCH.exact; 719 Type typen = typeb.nextOf().toBasetype(); 720 721 if (auto tsa = tb.isTypeSArray()) 722 { 723 if (e.elements.dim != tsa.dim.toInteger()) 724 result = MATCH.nomatch; 725 } 726 727 Type telement = tb.nextOf(); 728 if (!e.elements.dim) 729 { 730 if (typen.ty != Tvoid) 731 result = typen.implicitConvTo(telement); 732 } 733 else 734 { 735 if (e.basis) 736 { 737 MATCH m = e.basis.implicitConvTo(telement); 738 if (m < result) 739 result = m; 740 } 741 for (size_t i = 0; i < e.elements.dim; i++) 742 { 743 Expression el = (*e.elements)[i]; 744 if (result == MATCH.nomatch) 745 break; 746 if (!el) 747 continue; 748 MATCH m = el.implicitConvTo(telement); 749 if (m < result) 750 result = m; // remember worst match 751 } 752 } 753 754 if (!result) 755 result = e.type.implicitConvTo(t); 756 757 return; 758 } 759 else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) 760 { 761 result = MATCH.exact; 762 // Convert array literal to vector type 763 TypeVector tv = tb.isTypeVector(); 764 TypeSArray tbase = tv.basetype.isTypeSArray(); 765 assert(tbase); 766 const edim = e.elements.dim; 767 const tbasedim = tbase.dim.toInteger(); 768 if (edim > tbasedim) 769 { 770 result = MATCH.nomatch; 771 return; 772 } 773 774 Type telement = tv.elementType(); 775 if (edim < tbasedim) 776 { 777 Expression el = typeb.nextOf.defaultInitLiteral(e.loc); 778 MATCH m = el.implicitConvTo(telement); 779 if (m < result) 780 result = m; // remember worst match 781 } 782 foreach (el; (*e.elements)[]) 783 { 784 MATCH m = el.implicitConvTo(telement); 785 if (m < result) 786 result = m; // remember worst match 787 if (result == MATCH.nomatch) 788 break; // no need to check for worse 789 } 790 return; 791 } 792 793 visit(cast(Expression)e); 794 } 795 796 override void visit(AssocArrayLiteralExp e) 797 { 798 auto taa = t.toBasetype().isTypeAArray(); 799 Type typeb = e.type.toBasetype(); 800 801 if (!(taa && typeb.ty == Taarray)) 802 return visit(cast(Expression)e); 803 804 result = MATCH.exact; 805 foreach (i, el; (*e.keys)[]) 806 { 807 MATCH m = el.implicitConvTo(taa.index); 808 if (m < result) 809 result = m; // remember worst match 810 if (result == MATCH.nomatch) 811 break; // no need to check for worse 812 el = (*e.values)[i]; 813 m = el.implicitConvTo(taa.nextOf()); 814 if (m < result) 815 result = m; // remember worst match 816 if (result == MATCH.nomatch) 817 break; // no need to check for worse 818 } 819 } 820 821 override void visit(CallExp e) 822 { 823 enum LOG = false; 824 static if (LOG) 825 { 826 printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 827 } 828 829 visit(cast(Expression)e); 830 if (result != MATCH.nomatch) 831 return; 832 833 /* Allow the result of strongly pure functions to 834 * convert to immutable 835 */ 836 if (e.f && e.f.isReturnIsolated() && 837 (!global.params.vsafe || // lots of legacy code breaks with the following purity check 838 e.f.isPure() >= PURE.strong || 839 // Special case exemption for Object.dup() which we assume is implemented correctly 840 e.f.ident == Id.dup && 841 e.f.toParent2() == ClassDeclaration.object.toParent()) 842 ) 843 { 844 result = e.type.immutableOf().implicitConvTo(t); 845 if (result > MATCH.constant) // Match level is MATCH.constant at best. 846 result = MATCH.constant; 847 return; 848 } 849 850 /* Conversion is 'const' conversion if: 851 * 1. function is pure (weakly pure is ok) 852 * 2. implicit conversion only fails because of mod bits 853 * 3. each function parameter can be implicitly converted to the mod bits 854 */ 855 auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction(); 856 if (!tf) 857 return; 858 859 if (tf.purity == PURE.impure) 860 return; 861 if (e.f && e.f.isNested()) 862 return; 863 864 /* See if fail only because of mod bits. 865 * 866 * https://issues.dlang.org/show_bug.cgi?id=14155 867 * All pure functions can access global immutable data. 868 * So the returned pointer may refer an immutable global data, 869 * and then the returned pointer that points non-mutable object 870 * cannot be unique pointer. 871 * 872 * Example: 873 * immutable g; 874 * static this() { g = 1; } 875 * const(int*) foo() pure { return &g; } 876 * void test() { 877 * immutable(int*) ip = foo(); // OK 878 * int* mp = foo(); // should be disallowed 879 * } 880 */ 881 if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) 882 { 883 return; 884 } 885 // Allow a conversion to immutable type, or 886 // conversions of mutable types between thread-local and shared. 887 888 /* Get mod bits of what we're converting to 889 */ 890 Type tb = t.toBasetype(); 891 MOD mod = tb.mod; 892 if (tf.isref) 893 { 894 } 895 else 896 { 897 if (Type ti = getIndirection(t)) 898 mod = ti.mod; 899 } 900 static if (LOG) 901 { 902 printf("mod = x%x\n", mod); 903 } 904 if (mod & MODFlags.wild) 905 return; // not sure what to do with this 906 907 /* Apply mod bits to each function parameter, 908 * and see if we can convert the function argument to the modded type 909 */ 910 911 size_t nparams = tf.parameterList.length; 912 size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended 913 if (auto dve = e.e1.isDotVarExp()) 914 { 915 /* Treat 'this' as just another function argument 916 */ 917 Type targ = dve.e1.type; 918 if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) 919 return; 920 } 921 foreach (const i; j .. e.arguments.dim) 922 { 923 Expression earg = (*e.arguments)[i]; 924 Type targ = earg.type.toBasetype(); 925 static if (LOG) 926 { 927 printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); 928 } 929 if (i - j < nparams) 930 { 931 Parameter fparam = tf.parameterList[i - j]; 932 if (fparam.storageClass & STC.lazy_) 933 return; // not sure what to do with this 934 Type tparam = fparam.type; 935 if (!tparam) 936 continue; 937 if (fparam.storageClass & (STC.out_ | STC.ref_)) 938 { 939 if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) 940 return; 941 continue; 942 } 943 } 944 static if (LOG) 945 { 946 printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); 947 } 948 if (implicitMod(earg, targ, mod) == MATCH.nomatch) 949 return; 950 } 951 952 /* Success 953 */ 954 result = MATCH.constant; 955 } 956 957 override void visit(AddrExp e) 958 { 959 version (none) 960 { 961 printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 962 } 963 result = e.type.implicitConvTo(t); 964 //printf("\tresult = %d\n", result); 965 966 if (result != MATCH.nomatch) 967 return; 968 969 Type tb = t.toBasetype(); 970 Type typeb = e.type.toBasetype(); 971 972 // Look for pointers to functions where the functions are overloaded. 973 if (e.e1.op == TOK.overloadSet && 974 (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) 975 { 976 OverExp eo = e.e1.isOverExp(); 977 FuncDeclaration f = null; 978 foreach (s; eo.vars.a[]) 979 { 980 FuncDeclaration f2 = s.isFuncDeclaration(); 981 assert(f2); 982 if (f2.overloadExactMatch(tb.nextOf())) 983 { 984 if (f) 985 { 986 /* Error if match in more than one overload set, 987 * even if one is a 'better' match than the other. 988 */ 989 ScopeDsymbol.multiplyDefined(e.loc, f, f2); 990 } 991 else 992 f = f2; 993 result = MATCH.exact; 994 } 995 } 996 } 997 998 if (e.e1.op == TOK.variable && 999 typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && 1000 tb.ty == Tpointer && tb.nextOf().ty == Tfunction) 1001 { 1002 /* I don't think this can ever happen - 1003 * it should have been 1004 * converted to a SymOffExp. 1005 */ 1006 assert(0); 1007 } 1008 1009 //printf("\tresult = %d\n", result); 1010 } 1011 1012 override void visit(SymOffExp e) 1013 { 1014 version (none) 1015 { 1016 printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 1017 } 1018 result = e.type.implicitConvTo(t); 1019 //printf("\tresult = %d\n", result); 1020 if (result != MATCH.nomatch) 1021 return; 1022 1023 Type tb = t.toBasetype(); 1024 Type typeb = e.type.toBasetype(); 1025 1026 // Look for pointers to functions where the functions are overloaded. 1027 if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && 1028 (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) 1029 { 1030 if (FuncDeclaration f = e.var.isFuncDeclaration()) 1031 { 1032 f = f.overloadExactMatch(tb.nextOf()); 1033 if (f) 1034 { 1035 if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) || 1036 (tb.ty == Tpointer && !(f.needThis() || f.isNested()))) 1037 { 1038 result = MATCH.exact; 1039 } 1040 } 1041 } 1042 } 1043 //printf("\tresult = %d\n", result); 1044 } 1045 1046 override void visit(DelegateExp e) 1047 { 1048 version (none) 1049 { 1050 printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 1051 } 1052 result = e.type.implicitConvTo(t); 1053 if (result != MATCH.nomatch) 1054 return; 1055 1056 Type tb = t.toBasetype(); 1057 Type typeb = e.type.toBasetype(); 1058 1059 // Look for pointers to functions where the functions are overloaded. 1060 if (typeb.ty == Tdelegate && tb.ty == Tdelegate) 1061 { 1062 if (e.func && e.func.overloadExactMatch(tb.nextOf())) 1063 result = MATCH.exact; 1064 } 1065 } 1066 1067 override void visit(FuncExp e) 1068 { 1069 //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); 1070 MATCH m = e.matchType(t, null, null, 1); 1071 if (m > MATCH.nomatch) 1072 { 1073 result = m; 1074 return; 1075 } 1076 visit(cast(Expression)e); 1077 } 1078 1079 override void visit(AndExp e) 1080 { 1081 visit(cast(Expression)e); 1082 if (result != MATCH.nomatch) 1083 return; 1084 1085 MATCH m1 = e.e1.implicitConvTo(t); 1086 MATCH m2 = e.e2.implicitConvTo(t); 1087 1088 // Pick the worst match 1089 result = (m1 < m2) ? m1 : m2; 1090 } 1091 1092 override void visit(OrExp e) 1093 { 1094 visit(cast(Expression)e); 1095 if (result != MATCH.nomatch) 1096 return; 1097 1098 MATCH m1 = e.e1.implicitConvTo(t); 1099 MATCH m2 = e.e2.implicitConvTo(t); 1100 1101 // Pick the worst match 1102 result = (m1 < m2) ? m1 : m2; 1103 } 1104 1105 override void visit(XorExp e) 1106 { 1107 visit(cast(Expression)e); 1108 if (result != MATCH.nomatch) 1109 return; 1110 1111 MATCH m1 = e.e1.implicitConvTo(t); 1112 MATCH m2 = e.e2.implicitConvTo(t); 1113 1114 // Pick the worst match 1115 result = (m1 < m2) ? m1 : m2; 1116 } 1117 1118 override void visit(CondExp e) 1119 { 1120 MATCH m1 = e.e1.implicitConvTo(t); 1121 MATCH m2 = e.e2.implicitConvTo(t); 1122 //printf("CondExp: m1 %d m2 %d\n", m1, m2); 1123 1124 // Pick the worst match 1125 result = (m1 < m2) ? m1 : m2; 1126 } 1127 1128 override void visit(CommaExp e) 1129 { 1130 e.e2.accept(this); 1131 } 1132 1133 override void visit(CastExp e) 1134 { 1135 version (none) 1136 { 1137 printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 1138 } 1139 result = e.type.implicitConvTo(t); 1140 if (result != MATCH.nomatch) 1141 return; 1142 1143 if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch) 1144 result = MATCH.convert; 1145 else 1146 visit(cast(Expression)e); 1147 } 1148 1149 override void visit(NewExp e) 1150 { 1151 version (none) 1152 { 1153 printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 1154 } 1155 visit(cast(Expression)e); 1156 if (result != MATCH.nomatch) 1157 return; 1158 1159 /* Calling new() is like calling a pure function. We can implicitly convert the 1160 * return from new() to t using the same algorithm as in CallExp, with the function 1161 * 'arguments' being: 1162 * thisexp 1163 * newargs 1164 * arguments 1165 * .init 1166 * 'member' and 'allocator' need to be pure. 1167 */ 1168 1169 /* See if fail only because of mod bits 1170 */ 1171 if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch) 1172 return; 1173 1174 /* Get mod bits of what we're converting to 1175 */ 1176 Type tb = t.toBasetype(); 1177 MOD mod = tb.mod; 1178 if (Type ti = getIndirection(t)) 1179 mod = ti.mod; 1180 static if (LOG) 1181 { 1182 printf("mod = x%x\n", mod); 1183 } 1184 if (mod & MODFlags.wild) 1185 return; // not sure what to do with this 1186 1187 /* Apply mod bits to each argument, 1188 * and see if we can convert the argument to the modded type 1189 */ 1190 1191 if (e.thisexp) 1192 { 1193 /* Treat 'this' as just another function argument 1194 */ 1195 Type targ = e.thisexp.type; 1196 if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) 1197 return; 1198 } 1199 1200 /* Check call to 'allocator', then 'member' 1201 */ 1202 FuncDeclaration fd = e.allocator; 1203 for (int count = 0; count < 2; ++count, (fd = e.member)) 1204 { 1205 if (!fd) 1206 continue; 1207 if (fd.errors || fd.type.ty != Tfunction) 1208 return; // error 1209 TypeFunction tf = cast(TypeFunction)fd.type; 1210 if (tf.purity == PURE.impure) 1211 return; // impure 1212 1213 if (fd == e.member) 1214 { 1215 if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) 1216 { 1217 return; 1218 } 1219 // Allow a conversion to immutable type, or 1220 // conversions of mutable types between thread-local and shared. 1221 } 1222 1223 Expressions* args = (fd == e.allocator) ? e.newargs : e.arguments; 1224 1225 size_t nparams = tf.parameterList.length; 1226 // if TypeInfoArray was prepended 1227 size_t j = tf.isDstyleVariadic(); 1228 for (size_t i = j; i < e.arguments.dim; ++i) 1229 { 1230 Expression earg = (*args)[i]; 1231 Type targ = earg.type.toBasetype(); 1232 static if (LOG) 1233 { 1234 printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); 1235 } 1236 if (i - j < nparams) 1237 { 1238 Parameter fparam = tf.parameterList[i - j]; 1239 if (fparam.storageClass & STC.lazy_) 1240 return; // not sure what to do with this 1241 Type tparam = fparam.type; 1242 if (!tparam) 1243 continue; 1244 if (fparam.storageClass & (STC.out_ | STC.ref_)) 1245 { 1246 if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) 1247 return; 1248 continue; 1249 } 1250 } 1251 static if (LOG) 1252 { 1253 printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); 1254 } 1255 if (implicitMod(earg, targ, mod) == MATCH.nomatch) 1256 return; 1257 } 1258 } 1259 1260 /* If no 'member', then construction is by simple assignment, 1261 * and just straight check 'arguments' 1262 */ 1263 if (!e.member && e.arguments) 1264 { 1265 for (size_t i = 0; i < e.arguments.dim; ++i) 1266 { 1267 Expression earg = (*e.arguments)[i]; 1268 if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853 1269 // if it's on overlapped field 1270 continue; 1271 Type targ = earg.type.toBasetype(); 1272 static if (LOG) 1273 { 1274 printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); 1275 printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); 1276 } 1277 if (implicitMod(earg, targ, mod) == MATCH.nomatch) 1278 return; 1279 } 1280 } 1281 1282 /* Consider the .init expression as an argument 1283 */ 1284 Type ntb = e.newtype.toBasetype(); 1285 if (ntb.ty == Tarray) 1286 ntb = ntb.nextOf().toBasetype(); 1287 if (ntb.ty == Tstruct) 1288 { 1289 // Don't allow nested structs - uplevel reference may not be convertible 1290 StructDeclaration sd = (cast(TypeStruct)ntb).sym; 1291 sd.size(e.loc); // resolve any forward references 1292 if (sd.isNested()) 1293 return; 1294 } 1295 if (ntb.isZeroInit(e.loc)) 1296 { 1297 /* Zeros are implicitly convertible, except for special cases. 1298 */ 1299 if (ntb.ty == Tclass) 1300 { 1301 /* With new() must look at the class instance initializer. 1302 */ 1303 ClassDeclaration cd = (cast(TypeClass)ntb).sym; 1304 1305 cd.size(e.loc); // resolve any forward references 1306 1307 if (cd.isNested()) 1308 return; // uplevel reference may not be convertible 1309 1310 assert(!cd.isInterfaceDeclaration()); 1311 1312 struct ClassCheck 1313 { 1314 extern (C++) static bool convertible(Loc loc, ClassDeclaration cd, MOD mod) 1315 { 1316 for (size_t i = 0; i < cd.fields.dim; i++) 1317 { 1318 VarDeclaration v = cd.fields[i]; 1319 Initializer _init = v._init; 1320 if (_init) 1321 { 1322 if (_init.isVoidInitializer()) 1323 { 1324 } 1325 else if (ExpInitializer ei = _init.isExpInitializer()) 1326 { 1327 Type tb = v.type.toBasetype(); 1328 if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch) 1329 return false; 1330 } 1331 else 1332 { 1333 /* Enhancement: handle StructInitializer and ArrayInitializer 1334 */ 1335 return false; 1336 } 1337 } 1338 else if (!v.type.isZeroInit(loc)) 1339 return false; 1340 } 1341 return cd.baseClass ? convertible(loc, cd.baseClass, mod) : true; 1342 } 1343 } 1344 1345 if (!ClassCheck.convertible(e.loc, cd, mod)) 1346 return; 1347 } 1348 } 1349 else 1350 { 1351 Expression earg = e.newtype.defaultInitLiteral(e.loc); 1352 Type targ = e.newtype.toBasetype(); 1353 1354 if (implicitMod(earg, targ, mod) == MATCH.nomatch) 1355 return; 1356 } 1357 1358 /* Success 1359 */ 1360 result = MATCH.constant; 1361 } 1362 1363 override void visit(SliceExp e) 1364 { 1365 //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars()); 1366 visit(cast(Expression)e); 1367 if (result != MATCH.nomatch) 1368 return; 1369 1370 Type tb = t.toBasetype(); 1371 Type typeb = e.type.toBasetype(); 1372 1373 if (tb.ty == Tsarray && typeb.ty == Tarray) 1374 { 1375 typeb = toStaticArrayType(e); 1376 if (typeb) 1377 result = typeb.implicitConvTo(t); 1378 return; 1379 } 1380 1381 /* If the only reason it won't convert is because of the mod bits, 1382 * then test for conversion by seeing if e1 can be converted with those 1383 * same mod bits. 1384 */ 1385 Type t1b = e.e1.type.toBasetype(); 1386 if (tb.ty == Tarray && typeb.equivalent(tb)) 1387 { 1388 Type tbn = tb.nextOf(); 1389 Type tx = null; 1390 1391 /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1 1392 * is equivalent with the uniqueness of the referred data. And in here 1393 * we can have arbitrary typed reference for that. 1394 */ 1395 if (t1b.ty == Tarray) 1396 tx = tbn.arrayOf(); 1397 if (t1b.ty == Tpointer) 1398 tx = tbn.pointerTo(); 1399 1400 /* If e.e1 is static array, at least it should be an rvalue. 1401 * If not, e.e1 is a reference, and its uniqueness does not link 1402 * to the uniqueness of the referred data. 1403 */ 1404 if (t1b.ty == Tsarray && !e.e1.isLvalue()) 1405 tx = tbn.sarrayOf(t1b.size() / tbn.size()); 1406 1407 if (tx) 1408 { 1409 result = e.e1.implicitConvTo(tx); 1410 if (result > MATCH.constant) // Match level is MATCH.constant at best. 1411 result = MATCH.constant; 1412 } 1413 } 1414 1415 // Enhancement 10724 1416 if (tb.ty == Tpointer && e.e1.op == TOK.string_) 1417 e.e1.accept(this); 1418 } 1419 } 1420 1421 scope ImplicitConvTo v = new ImplicitConvTo(t); 1422 e.accept(v); 1423 return v.result; 1424 } 1425 1426 Type toStaticArrayType(SliceExp e) 1427 { 1428 if (e.lwr && e.upr) 1429 { 1430 // For the following code to work, e should be optimized beforehand. 1431 // (eg. $ in lwr and upr should be already resolved, if possible) 1432 Expression lwr = e.lwr.optimize(WANTvalue); 1433 Expression upr = e.upr.optimize(WANTvalue); 1434 if (lwr.isConst() && upr.isConst()) 1435 { 1436 size_t len = cast(size_t)(upr.toUInteger() - lwr.toUInteger()); 1437 return e.type.toBasetype().nextOf().sarrayOf(len); 1438 } 1439 } 1440 else 1441 { 1442 Type t1b = e.e1.type.toBasetype(); 1443 if (t1b.ty == Tsarray) 1444 return t1b; 1445 } 1446 return null; 1447 } 1448 1449 // Try casting the alias this member. Return the expression if it succeeds, null otherwise. 1450 private Expression tryAliasThisCast(Expression e, Scope* sc, Type tob, Type t1b, Type t) 1451 { 1452 Expression result; 1453 AggregateDeclaration t1ad = isAggregate(t1b); 1454 if (!t1ad) 1455 return null; 1456 1457 AggregateDeclaration toad = isAggregate(tob); 1458 if (t1ad == toad || !t1ad.aliasthis) 1459 return null; 1460 1461 /* Forward the cast to our alias this member, rewrite to: 1462 * cast(to)e1.aliasthis 1463 */ 1464 result = resolveAliasThis(sc, e); 1465 const errors = global.startGagging(); 1466 result = result.castTo(sc, t); 1467 return global.endGagging(errors) ? null : result; 1468 } 1469 1470 /************************************** 1471 * Do an explicit cast. 1472 * Assume that the 'this' expression does not have any indirections. 1473 */ 1474 Expression castTo(Expression e, Scope* sc, Type t) 1475 { 1476 extern (C++) final class CastTo : Visitor 1477 { 1478 alias visit = Visitor.visit; 1479 public: 1480 Type t; 1481 Scope* sc; 1482 Expression result; 1483 1484 extern (D) this(Scope* sc, Type t) 1485 { 1486 this.sc = sc; 1487 this.t = t; 1488 } 1489 1490 override void visit(Expression e) 1491 { 1492 //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars()); 1493 version (none) 1494 { 1495 printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 1496 } 1497 if (e.type.equals(t)) 1498 { 1499 result = e; 1500 return; 1501 } 1502 if (e.op == TOK.variable) 1503 { 1504 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); 1505 if (v && v.storage_class & STC.manifest) 1506 { 1507 result = e.ctfeInterpret(); 1508 /* https://issues.dlang.org/show_bug.cgi?id=18236 1509 * 1510 * The expression returned by ctfeInterpret points 1511 * to the line where the manifest constant was declared 1512 * so we need to update the location before trying to cast 1513 */ 1514 result.loc = e.loc; 1515 result = result.castTo(sc, t); 1516 return; 1517 } 1518 } 1519 1520 Type tob = t.toBasetype(); 1521 Type t1b = e.type.toBasetype(); 1522 if (tob.equals(t1b)) 1523 { 1524 result = e.copy(); // because of COW for assignment to e.type 1525 result.type = t; 1526 return; 1527 } 1528 1529 /* Make semantic error against invalid cast between concrete types. 1530 * Assume that 'e' is never be any placeholder expressions. 1531 * The result of these checks should be consistent with CastExp::toElem(). 1532 */ 1533 1534 // Fat Value types 1535 const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray); 1536 const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray); 1537 1538 // Fat Reference types 1539 const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate); 1540 const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate); 1541 1542 // Reference types 1543 const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass); 1544 const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass); 1545 1546 // Arithmetic types (== valueable basic types) 1547 const(bool) tob_isA = (tob.isintegral() || tob.isfloating()); 1548 const(bool) t1b_isA = (t1b.isintegral() || t1b.isfloating()); 1549 1550 bool hasAliasThis; 1551 if (AggregateDeclaration t1ad = isAggregate(t1b)) 1552 { 1553 AggregateDeclaration toad = isAggregate(tob); 1554 if (t1ad != toad && t1ad.aliasthis) 1555 { 1556 if (t1b.ty == Tclass && tob.ty == Tclass) 1557 { 1558 ClassDeclaration t1cd = t1b.isClassHandle(); 1559 ClassDeclaration tocd = tob.isClassHandle(); 1560 int offset; 1561 if (tocd.isBaseOf(t1cd, &offset)) 1562 goto Lok; 1563 } 1564 hasAliasThis = true; 1565 } 1566 } 1567 else if (tob.ty == Tvector && t1b.ty != Tvector) 1568 { 1569 //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars()); 1570 TypeVector tv = cast(TypeVector)tob; 1571 result = new CastExp(e.loc, e, tv.elementType()); 1572 result = new VectorExp(e.loc, result, tob); 1573 result = result.expressionSemantic(sc); 1574 return; 1575 } 1576 else if (tob.ty != Tvector && t1b.ty == Tvector) 1577 { 1578 // T[n] <-- __vector(U[m]) 1579 if (tob.ty == Tsarray) 1580 { 1581 if (t1b.size(e.loc) == tob.size(e.loc)) 1582 goto Lok; 1583 } 1584 goto Lfail; 1585 } 1586 else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf())) 1587 { 1588 result = e.copy(); 1589 result.type = t; 1590 return; 1591 } 1592 1593 // arithmetic values vs. other arithmetic values 1594 // arithmetic values vs. T* 1595 if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer)) 1596 { 1597 goto Lok; 1598 } 1599 1600 // arithmetic values vs. references or fat values 1601 if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV)) 1602 { 1603 goto Lfail; 1604 } 1605 1606 // Bugzlla 3133: A cast between fat values is possible only when the sizes match. 1607 if (tob_isFV && t1b_isFV) 1608 { 1609 if (hasAliasThis) 1610 { 1611 result = tryAliasThisCast(e, sc, tob, t1b, t); 1612 if (result) 1613 return; 1614 } 1615 1616 if (t1b.size(e.loc) == tob.size(e.loc)) 1617 goto Lok; 1618 1619 auto ts = toAutoQualChars(e.type, t); 1620 e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes", 1621 e.toChars(), ts[0], ts[1]); 1622 result = new ErrorExp(); 1623 return; 1624 } 1625 1626 // Fat values vs. null or references 1627 if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR)) 1628 { 1629 if (tob.ty == Tpointer && t1b.ty == Tsarray) 1630 { 1631 // T[n] sa; 1632 // cast(U*)sa; // ==> cast(U*)sa.ptr; 1633 result = new AddrExp(e.loc, e, t); 1634 return; 1635 } 1636 if (tob.ty == Tarray && t1b.ty == Tsarray) 1637 { 1638 // T[n] sa; 1639 // cast(U[])sa; // ==> cast(U[])sa[]; 1640 d_uns64 fsize = t1b.nextOf().size(); 1641 d_uns64 tsize = tob.nextOf().size(); 1642 if (((cast(TypeSArray)t1b).dim.toInteger() * fsize) % tsize != 0) 1643 { 1644 // copied from sarray_toDarray() in e2ir.c 1645 e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up", e.toChars(), e.type.toChars(), t.toChars()); 1646 result = new ErrorExp(); 1647 return; 1648 } 1649 goto Lok; 1650 } 1651 goto Lfail; 1652 } 1653 1654 /* For references, any reinterpret casts are allowed to same 'ty' type. 1655 * T* to U* 1656 * R1 function(P1) to R2 function(P2) 1657 * R1 delegate(P1) to R2 delegate(P2) 1658 * T[] to U[] 1659 * V1[K1] to V2[K2] 1660 * class/interface A to B (will be a dynamic cast if possible) 1661 */ 1662 if (tob.ty == t1b.ty && tob_isR && t1b_isR) 1663 goto Lok; 1664 1665 // typeof(null) <-- non-null references or values 1666 if (tob.ty == Tnull && t1b.ty != Tnull) 1667 goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629 1668 // typeof(null) --> non-null references or arithmetic values 1669 if (t1b.ty == Tnull && tob.ty != Tnull) 1670 goto Lok; 1671 1672 // Check size mismatch of references. 1673 // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof. 1674 if (tob_isFR && t1b_isR || t1b_isFR && tob_isR) 1675 { 1676 if (tob.ty == Tpointer && t1b.ty == Tarray) 1677 { 1678 // T[] da; 1679 // cast(U*)da; // ==> cast(U*)da.ptr; 1680 goto Lok; 1681 } 1682 if (tob.ty == Tpointer && t1b.ty == Tdelegate) 1683 { 1684 // void delegate() dg; 1685 // cast(U*)dg; // ==> cast(U*)dg.ptr; 1686 // Note that it happens even when U is a Tfunction! 1687 e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars()); 1688 goto Lok; 1689 } 1690 goto Lfail; 1691 } 1692 1693 if (t1b.ty == Tvoid && tob.ty != Tvoid) 1694 { 1695 Lfail: 1696 /* if the cast cannot be performed, maybe there is an alias 1697 * this that can be used for casting. 1698 */ 1699 if (hasAliasThis) 1700 { 1701 result = tryAliasThisCast(e, sc, tob, t1b, t); 1702 if (result) 1703 return; 1704 } 1705 e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars()); 1706 result = new ErrorExp(); 1707 return; 1708 } 1709 1710 Lok: 1711 result = new CastExp(e.loc, e, t); 1712 result.type = t; // Don't call semantic() 1713 //printf("Returning: %s\n", result.toChars()); 1714 } 1715 1716 override void visit(ErrorExp e) 1717 { 1718 result = e; 1719 } 1720 1721 override void visit(RealExp e) 1722 { 1723 if (!e.type.equals(t)) 1724 { 1725 if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary())) 1726 { 1727 result = e.copy(); 1728 result.type = t; 1729 } 1730 else 1731 visit(cast(Expression)e); 1732 return; 1733 } 1734 result = e; 1735 } 1736 1737 override void visit(ComplexExp e) 1738 { 1739 if (!e.type.equals(t)) 1740 { 1741 if (e.type.iscomplex() && t.iscomplex()) 1742 { 1743 result = e.copy(); 1744 result.type = t; 1745 } 1746 else 1747 visit(cast(Expression)e); 1748 return; 1749 } 1750 result = e; 1751 } 1752 1753 override void visit(NullExp e) 1754 { 1755 //printf("NullExp::castTo(t = %s) %s\n", t.toChars(), toChars()); 1756 visit(cast(Expression)e); 1757 if (result.op == TOK.null_) 1758 { 1759 NullExp ex = cast(NullExp)result; 1760 ex.committed = 1; 1761 return; 1762 } 1763 } 1764 1765 override void visit(StructLiteralExp e) 1766 { 1767 visit(cast(Expression)e); 1768 if (result.op == TOK.structLiteral) 1769 (cast(StructLiteralExp)result).stype = t; // commit type 1770 } 1771 1772 override void visit(StringExp e) 1773 { 1774 /* This follows copy-on-write; any changes to 'this' 1775 * will result in a copy. 1776 * The this.string member is considered immutable. 1777 */ 1778 int copied = 0; 1779 1780 //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed); 1781 1782 if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) 1783 { 1784 e.error("cannot convert string literal to `void*`"); 1785 result = new ErrorExp(); 1786 return; 1787 } 1788 1789 StringExp se = e; 1790 if (!e.committed) 1791 { 1792 se = cast(StringExp)e.copy(); 1793 se.committed = 1; 1794 copied = 1; 1795 } 1796 1797 if (e.type.equals(t)) 1798 { 1799 result = se; 1800 return; 1801 } 1802 1803 Type tb = t.toBasetype(); 1804 Type typeb = e.type.toBasetype(); 1805 1806 //printf("\ttype = %s\n", e.type.toChars()); 1807 if (tb.ty == Tdelegate && typeb.ty != Tdelegate) 1808 { 1809 visit(cast(Expression)e); 1810 return; 1811 } 1812 1813 if (typeb.equals(tb)) 1814 { 1815 if (!copied) 1816 { 1817 se = cast(StringExp)e.copy(); 1818 copied = 1; 1819 } 1820 se.type = t; 1821 result = se; 1822 return; 1823 } 1824 1825 /* Handle reinterpret casts: 1826 * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000] 1827 * cast(wchar[2])"abcd"c --> [\u6261, \u6463] 1828 * cast(wchar[1])"abcd"c --> [\u6261] 1829 * cast(char[4])"a" --> ['a', 0, 0, 0] 1830 */ 1831 if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray) 1832 { 1833 se = cast(StringExp)e.copy(); 1834 d_uns64 szx = tb.nextOf().size(); 1835 assert(szx <= 255); 1836 se.sz = cast(ubyte)szx; 1837 se.len = cast(size_t)(cast(TypeSArray)tb).dim.toInteger(); 1838 se.committed = 1; 1839 se.type = t; 1840 1841 /* If larger than source, pad with zeros. 1842 */ 1843 const fullSize = (se.len + 1) * se.sz; // incl. terminating 0 1844 if (fullSize > (e.len + 1) * e.sz) 1845 { 1846 void* s = mem.xmalloc(fullSize); 1847 const srcSize = e.len * e.sz; 1848 const data = se.peekData(); 1849 memcpy(s, data.ptr, srcSize); 1850 memset(s + srcSize, 0, fullSize - srcSize); 1851 se.setData(s, se.len, se.sz); 1852 } 1853 result = se; 1854 return; 1855 } 1856 1857 if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer) 1858 { 1859 if (!copied) 1860 { 1861 se = cast(StringExp)e.copy(); 1862 copied = 1; 1863 } 1864 goto Lcast; 1865 } 1866 if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer) 1867 { 1868 if (!copied) 1869 { 1870 se = cast(StringExp)e.copy(); 1871 copied = 1; 1872 } 1873 goto Lcast; 1874 } 1875 1876 if (typeb.nextOf().size() == tb.nextOf().size()) 1877 { 1878 if (!copied) 1879 { 1880 se = cast(StringExp)e.copy(); 1881 copied = 1; 1882 } 1883 if (tb.ty == Tsarray) 1884 goto L2; // handle possible change in static array dimension 1885 se.type = t; 1886 result = se; 1887 return; 1888 } 1889 1890 if (e.committed) 1891 goto Lcast; 1892 1893 auto X(T, U)(T tf, U tt) 1894 { 1895 return (cast(int)tf * 256 + cast(int)tt); 1896 } 1897 1898 { 1899 OutBuffer buffer; 1900 size_t newlen = 0; 1901 int tfty = typeb.nextOf().toBasetype().ty; 1902 int ttty = tb.nextOf().toBasetype().ty; 1903 switch (X(tfty, ttty)) 1904 { 1905 case X(Tchar, Tchar): 1906 case X(Twchar, Twchar): 1907 case X(Tdchar, Tdchar): 1908 break; 1909 1910 case X(Tchar, Twchar): 1911 for (size_t u = 0; u < e.len;) 1912 { 1913 dchar c; 1914 if (const s = utf_decodeChar(se.peekString(), u, c)) 1915 e.error("%.*s", cast(int)s.length, s.ptr); 1916 else 1917 buffer.writeUTF16(c); 1918 } 1919 newlen = buffer.length / 2; 1920 buffer.writeUTF16(0); 1921 goto L1; 1922 1923 case X(Tchar, Tdchar): 1924 for (size_t u = 0; u < e.len;) 1925 { 1926 dchar c; 1927 if (const s = utf_decodeChar(se.peekString(), u, c)) 1928 e.error("%.*s", cast(int)s.length, s.ptr); 1929 buffer.write4(c); 1930 newlen++; 1931 } 1932 buffer.write4(0); 1933 goto L1; 1934 1935 case X(Twchar, Tchar): 1936 for (size_t u = 0; u < e.len;) 1937 { 1938 dchar c; 1939 if (const s = utf_decodeWchar(se.peekWstring(), u, c)) 1940 e.error("%.*s", cast(int)s.length, s.ptr); 1941 else 1942 buffer.writeUTF8(c); 1943 } 1944 newlen = buffer.length; 1945 buffer.writeUTF8(0); 1946 goto L1; 1947 1948 case X(Twchar, Tdchar): 1949 for (size_t u = 0; u < e.len;) 1950 { 1951 dchar c; 1952 if (const s = utf_decodeWchar(se.peekWstring(), u, c)) 1953 e.error("%.*s", cast(int)s.length, s.ptr); 1954 buffer.write4(c); 1955 newlen++; 1956 } 1957 buffer.write4(0); 1958 goto L1; 1959 1960 case X(Tdchar, Tchar): 1961 for (size_t u = 0; u < e.len; u++) 1962 { 1963 uint c = se.peekDstring()[u]; 1964 if (!utf_isValidDchar(c)) 1965 e.error("invalid UCS-32 char \\U%08x", c); 1966 else 1967 buffer.writeUTF8(c); 1968 newlen++; 1969 } 1970 newlen = buffer.length; 1971 buffer.writeUTF8(0); 1972 goto L1; 1973 1974 case X(Tdchar, Twchar): 1975 for (size_t u = 0; u < e.len; u++) 1976 { 1977 uint c = se.peekDstring()[u]; 1978 if (!utf_isValidDchar(c)) 1979 e.error("invalid UCS-32 char \\U%08x", c); 1980 else 1981 buffer.writeUTF16(c); 1982 newlen++; 1983 } 1984 newlen = buffer.length / 2; 1985 buffer.writeUTF16(0); 1986 goto L1; 1987 1988 L1: 1989 if (!copied) 1990 { 1991 se = cast(StringExp)e.copy(); 1992 copied = 1; 1993 } 1994 1995 { 1996 d_uns64 szx = tb.nextOf().size(); 1997 assert(szx <= 255); 1998 se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx); 1999 } 2000 break; 2001 2002 default: 2003 assert(typeb.nextOf().size() != tb.nextOf().size()); 2004 goto Lcast; 2005 } 2006 } 2007 L2: 2008 assert(copied); 2009 2010 // See if need to truncate or extend the literal 2011 if (tb.ty == Tsarray) 2012 { 2013 size_t dim2 = cast(size_t)(cast(TypeSArray)tb).dim.toInteger(); 2014 //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2); 2015 2016 // Changing dimensions 2017 if (dim2 != se.len) 2018 { 2019 // Copy when changing the string literal 2020 const newsz = se.sz; 2021 const d = (dim2 < se.len) ? dim2 : se.len; 2022 void* s = mem.xmalloc((dim2 + 1) * newsz); 2023 memcpy(s, se.peekData().ptr, d * newsz); 2024 // Extend with 0, add terminating 0 2025 memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz); 2026 se.setData(s, dim2, newsz); 2027 } 2028 } 2029 se.type = t; 2030 result = se; 2031 return; 2032 2033 Lcast: 2034 result = new CastExp(e.loc, se, t); 2035 result.type = t; // so semantic() won't be run on e 2036 } 2037 2038 override void visit(AddrExp e) 2039 { 2040 version (none) 2041 { 2042 printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 2043 } 2044 result = e; 2045 2046 Type tb = t.toBasetype(); 2047 Type typeb = e.type.toBasetype(); 2048 2049 if (tb.equals(typeb)) 2050 { 2051 result = e.copy(); 2052 result.type = t; 2053 return; 2054 } 2055 2056 // Look for pointers to functions where the functions are overloaded. 2057 if (e.e1.op == TOK.overloadSet && 2058 (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) 2059 { 2060 OverExp eo = cast(OverExp)e.e1; 2061 FuncDeclaration f = null; 2062 for (size_t i = 0; i < eo.vars.a.dim; i++) 2063 { 2064 auto s = eo.vars.a[i]; 2065 auto f2 = s.isFuncDeclaration(); 2066 assert(f2); 2067 if (f2.overloadExactMatch(tb.nextOf())) 2068 { 2069 if (f) 2070 { 2071 /* Error if match in more than one overload set, 2072 * even if one is a 'better' match than the other. 2073 */ 2074 ScopeDsymbol.multiplyDefined(e.loc, f, f2); 2075 } 2076 else 2077 f = f2; 2078 } 2079 } 2080 if (f) 2081 { 2082 f.tookAddressOf++; 2083 auto se = new SymOffExp(e.loc, f, 0, false); 2084 se.expressionSemantic(sc); 2085 // Let SymOffExp::castTo() do the heavy lifting 2086 visit(se); 2087 return; 2088 } 2089 } 2090 2091 if (e.e1.op == TOK.variable && 2092 typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && 2093 tb.ty == Tpointer && tb.nextOf().ty == Tfunction) 2094 { 2095 auto ve = cast(VarExp)e.e1; 2096 auto f = ve.var.isFuncDeclaration(); 2097 if (f) 2098 { 2099 assert(f.isImportedSymbol()); 2100 f = f.overloadExactMatch(tb.nextOf()); 2101 if (f) 2102 { 2103 result = new VarExp(e.loc, f, false); 2104 result.type = f.type; 2105 result = new AddrExp(e.loc, result, t); 2106 return; 2107 } 2108 } 2109 } 2110 2111 if (auto f = isFuncAddress(e)) 2112 { 2113 if (f.checkForwardRef(e.loc)) 2114 { 2115 result = new ErrorExp(); 2116 return; 2117 } 2118 } 2119 2120 visit(cast(Expression)e); 2121 } 2122 2123 override void visit(TupleExp e) 2124 { 2125 if (e.type.equals(t)) 2126 { 2127 result = e; 2128 return; 2129 } 2130 2131 TupleExp te = cast(TupleExp)e.copy(); 2132 te.e0 = e.e0 ? e.e0.copy() : null; 2133 te.exps = e.exps.copy(); 2134 for (size_t i = 0; i < te.exps.dim; i++) 2135 { 2136 Expression ex = (*te.exps)[i]; 2137 ex = ex.castTo(sc, t); 2138 (*te.exps)[i] = ex; 2139 } 2140 result = te; 2141 2142 /* Questionable behavior: In here, result.type is not set to t. 2143 * Therefoe: 2144 * TypeTuple!(int, int) values; 2145 * auto values2 = cast(long)values; 2146 * // typeof(values2) == TypeTuple!(int, int) !! 2147 * 2148 * Only when the casted tuple is immediately expanded, it would work. 2149 * auto arr = [cast(long)values]; 2150 * // typeof(arr) == long[] 2151 */ 2152 } 2153 2154 override void visit(ArrayLiteralExp e) 2155 { 2156 version (none) 2157 { 2158 printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); 2159 } 2160 2161 ArrayLiteralExp ae = e; 2162 2163 Type tb = t.toBasetype(); 2164 if (tb.ty == Tarray && global.params.vsafe) 2165 { 2166 if (checkArrayLiteralEscape(sc, ae, false)) 2167 { 2168 result = new ErrorExp(); 2169 return; 2170 } 2171 } 2172 2173 if (e.type == t) 2174 { 2175 result = e; 2176 return; 2177 } 2178 Type typeb = e.type.toBasetype(); 2179 2180 if ((tb.ty == Tarray || tb.ty == Tsarray) && 2181 (typeb.ty == Tarray || typeb.ty == Tsarray)) 2182 { 2183 if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid) 2184 { 2185 // Don't do anything to cast non-void[] to void[] 2186 } 2187 else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid) 2188 { 2189 // Don't do anything for casting void[n] to others 2190 } 2191 else 2192 { 2193 if (tb.ty == Tsarray) 2194 { 2195 TypeSArray tsa = cast(TypeSArray)tb; 2196 if (e.elements.dim != tsa.dim.toInteger()) 2197 goto L1; 2198 } 2199 2200 ae = cast(ArrayLiteralExp)e.copy(); 2201 if (e.basis) 2202 ae.basis = e.basis.castTo(sc, tb.nextOf()); 2203 ae.elements = e.elements.copy(); 2204 for (size_t i = 0; i < e.elements.dim; i++) 2205 { 2206 Expression ex = (*e.elements)[i]; 2207 if (!ex) 2208 continue; 2209 ex = ex.castTo(sc, tb.nextOf()); 2210 (*ae.elements)[i] = ex; 2211 } 2212 ae.type = t; 2213 result = ae; 2214 return; 2215 } 2216 } 2217 else if (tb.ty == Tpointer && typeb.ty == Tsarray) 2218 { 2219 Type tp = typeb.nextOf().pointerTo(); 2220 if (!tp.equals(ae.type)) 2221 { 2222 ae = cast(ArrayLiteralExp)e.copy(); 2223 ae.type = tp; 2224 } 2225 } 2226 else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) 2227 { 2228 // Convert array literal to vector type 2229 TypeVector tv = cast(TypeVector)tb; 2230 TypeSArray tbase = cast(TypeSArray)tv.basetype; 2231 assert(tbase.ty == Tsarray); 2232 const edim = e.elements.dim; 2233 const tbasedim = tbase.dim.toInteger(); 2234 if (edim > tbasedim) 2235 goto L1; 2236 2237 ae = cast(ArrayLiteralExp)e.copy(); 2238 ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642 2239 ae.elements = e.elements.copy(); 2240 Type telement = tv.elementType(); 2241 foreach (i; 0 .. edim) 2242 { 2243 Expression ex = (*e.elements)[i]; 2244 ex = ex.castTo(sc, telement); 2245 (*ae.elements)[i] = ex; 2246 } 2247 // Fill in the rest with the default initializer 2248 ae.elements.setDim(cast(size_t)tbasedim); 2249 foreach (i; edim .. cast(size_t)tbasedim) 2250 { 2251 Expression ex = typeb.nextOf.defaultInitLiteral(e.loc); 2252 ex = ex.castTo(sc, telement); 2253 (*ae.elements)[i] = ex; 2254 } 2255 Expression ev = new VectorExp(e.loc, ae, tb); 2256 ev = ev.expressionSemantic(sc); 2257 result = ev; 2258 return; 2259 } 2260 L1: 2261 visit(cast(Expression)ae); 2262 } 2263 2264 override void visit(AssocArrayLiteralExp e) 2265 { 2266 //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); 2267 if (e.type == t) 2268 { 2269 result = e; 2270 return; 2271 } 2272 2273 Type tb = t.toBasetype(); 2274 Type typeb = e.type.toBasetype(); 2275 2276 if (tb.ty == Taarray && typeb.ty == Taarray && 2277 tb.nextOf().toBasetype().ty != Tvoid) 2278 { 2279 AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e.copy(); 2280 ae.keys = e.keys.copy(); 2281 ae.values = e.values.copy(); 2282 assert(e.keys.dim == e.values.dim); 2283 for (size_t i = 0; i < e.keys.dim; i++) 2284 { 2285 Expression ex = (*e.values)[i]; 2286 ex = ex.castTo(sc, tb.nextOf()); 2287 (*ae.values)[i] = ex; 2288 2289 ex = (*e.keys)[i]; 2290 ex = ex.castTo(sc, (cast(TypeAArray)tb).index); 2291 (*ae.keys)[i] = ex; 2292 } 2293 ae.type = t; 2294 result = ae; 2295 return; 2296 } 2297 visit(cast(Expression)e); 2298 } 2299 2300 override void visit(SymOffExp e) 2301 { 2302 version (none) 2303 { 2304 printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 2305 } 2306 if (e.type == t && !e.hasOverloads) 2307 { 2308 result = e; 2309 return; 2310 } 2311 2312 Type tb = t.toBasetype(); 2313 Type typeb = e.type.toBasetype(); 2314 2315 if (tb.equals(typeb)) 2316 { 2317 result = e.copy(); 2318 result.type = t; 2319 (cast(SymOffExp)result).hasOverloads = false; 2320 return; 2321 } 2322 2323 // Look for pointers to functions where the functions are overloaded. 2324 if (e.hasOverloads && 2325 typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && 2326 (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) 2327 { 2328 FuncDeclaration f = e.var.isFuncDeclaration(); 2329 f = f ? f.overloadExactMatch(tb.nextOf()) : null; 2330 if (f) 2331 { 2332 if (tb.ty == Tdelegate) 2333 { 2334 if (f.needThis() && hasThis(sc)) 2335 { 2336 result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false); 2337 result = result.expressionSemantic(sc); 2338 } 2339 else if (f.needThis()) 2340 { 2341 e.error("no `this` to create delegate for `%s`", f.toChars()); 2342 result = new ErrorExp(); 2343 return; 2344 } 2345 else if (f.isNested()) 2346 { 2347 result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false); 2348 result = result.expressionSemantic(sc); 2349 } 2350 else 2351 { 2352 e.error("cannot cast from function pointer to delegate"); 2353 result = new ErrorExp(); 2354 return; 2355 } 2356 } 2357 else 2358 { 2359 result = new SymOffExp(e.loc, f, 0, false); 2360 result.type = t; 2361 } 2362 f.tookAddressOf++; 2363 return; 2364 } 2365 } 2366 2367 if (auto f = isFuncAddress(e)) 2368 { 2369 if (f.checkForwardRef(e.loc)) 2370 { 2371 result = new ErrorExp(); 2372 return; 2373 } 2374 } 2375 2376 visit(cast(Expression)e); 2377 } 2378 2379 override void visit(DelegateExp e) 2380 { 2381 version (none) 2382 { 2383 printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); 2384 } 2385 __gshared const(char)* msg = "cannot form delegate due to covariant return type"; 2386 2387 Type tb = t.toBasetype(); 2388 Type typeb = e.type.toBasetype(); 2389 2390 if (tb.equals(typeb) && !e.hasOverloads) 2391 { 2392 int offset; 2393 e.func.tookAddressOf++; 2394 if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset) 2395 e.error("%s", msg); 2396 result = e.copy(); 2397 result.type = t; 2398 return; 2399 } 2400 2401 // Look for delegates to functions where the functions are overloaded. 2402 if (typeb.ty == Tdelegate && tb.ty == Tdelegate) 2403 { 2404 if (e.func) 2405 { 2406 auto f = e.func.overloadExactMatch(tb.nextOf()); 2407 if (f) 2408 { 2409 int offset; 2410 if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) 2411 e.error("%s", msg); 2412 if (f != e.func) // if address not already marked as taken 2413 f.tookAddressOf++; 2414 result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2); 2415 result.type = t; 2416 return; 2417 } 2418 if (e.func.tintro) 2419 e.error("%s", msg); 2420 } 2421 } 2422 2423 if (auto f = isFuncAddress(e)) 2424 { 2425 if (f.checkForwardRef(e.loc)) 2426 { 2427 result = new ErrorExp(); 2428 return; 2429 } 2430 } 2431 2432 visit(cast(Expression)e); 2433 } 2434 2435 override void visit(FuncExp e) 2436 { 2437 //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars()); 2438 FuncExp fe; 2439 if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch) 2440 { 2441 result = fe; 2442 return; 2443 } 2444 visit(cast(Expression)e); 2445 } 2446 2447 override void visit(CondExp e) 2448 { 2449 if (!e.type.equals(t)) 2450 { 2451 result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t)); 2452 result.type = t; 2453 return; 2454 } 2455 result = e; 2456 } 2457 2458 override void visit(CommaExp e) 2459 { 2460 Expression e2c = e.e2.castTo(sc, t); 2461 2462 if (e2c != e.e2) 2463 { 2464 result = new CommaExp(e.loc, e.e1, e2c); 2465 result.type = e2c.type; 2466 } 2467 else 2468 { 2469 result = e; 2470 result.type = e.e2.type; 2471 } 2472 } 2473 2474 override void visit(SliceExp e) 2475 { 2476 //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars()); 2477 2478 Type tb = t.toBasetype(); 2479 Type typeb = e.type.toBasetype(); 2480 2481 if (e.type.equals(t) || typeb.ty != Tarray || 2482 (tb.ty != Tarray && tb.ty != Tsarray)) 2483 { 2484 visit(cast(Expression)e); 2485 return; 2486 } 2487 2488 if (tb.ty == Tarray) 2489 { 2490 if (typeb.nextOf().equivalent(tb.nextOf())) 2491 { 2492 // T[] to const(T)[] 2493 result = e.copy(); 2494 result.type = t; 2495 } 2496 else 2497 { 2498 visit(cast(Expression)e); 2499 } 2500 return; 2501 } 2502 2503 // Handle the cast from Tarray to Tsarray with CT-known slicing 2504 2505 TypeSArray tsa = cast(TypeSArray)toStaticArrayType(e); 2506 if (tsa && tsa.size(e.loc) == tb.size(e.loc)) 2507 { 2508 /* Match if the sarray sizes are equal: 2509 * T[a .. b] to const(T)[b-a] 2510 * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim) 2511 * 2512 * If a SliceExp has Tsarray, it will become lvalue. 2513 * That's handled in SliceExp::isLvalue and toLvalue 2514 */ 2515 result = e.copy(); 2516 result.type = t; 2517 return; 2518 } 2519 if (tsa && tsa.dim.equals((cast(TypeSArray)tb).dim)) 2520 { 2521 /* Match if the dimensions are equal 2522 * with the implicit conversion of e.e1: 2523 * cast(float[2]) [2.0, 1.0, 0.0][0..2]; 2524 */ 2525 Type t1b = e.e1.type.toBasetype(); 2526 if (t1b.ty == Tsarray) 2527 t1b = tb.nextOf().sarrayOf((cast(TypeSArray)t1b).dim.toInteger()); 2528 else if (t1b.ty == Tarray) 2529 t1b = tb.nextOf().arrayOf(); 2530 else if (t1b.ty == Tpointer) 2531 t1b = tb.nextOf().pointerTo(); 2532 else 2533 assert(0); 2534 if (e.e1.implicitConvTo(t1b) > MATCH.nomatch) 2535 { 2536 Expression e1x = e.e1.implicitCastTo(sc, t1b); 2537 assert(e1x.op != TOK.error); 2538 e = cast(SliceExp)e.copy(); 2539 e.e1 = e1x; 2540 e.type = t; 2541 result = e; 2542 return; 2543 } 2544 } 2545 auto ts = toAutoQualChars(tsa ? tsa : e.type, t); 2546 e.error("cannot cast expression `%s` of type `%s` to `%s`", 2547 e.toChars(), ts[0], ts[1]); 2548 result = new ErrorExp(); 2549 } 2550 } 2551 2552 scope CastTo v = new CastTo(sc, t); 2553 e.accept(v); 2554 return v.result; 2555 } 2556 2557 /**************************************** 2558 * Set type inference target 2559 * t Target type 2560 * flag 1: don't put an error when inference fails 2561 */ 2562 Expression inferType(Expression e, Type t, int flag = 0) 2563 { 2564 Expression visitAle(ArrayLiteralExp ale) 2565 { 2566 Type tb = t.toBasetype(); 2567 if (tb.ty == Tarray || tb.ty == Tsarray) 2568 { 2569 Type tn = tb.nextOf(); 2570 if (ale.basis) 2571 ale.basis = inferType(ale.basis, tn, flag); 2572 for (size_t i = 0; i < ale.elements.dim; i++) 2573 { 2574 if (Expression e = (*ale.elements)[i]) 2575 { 2576 e = inferType(e, tn, flag); 2577 (*ale.elements)[i] = e; 2578 } 2579 } 2580 } 2581 return ale; 2582 } 2583 2584 Expression visitAar(AssocArrayLiteralExp aale) 2585 { 2586 Type tb = t.toBasetype(); 2587 if (tb.ty == Taarray) 2588 { 2589 TypeAArray taa = cast(TypeAArray)tb; 2590 Type ti = taa.index; 2591 Type tv = taa.nextOf(); 2592 for (size_t i = 0; i < aale.keys.dim; i++) 2593 { 2594 if (Expression e = (*aale.keys)[i]) 2595 { 2596 e = inferType(e, ti, flag); 2597 (*aale.keys)[i] = e; 2598 } 2599 } 2600 for (size_t i = 0; i < aale.values.dim; i++) 2601 { 2602 if (Expression e = (*aale.values)[i]) 2603 { 2604 e = inferType(e, tv, flag); 2605 (*aale.values)[i] = e; 2606 } 2607 } 2608 } 2609 return aale; 2610 } 2611 2612 Expression visitFun(FuncExp fe) 2613 { 2614 //printf("FuncExp::inferType('%s'), to=%s\n", fe.type ? fe.type.toChars() : "null", t.toChars()); 2615 if (t.ty == Tdelegate || t.ty == Tpointer && t.nextOf().ty == Tfunction) 2616 { 2617 fe.fd.treq = t; 2618 } 2619 return fe; 2620 } 2621 2622 Expression visitTer(CondExp ce) 2623 { 2624 Type tb = t.toBasetype(); 2625 ce.e1 = inferType(ce.e1, tb, flag); 2626 ce.e2 = inferType(ce.e2, tb, flag); 2627 return ce; 2628 } 2629 2630 if (t) switch (e.op) 2631 { 2632 case TOK.arrayLiteral: return visitAle(cast(ArrayLiteralExp) e); 2633 case TOK.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e); 2634 case TOK.function_: return visitFun(cast(FuncExp) e); 2635 case TOK.question: return visitTer(cast(CondExp) e); 2636 default: 2637 } 2638 return e; 2639 } 2640 2641 /**************************************** 2642 * Scale addition/subtraction to/from pointer. 2643 */ 2644 Expression scaleFactor(BinExp be, Scope* sc) 2645 { 2646 Type t1b = be.e1.type.toBasetype(); 2647 Type t2b = be.e2.type.toBasetype(); 2648 Expression eoff; 2649 2650 if (t1b.ty == Tpointer && t2b.isintegral()) 2651 { 2652 // Need to adjust operator by the stride 2653 // Replace (ptr + int) with (ptr + (int * stride)) 2654 Type t = Type.tptrdiff_t; 2655 2656 d_uns64 stride = t1b.nextOf().size(be.loc); 2657 if (!t.equals(t2b)) 2658 be.e2 = be.e2.castTo(sc, t); 2659 eoff = be.e2; 2660 be.e2 = new MulExp(be.loc, be.e2, new IntegerExp(Loc.initial, stride, t)); 2661 be.e2.type = t; 2662 be.type = be.e1.type; 2663 } 2664 else if (t2b.ty == Tpointer && t1b.isintegral()) 2665 { 2666 // Need to adjust operator by the stride 2667 // Replace (int + ptr) with (ptr + (int * stride)) 2668 Type t = Type.tptrdiff_t; 2669 Expression e; 2670 2671 d_uns64 stride = t2b.nextOf().size(be.loc); 2672 if (!t.equals(t1b)) 2673 e = be.e1.castTo(sc, t); 2674 else 2675 e = be.e1; 2676 eoff = e; 2677 e = new MulExp(be.loc, e, new IntegerExp(Loc.initial, stride, t)); 2678 e.type = t; 2679 be.type = be.e2.type; 2680 be.e1 = be.e2; 2681 be.e2 = e; 2682 } 2683 else 2684 assert(0); 2685 2686 if (sc.func && !sc.intypeof) 2687 { 2688 eoff = eoff.optimize(WANTvalue); 2689 if (eoff.op == TOK.int64 && eoff.toInteger() == 0) 2690 { 2691 } 2692 else if (sc.func.setUnsafe()) 2693 { 2694 be.error("pointer arithmetic not allowed in @safe functions"); 2695 return new ErrorExp(); 2696 } 2697 } 2698 2699 return be; 2700 } 2701 2702 /************************************** 2703 * Return true if e is an empty array literal with dimensionality 2704 * equal to or less than type of other array. 2705 * [], [[]], [[[]]], etc. 2706 * I.e., make sure that [1,2] is compatible with [], 2707 * [[1,2]] is compatible with [[]], etc. 2708 */ 2709 private bool isVoidArrayLiteral(Expression e, Type other) 2710 { 2711 while (e.op == TOK.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1)) 2712 { 2713 auto ale = cast(ArrayLiteralExp)e; 2714 e = ale[0]; 2715 if (other.ty == Tsarray || other.ty == Tarray) 2716 other = other.nextOf(); 2717 else 2718 return false; 2719 } 2720 if (other.ty != Tsarray && other.ty != Tarray) 2721 return false; 2722 Type t = e.type; 2723 return (e.op == TOK.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0); 2724 } 2725 2726 /************************************** 2727 * Combine types. 2728 * Output: 2729 * *pt merged type, if *pt is not NULL 2730 * *pe1 rewritten e1 2731 * *pe2 rewritten e2 2732 * Returns: 2733 * true success 2734 * false failed 2735 */ 2736 bool typeMerge(Scope* sc, TOK op, Type* pt, Expression* pe1, Expression* pe2) 2737 { 2738 //printf("typeMerge() %s op %s\n", pe1.toChars(), pe2.toChars()); 2739 2740 MATCH m; 2741 Expression e1 = *pe1; 2742 Expression e2 = *pe2; 2743 2744 Type t1 = e1.type; 2745 Type t2 = e2.type; 2746 2747 Type t1b = e1.type.toBasetype(); 2748 Type t2b = e2.type.toBasetype(); 2749 2750 Type t; 2751 2752 bool Lret() 2753 { 2754 if (!*pt) 2755 *pt = t; 2756 *pe1 = e1; 2757 *pe2 = e2; 2758 2759 version (none) 2760 { 2761 printf("-typeMerge() %s op %s\n", e1.toChars(), e2.toChars()); 2762 if (e1.type) 2763 printf("\tt1 = %s\n", e1.type.toChars()); 2764 if (e2.type) 2765 printf("\tt2 = %s\n", e2.type.toChars()); 2766 printf("\ttype = %s\n", t.toChars()); 2767 } 2768 return true; 2769 } 2770 2771 bool Lt1() 2772 { 2773 e2 = e2.castTo(sc, t1); 2774 t = t1; 2775 return Lret(); 2776 } 2777 2778 bool Lt2() 2779 { 2780 e1 = e1.castTo(sc, t2); 2781 t = t2; 2782 return Lret(); 2783 } 2784 2785 bool Lincompatible() { return false; } 2786 2787 if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic())) 2788 { 2789 if (op == TOK.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar()) 2790 { 2791 e1 = e1.castTo(sc, Type.tdchar); 2792 e2 = e2.castTo(sc, Type.tdchar); 2793 } 2794 else 2795 { 2796 e1 = integralPromotions(e1, sc); 2797 e2 = integralPromotions(e2, sc); 2798 } 2799 } 2800 2801 t1 = e1.type; 2802 t2 = e2.type; 2803 assert(t1); 2804 t = t1; 2805 2806 /* The start type of alias this type recursion. 2807 * In following case, we should save A, and stop recursion 2808 * if it appears again. 2809 * X -> Y -> [A] -> B -> A -> B -> ... 2810 */ 2811 Type att1 = null; 2812 Type att2 = null; 2813 2814 //if (t1) printf("\tt1 = %s\n", t1.toChars()); 2815 //if (t2) printf("\tt2 = %s\n", t2.toChars()); 2816 debug 2817 { 2818 if (!t2) 2819 printf("\te2 = '%s'\n", e2.toChars()); 2820 } 2821 assert(t2); 2822 2823 if (t1.mod != t2.mod && 2824 t1.ty == Tenum && t2.ty == Tenum && 2825 (cast(TypeEnum)t1).sym == (cast(TypeEnum)t2).sym) 2826 { 2827 ubyte mod = MODmerge(t1.mod, t2.mod); 2828 t1 = t1.castMod(mod); 2829 t2 = t2.castMod(mod); 2830 } 2831 2832 Lagain: 2833 t1b = t1.toBasetype(); 2834 t2b = t2.toBasetype(); 2835 2836 TY ty = cast(TY)impcnvResult[t1b.ty][t2b.ty]; 2837 if (ty != Terror) 2838 { 2839 TY ty1 = cast(TY)impcnvType1[t1b.ty][t2b.ty]; 2840 TY ty2 = cast(TY)impcnvType2[t1b.ty][t2b.ty]; 2841 2842 if (t1b.ty == ty1) // if no promotions 2843 { 2844 if (t1.equals(t2)) 2845 { 2846 t = t1; 2847 return Lret(); 2848 } 2849 2850 if (t1b.equals(t2b)) 2851 { 2852 t = t1b; 2853 return Lret(); 2854 } 2855 } 2856 2857 t = Type.basic[ty]; 2858 2859 t1 = Type.basic[ty1]; 2860 t2 = Type.basic[ty2]; 2861 e1 = e1.castTo(sc, t1); 2862 e2 = e2.castTo(sc, t2); 2863 return Lret(); 2864 } 2865 2866 t1 = t1b; 2867 t2 = t2b; 2868 2869 if (t1.ty == Ttuple || t2.ty == Ttuple) 2870 return Lincompatible(); 2871 2872 if (t1.equals(t2)) 2873 { 2874 // merging can not result in new enum type 2875 if (t.ty == Tenum) 2876 t = t1b; 2877 } 2878 else if ((t1.ty == Tpointer && t2.ty == Tpointer) || (t1.ty == Tdelegate && t2.ty == Tdelegate)) 2879 { 2880 // Bring pointers to compatible type 2881 Type t1n = t1.nextOf(); 2882 Type t2n = t2.nextOf(); 2883 2884 if (t1n.equals(t2n)) 2885 { 2886 } 2887 else if (t1n.ty == Tvoid) // pointers to void are always compatible 2888 t = t2; 2889 else if (t2n.ty == Tvoid) 2890 { 2891 } 2892 else if (t1.implicitConvTo(t2)) 2893 { 2894 return Lt2(); 2895 } 2896 else if (t2.implicitConvTo(t1)) 2897 { 2898 return Lt1(); 2899 } 2900 else if (t1n.ty == Tfunction && t2n.ty == Tfunction) 2901 { 2902 TypeFunction tf1 = cast(TypeFunction)t1n; 2903 TypeFunction tf2 = cast(TypeFunction)t2n; 2904 tf1.purityLevel(); 2905 tf2.purityLevel(); 2906 2907 TypeFunction d = cast(TypeFunction)tf1.syntaxCopy(); 2908 2909 if (tf1.purity != tf2.purity) 2910 d.purity = PURE.impure; 2911 assert(d.purity != PURE.fwdref); 2912 2913 d.isnothrow = (tf1.isnothrow && tf2.isnothrow); 2914 d.isnogc = (tf1.isnogc && tf2.isnogc); 2915 2916 if (tf1.trust == tf2.trust) 2917 d.trust = tf1.trust; 2918 else if (tf1.trust <= TRUST.system || tf2.trust <= TRUST.system) 2919 d.trust = TRUST.system; 2920 else 2921 d.trust = TRUST.trusted; 2922 2923 Type tx = null; 2924 if (t1.ty == Tdelegate) 2925 { 2926 tx = new TypeDelegate(d); 2927 } 2928 else 2929 tx = d.pointerTo(); 2930 2931 tx = tx.typeSemantic(e1.loc, sc); 2932 2933 if (t1.implicitConvTo(tx) && t2.implicitConvTo(tx)) 2934 { 2935 t = tx; 2936 e1 = e1.castTo(sc, t); 2937 e2 = e2.castTo(sc, t); 2938 return Lret(); 2939 } 2940 return Lincompatible(); 2941 } 2942 else if (t1n.mod != t2n.mod) 2943 { 2944 if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared()) 2945 return Lincompatible(); 2946 ubyte mod = MODmerge(t1n.mod, t2n.mod); 2947 t1 = t1n.castMod(mod).pointerTo(); 2948 t2 = t2n.castMod(mod).pointerTo(); 2949 t = t1; 2950 goto Lagain; 2951 } 2952 else if (t1n.ty == Tclass && t2n.ty == Tclass) 2953 { 2954 ClassDeclaration cd1 = t1n.isClassHandle(); 2955 ClassDeclaration cd2 = t2n.isClassHandle(); 2956 int offset; 2957 if (cd1.isBaseOf(cd2, &offset)) 2958 { 2959 if (offset) 2960 e2 = e2.castTo(sc, t); 2961 } 2962 else if (cd2.isBaseOf(cd1, &offset)) 2963 { 2964 t = t2; 2965 if (offset) 2966 e1 = e1.castTo(sc, t); 2967 } 2968 else 2969 return Lincompatible(); 2970 } 2971 else 2972 { 2973 t1 = t1n.constOf().pointerTo(); 2974 t2 = t2n.constOf().pointerTo(); 2975 if (t1.implicitConvTo(t2)) 2976 { 2977 return Lt2(); 2978 } 2979 else if (t2.implicitConvTo(t1)) 2980 { 2981 return Lt1(); 2982 } 2983 return Lincompatible(); 2984 } 2985 } 2986 else if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && (cast(TypeSArray)t2).dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1))) 2987 { 2988 /* (T[n] op void*) => T[] 2989 * (T[] op void*) => T[] 2990 * (T[n] op void[0]) => T[] 2991 * (T[] op void[0]) => T[] 2992 * (T[n] op void[]) => T[] 2993 * (T[] op void[]) => T[] 2994 */ 2995 goto Lx1; 2996 } 2997 else if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && (cast(TypeSArray)t1).dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2))) 2998 { 2999 /* (void* op T[n]) => T[] 3000 * (void* op T[]) => T[] 3001 * (void[0] op T[n]) => T[] 3002 * (void[0] op T[]) => T[] 3003 * (void[] op T[n]) => T[] 3004 * (void[] op T[]) => T[] 3005 */ 3006 goto Lx2; 3007 } 3008 else if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch) 3009 { 3010 // https://issues.dlang.org/show_bug.cgi?id=7285 3011 // Tsarray op [x, y, ...] should to be Tsarray 3012 // https://issues.dlang.org/show_bug.cgi?id=14737 3013 // Tsarray ~ [x, y, ...] should to be Tarray 3014 if (t1.ty == Tsarray && e2.op == TOK.arrayLiteral && op != TOK.concatenate) 3015 return Lt1(); 3016 if (m == MATCH.constant && (op == TOK.addAssign || op == TOK.minAssign || op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign || op == TOK.powAssign || op == TOK.andAssign || op == TOK.orAssign || op == TOK.xorAssign)) 3017 { 3018 // Don't make the lvalue const 3019 t = t2; 3020 return Lret(); 3021 } 3022 return Lt2(); 3023 } 3024 else if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1)) 3025 { 3026 // https://issues.dlang.org/show_bug.cgi?id=7285 3027 // https://issues.dlang.org/show_bug.cgi?id=14737 3028 if (t2.ty == Tsarray && e1.op == TOK.arrayLiteral && op != TOK.concatenate) 3029 return Lt2(); 3030 return Lt1(); 3031 } 3032 else if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod) 3033 { 3034 /* If one is mutable and the other invariant, then retry 3035 * with both of them as const 3036 */ 3037 Type t1n = t1.nextOf(); 3038 Type t2n = t2.nextOf(); 3039 ubyte mod; 3040 if (e1.op == TOK.null_ && e2.op != TOK.null_) 3041 mod = t2n.mod; 3042 else if (e1.op != TOK.null_ && e2.op == TOK.null_) 3043 mod = t1n.mod; 3044 else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared()) 3045 return Lincompatible(); 3046 else 3047 mod = MODmerge(t1n.mod, t2n.mod); 3048 3049 if (t1.ty == Tpointer) 3050 t1 = t1n.castMod(mod).pointerTo(); 3051 else 3052 t1 = t1n.castMod(mod).arrayOf(); 3053 3054 if (t2.ty == Tpointer) 3055 t2 = t2n.castMod(mod).pointerTo(); 3056 else 3057 t2 = t2n.castMod(mod).arrayOf(); 3058 t = t1; 3059 goto Lagain; 3060 } 3061 else if (t1.ty == Tclass && t2.ty == Tclass) 3062 { 3063 if (t1.mod != t2.mod) 3064 { 3065 ubyte mod; 3066 if (e1.op == TOK.null_ && e2.op != TOK.null_) 3067 mod = t2.mod; 3068 else if (e1.op != TOK.null_ && e2.op == TOK.null_) 3069 mod = t1.mod; 3070 else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) 3071 return Lincompatible(); 3072 else 3073 mod = MODmerge(t1.mod, t2.mod); 3074 t1 = t1.castMod(mod); 3075 t2 = t2.castMod(mod); 3076 t = t1; 3077 goto Lagain; 3078 } 3079 goto Lcc; 3080 } 3081 else if (t1.ty == Tclass || t2.ty == Tclass) 3082 { 3083 Lcc: 3084 while (1) 3085 { 3086 MATCH i1 = e2.implicitConvTo(t1); 3087 MATCH i2 = e1.implicitConvTo(t2); 3088 3089 if (i1 && i2) 3090 { 3091 // We have the case of class vs. void*, so pick class 3092 if (t1.ty == Tpointer) 3093 i1 = MATCH.nomatch; 3094 else if (t2.ty == Tpointer) 3095 i2 = MATCH.nomatch; 3096 } 3097 3098 if (i2) 3099 { 3100 e2 = e2.castTo(sc, t2); 3101 return Lt2(); 3102 } 3103 else if (i1) 3104 { 3105 e1 = e1.castTo(sc, t1); 3106 return Lt1(); 3107 } 3108 else if (t1.ty == Tclass && t2.ty == Tclass) 3109 { 3110 TypeClass tc1 = cast(TypeClass)t1; 3111 TypeClass tc2 = cast(TypeClass)t2; 3112 3113 /* Pick 'tightest' type 3114 */ 3115 ClassDeclaration cd1 = tc1.sym.baseClass; 3116 ClassDeclaration cd2 = tc2.sym.baseClass; 3117 if (cd1 && cd2) 3118 { 3119 t1 = cd1.type.castMod(t1.mod); 3120 t2 = cd2.type.castMod(t2.mod); 3121 } 3122 else if (cd1) 3123 t1 = cd1.type; 3124 else if (cd2) 3125 t2 = cd2.type; 3126 else 3127 return Lincompatible(); 3128 } 3129 else if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis) 3130 { 3131 if (att1 && e1.type == att1) 3132 return Lincompatible(); 3133 if (!att1 && e1.type.checkAliasThisRec()) 3134 att1 = e1.type; 3135 //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars()); 3136 e1 = resolveAliasThis(sc, e1); 3137 t1 = e1.type; 3138 continue; 3139 } 3140 else if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis) 3141 { 3142 if (att2 && e2.type == att2) 3143 return Lincompatible(); 3144 if (!att2 && e2.type.checkAliasThisRec()) 3145 att2 = e2.type; 3146 //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars()); 3147 e2 = resolveAliasThis(sc, e2); 3148 t2 = e2.type; 3149 continue; 3150 } 3151 else 3152 return Lincompatible(); 3153 } 3154 } 3155 else if (t1.ty == Tstruct && t2.ty == Tstruct) 3156 { 3157 if (t1.mod != t2.mod) 3158 { 3159 if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) 3160 return Lincompatible(); 3161 ubyte mod = MODmerge(t1.mod, t2.mod); 3162 t1 = t1.castMod(mod); 3163 t2 = t2.castMod(mod); 3164 t = t1; 3165 goto Lagain; 3166 } 3167 3168 TypeStruct ts1 = cast(TypeStruct)t1; 3169 TypeStruct ts2 = cast(TypeStruct)t2; 3170 if (ts1.sym != ts2.sym) 3171 { 3172 if (!ts1.sym.aliasthis && !ts2.sym.aliasthis) 3173 return Lincompatible(); 3174 3175 MATCH i1 = MATCH.nomatch; 3176 MATCH i2 = MATCH.nomatch; 3177 3178 Expression e1b = null; 3179 Expression e2b = null; 3180 if (ts2.sym.aliasthis) 3181 { 3182 if (att2 && e2.type == att2) 3183 return Lincompatible(); 3184 if (!att2 && e2.type.checkAliasThisRec()) 3185 att2 = e2.type; 3186 //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars()); 3187 e2b = resolveAliasThis(sc, e2); 3188 i1 = e2b.implicitConvTo(t1); 3189 } 3190 if (ts1.sym.aliasthis) 3191 { 3192 if (att1 && e1.type == att1) 3193 return Lincompatible(); 3194 if (!att1 && e1.type.checkAliasThisRec()) 3195 att1 = e1.type; 3196 //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars()); 3197 e1b = resolveAliasThis(sc, e1); 3198 i2 = e1b.implicitConvTo(t2); 3199 } 3200 if (i1 && i2) 3201 return Lincompatible(); 3202 3203 if (i1) 3204 return Lt1(); 3205 else if (i2) 3206 return Lt2(); 3207 3208 if (e1b) 3209 { 3210 e1 = e1b; 3211 t1 = e1b.type.toBasetype(); 3212 } 3213 if (e2b) 3214 { 3215 e2 = e2b; 3216 t2 = e2b.type.toBasetype(); 3217 } 3218 t = t1; 3219 goto Lagain; 3220 } 3221 } 3222 else if (t1.ty == Tstruct || t2.ty == Tstruct) 3223 { 3224 if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis) 3225 { 3226 if (att1 && e1.type == att1) 3227 return Lincompatible(); 3228 if (!att1 && e1.type.checkAliasThisRec()) 3229 att1 = e1.type; 3230 //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars()); 3231 e1 = resolveAliasThis(sc, e1); 3232 t1 = e1.type; 3233 t = t1; 3234 goto Lagain; 3235 } 3236 if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis) 3237 { 3238 if (att2 && e2.type == att2) 3239 return Lincompatible(); 3240 if (!att2 && e2.type.checkAliasThisRec()) 3241 att2 = e2.type; 3242 //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars()); 3243 e2 = resolveAliasThis(sc, e2); 3244 t2 = e2.type; 3245 t = t2; 3246 goto Lagain; 3247 } 3248 return Lincompatible(); 3249 } 3250 else if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2)) 3251 { 3252 return Lt2(); 3253 } 3254 else if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1)) 3255 { 3256 return Lt1(); 3257 } 3258 else if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf())) 3259 { 3260 Lx1: 3261 t = t1.nextOf().arrayOf(); // T[] 3262 e1 = e1.castTo(sc, t); 3263 e2 = e2.castTo(sc, t); 3264 } 3265 else if (t1.ty == Tsarray && t2.ty == Tsarray && e1.implicitConvTo(t2.nextOf().arrayOf())) 3266 { 3267 Lx2: 3268 t = t2.nextOf().arrayOf(); 3269 e1 = e1.castTo(sc, t); 3270 e2 = e2.castTo(sc, t); 3271 } 3272 else if (t1.ty == Tvector && t2.ty == Tvector) 3273 { 3274 // https://issues.dlang.org/show_bug.cgi?id=13841 3275 // all vector types should have no common types between 3276 // different vectors, even though their sizes are same. 3277 auto tv1 = cast(TypeVector)t1; 3278 auto tv2 = cast(TypeVector)t2; 3279 if (!tv1.basetype.equals(tv2.basetype)) 3280 return Lincompatible(); 3281 3282 goto LmodCompare; 3283 } 3284 else if (t1.ty == Tvector && t2.ty != Tvector && e2.implicitConvTo(t1)) 3285 { 3286 e2 = e2.castTo(sc, t1); 3287 t2 = t1; 3288 t = t1; 3289 goto Lagain; 3290 } 3291 else if (t2.ty == Tvector && t1.ty != Tvector && e1.implicitConvTo(t2)) 3292 { 3293 e1 = e1.castTo(sc, t2); 3294 t1 = t2; 3295 t = t1; 3296 goto Lagain; 3297 } 3298 else if (t1.isintegral() && t2.isintegral()) 3299 { 3300 if (t1.ty != t2.ty) 3301 { 3302 if (t1.ty == Tvector || t2.ty == Tvector) 3303 return Lincompatible(); 3304 e1 = integralPromotions(e1, sc); 3305 e2 = integralPromotions(e2, sc); 3306 t1 = e1.type; 3307 t2 = e2.type; 3308 goto Lagain; 3309 } 3310 assert(t1.ty == t2.ty); 3311 LmodCompare: 3312 if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) 3313 return Lincompatible(); 3314 ubyte mod = MODmerge(t1.mod, t2.mod); 3315 3316 t1 = t1.castMod(mod); 3317 t2 = t2.castMod(mod); 3318 t = t1; 3319 e1 = e1.castTo(sc, t); 3320 e2 = e2.castTo(sc, t); 3321 goto Lagain; 3322 } 3323 else if (t1.ty == Tnull && t2.ty == Tnull) 3324 { 3325 ubyte mod = MODmerge(t1.mod, t2.mod); 3326 3327 t = t1.castMod(mod); 3328 e1 = e1.castTo(sc, t); 3329 e2 = e2.castTo(sc, t); 3330 return Lret(); 3331 } 3332 else if (t2.ty == Tnull && (t1.ty == Tpointer || t1.ty == Taarray || t1.ty == Tarray)) 3333 { 3334 return Lt1(); 3335 } 3336 else if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray)) 3337 { 3338 return Lt2(); 3339 } 3340 else if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1)) 3341 { 3342 if (e2.implicitConvTo(t1.nextOf())) 3343 { 3344 // T[] op T 3345 // T[] op cast(T)U 3346 e2 = e2.castTo(sc, t1.nextOf()); 3347 t = t1.nextOf().arrayOf(); 3348 } 3349 else if (t1.nextOf().implicitConvTo(e2.type)) 3350 { 3351 // (cast(T)U)[] op T (https://issues.dlang.org/show_bug.cgi?id=12780) 3352 // e1 is left as U[], it will be handled in arrayOp() later. 3353 t = e2.type.arrayOf(); 3354 } 3355 else if (t2.ty == Tarray && isArrayOpOperand(e2)) 3356 { 3357 if (t1.nextOf().implicitConvTo(t2.nextOf())) 3358 { 3359 // (cast(T)U)[] op T[] (https://issues.dlang.org/show_bug.cgi?id=12780) 3360 t = t2.nextOf().arrayOf(); 3361 // if cast won't be handled in arrayOp() later 3362 if (!isArrayOpImplicitCast(t1.isTypeDArray(), t2.isTypeDArray())) 3363 e1 = e1.castTo(sc, t); 3364 } 3365 else if (t2.nextOf().implicitConvTo(t1.nextOf())) 3366 { 3367 // T[] op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780) 3368 // e2 is left as U[], it will be handled in arrayOp() later. 3369 t = t1.nextOf().arrayOf(); 3370 // if cast won't be handled in arrayOp() later 3371 if (!isArrayOpImplicitCast(t2.isTypeDArray(), t1.isTypeDArray())) 3372 e2 = e2.castTo(sc, t); 3373 } 3374 else 3375 return Lincompatible(); 3376 } 3377 else 3378 return Lincompatible(); 3379 } 3380 else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2)) 3381 { 3382 if (e1.implicitConvTo(t2.nextOf())) 3383 { 3384 // T op T[] 3385 // cast(T)U op T[] 3386 e1 = e1.castTo(sc, t2.nextOf()); 3387 t = t2.nextOf().arrayOf(); 3388 } 3389 else if (t2.nextOf().implicitConvTo(e1.type)) 3390 { 3391 // T op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780) 3392 // e2 is left as U[], it will be handled in arrayOp() later. 3393 t = e1.type.arrayOf(); 3394 } 3395 else 3396 return Lincompatible(); 3397 3398 //printf("test %s\n", Token::toChars(op)); 3399 e1 = e1.optimize(WANTvalue); 3400 if (isCommutative(op) && e1.isConst()) 3401 { 3402 /* Swap operands to minimize number of functions generated 3403 */ 3404 //printf("swap %s\n", Token::toChars(op)); 3405 Expression tmp = e1; 3406 e1 = e2; 3407 e2 = tmp; 3408 } 3409 } 3410 else 3411 { 3412 return Lincompatible(); 3413 } 3414 return Lret(); 3415 } 3416 3417 /************************************ 3418 * Bring leaves to common type. 3419 * Returns: 3420 * null on success, ErrorExp if error occurs 3421 */ 3422 Expression typeCombine(BinExp be, Scope* sc) 3423 { 3424 Expression errorReturn() 3425 { 3426 Expression ex = be.incompatibleTypes(); 3427 if (ex.op == TOK.error) 3428 return ex; 3429 return new ErrorExp(); 3430 } 3431 3432 Type t1 = be.e1.type.toBasetype(); 3433 Type t2 = be.e2.type.toBasetype(); 3434 3435 if (be.op == TOK.min || be.op == TOK.add) 3436 { 3437 // struct+struct, and class+class are errors 3438 if (t1.ty == Tstruct && t2.ty == Tstruct) 3439 return errorReturn(); 3440 else if (t1.ty == Tclass && t2.ty == Tclass) 3441 return errorReturn(); 3442 else if (t1.ty == Taarray && t2.ty == Taarray) 3443 return errorReturn(); 3444 } 3445 3446 if (!typeMerge(sc, be.op, &be.type, &be.e1, &be.e2)) 3447 return errorReturn(); 3448 3449 // If the types have no value, return an error 3450 if (be.e1.op == TOK.error) 3451 return be.e1; 3452 if (be.e2.op == TOK.error) 3453 return be.e2; 3454 return null; 3455 } 3456 3457 /*********************************** 3458 * Do integral promotions (convertchk). 3459 * Don't convert <array of> to <pointer to> 3460 */ 3461 Expression integralPromotions(Expression e, Scope* sc) 3462 { 3463 //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars()); 3464 switch (e.type.toBasetype().ty) 3465 { 3466 case Tvoid: 3467 e.error("void has no value"); 3468 return new ErrorExp(); 3469 3470 case Tint8: 3471 case Tuns8: 3472 case Tint16: 3473 case Tuns16: 3474 case Tbool: 3475 case Tchar: 3476 case Twchar: 3477 e = e.castTo(sc, Type.tint32); 3478 break; 3479 3480 case Tdchar: 3481 e = e.castTo(sc, Type.tuns32); 3482 break; 3483 3484 default: 3485 break; 3486 } 3487 return e; 3488 } 3489 3490 /****************************************************** 3491 * This provides a transition from the non-promoting behavior 3492 * of unary + - ~ to the C-like integral promotion behavior. 3493 * Params: 3494 * sc = context 3495 * ue = NegExp, UAddExp, or ComExp which is revised per rules 3496 * References: 3497 * https://issues.dlang.org/show_bug.cgi?id=16997 3498 */ 3499 3500 void fix16997(Scope* sc, UnaExp ue) 3501 { 3502 if (global.params.fix16997) 3503 ue.e1 = integralPromotions(ue.e1, sc); // desired C-like behavor 3504 else 3505 { 3506 switch (ue.e1.type.toBasetype.ty) 3507 { 3508 case Tint8: 3509 case Tuns8: 3510 case Tint16: 3511 case Tuns16: 3512 //case Tbool: // these operations aren't allowed on bool anyway 3513 case Tchar: 3514 case Twchar: 3515 case Tdchar: 3516 ue.deprecation("integral promotion not done for `%s`, use '-preview=intpromote' switch or `%scast(int)(%s)`", 3517 ue.toChars(), Token.toChars(ue.op), ue.e1.toChars()); 3518 break; 3519 3520 default: 3521 break; 3522 } 3523 } 3524 } 3525 3526 /*********************************** 3527 * See if both types are arrays that can be compared 3528 * for equality. Return true if so. 3529 * If they are arrays, but incompatible, issue error. 3530 * This is to enable comparing things like an immutable 3531 * array with a mutable one. 3532 */ 3533 extern (C++) bool arrayTypeCompatible(Loc loc, Type t1, Type t2) 3534 { 3535 t1 = t1.toBasetype().merge2(); 3536 t2 = t2.toBasetype().merge2(); 3537 3538 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) 3539 { 3540 if (t1.nextOf().implicitConvTo(t2.nextOf()) < MATCH.constant && t2.nextOf().implicitConvTo(t1.nextOf()) < MATCH.constant && (t1.nextOf().ty != Tvoid && t2.nextOf().ty != Tvoid)) 3541 { 3542 error(loc, "array equality comparison type mismatch, `%s` vs `%s`", t1.toChars(), t2.toChars()); 3543 } 3544 return true; 3545 } 3546 return false; 3547 } 3548 3549 /*********************************** 3550 * See if both types are arrays that can be compared 3551 * for equality without any casting. Return true if so. 3552 * This is to enable comparing things like an immutable 3553 * array with a mutable one. 3554 */ 3555 extern (C++) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2) 3556 { 3557 t1 = t1.toBasetype(); 3558 t2 = t2.toBasetype(); 3559 3560 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && t2.ty == t1.ty) 3561 { 3562 if (t1.nextOf().implicitConvTo(t2.nextOf()) >= MATCH.constant || t2.nextOf().implicitConvTo(t1.nextOf()) >= MATCH.constant) 3563 return true; 3564 } 3565 return false; 3566 } 3567 3568 /******************************************************************/ 3569 /* Determine the integral ranges of an expression. 3570 * This is used to determine if implicit narrowing conversions will 3571 * be allowed. 3572 */ 3573 IntRange getIntRange(Expression e) 3574 { 3575 extern (C++) final class IntRangeVisitor : Visitor 3576 { 3577 alias visit = Visitor.visit; 3578 3579 public: 3580 IntRange range; 3581 3582 override void visit(Expression e) 3583 { 3584 range = IntRange.fromType(e.type); 3585 } 3586 3587 override void visit(IntegerExp e) 3588 { 3589 range = IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type); 3590 } 3591 3592 override void visit(CastExp e) 3593 { 3594 range = getIntRange(e.e1)._cast(e.type); 3595 } 3596 3597 override void visit(AddExp e) 3598 { 3599 IntRange ir1 = getIntRange(e.e1); 3600 IntRange ir2 = getIntRange(e.e2); 3601 range = (ir1 + ir2)._cast(e.type); 3602 } 3603 3604 override void visit(MinExp e) 3605 { 3606 IntRange ir1 = getIntRange(e.e1); 3607 IntRange ir2 = getIntRange(e.e2); 3608 range = (ir1 - ir2)._cast(e.type); 3609 } 3610 3611 override void visit(DivExp e) 3612 { 3613 IntRange ir1 = getIntRange(e.e1); 3614 IntRange ir2 = getIntRange(e.e2); 3615 3616 range = (ir1 / ir2)._cast(e.type); 3617 } 3618 3619 override void visit(MulExp e) 3620 { 3621 IntRange ir1 = getIntRange(e.e1); 3622 IntRange ir2 = getIntRange(e.e2); 3623 3624 range = (ir1 * ir2)._cast(e.type); 3625 } 3626 3627 override void visit(ModExp e) 3628 { 3629 IntRange ir1 = getIntRange(e.e1); 3630 IntRange ir2 = getIntRange(e.e2); 3631 3632 // Modding on 0 is invalid anyway. 3633 if (!ir2.absNeg().imin.negative) 3634 { 3635 visit(cast(Expression)e); 3636 return; 3637 } 3638 range = (ir1 % ir2)._cast(e.type); 3639 } 3640 3641 override void visit(AndExp e) 3642 { 3643 IntRange result; 3644 bool hasResult = false; 3645 result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult); 3646 3647 assert(hasResult); 3648 range = result._cast(e.type); 3649 } 3650 3651 override void visit(OrExp e) 3652 { 3653 IntRange result; 3654 bool hasResult = false; 3655 result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult); 3656 3657 assert(hasResult); 3658 range = result._cast(e.type); 3659 } 3660 3661 override void visit(XorExp e) 3662 { 3663 IntRange result; 3664 bool hasResult = false; 3665 result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult); 3666 3667 assert(hasResult); 3668 range = result._cast(e.type); 3669 } 3670 3671 override void visit(ShlExp e) 3672 { 3673 IntRange ir1 = getIntRange(e.e1); 3674 IntRange ir2 = getIntRange(e.e2); 3675 3676 range = (ir1 << ir2)._cast(e.type); 3677 } 3678 3679 override void visit(ShrExp e) 3680 { 3681 IntRange ir1 = getIntRange(e.e1); 3682 IntRange ir2 = getIntRange(e.e2); 3683 3684 range = (ir1 >> ir2)._cast(e.type); 3685 } 3686 3687 override void visit(UshrExp e) 3688 { 3689 IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type); 3690 IntRange ir2 = getIntRange(e.e2); 3691 3692 range = (ir1 >>> ir2)._cast(e.type); 3693 } 3694 3695 override void visit(AssignExp e) 3696 { 3697 range = getIntRange(e.e2)._cast(e.type); 3698 } 3699 3700 override void visit(CondExp e) 3701 { 3702 // No need to check e.econd; assume caller has called optimize() 3703 IntRange ir1 = getIntRange(e.e1); 3704 IntRange ir2 = getIntRange(e.e2); 3705 range = ir1.unionWith(ir2)._cast(e.type); 3706 } 3707 3708 override void visit(VarExp e) 3709 { 3710 Expression ie; 3711 VarDeclaration vd = e.var.isVarDeclaration(); 3712 if (vd && vd.range) 3713 range = vd.range._cast(e.type); 3714 else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null) 3715 ie.accept(this); 3716 else 3717 visit(cast(Expression)e); 3718 } 3719 3720 override void visit(CommaExp e) 3721 { 3722 e.e2.accept(this); 3723 } 3724 3725 override void visit(ComExp e) 3726 { 3727 IntRange ir = getIntRange(e.e1); 3728 range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type); 3729 } 3730 3731 override void visit(NegExp e) 3732 { 3733 IntRange ir = getIntRange(e.e1); 3734 range = (-ir)._cast(e.type); 3735 } 3736 } 3737 3738 scope IntRangeVisitor v = new IntRangeVisitor(); 3739 e.accept(v); 3740 return v.range; 3741 }