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