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