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