1 /** 2 * Defines a D type. 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/mtype.d, _mtype.d) 8 * Documentation: https://dlang.org/phobos/dmd_mtype.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mtype.d 10 */ 11 12 module dmd.mtype; 13 14 import core.checkedint; 15 import core.stdc.stdarg; 16 import core.stdc.stdio; 17 import core.stdc.stdlib; 18 import core.stdc.string; 19 20 import dmd.aggregate; 21 import dmd.arraytypes; 22 import dmd.attrib; 23 import dmd.astenums; 24 import dmd.ast_node; 25 import dmd.gluelayer; 26 import dmd.dclass; 27 import dmd.dcast; 28 import dmd.declaration; 29 import dmd.denum; 30 import dmd.dmangle; 31 import dmd.dscope; 32 import dmd.dstruct; 33 import dmd.dsymbol; 34 import dmd.dsymbolsem; 35 import dmd.dtemplate; 36 import dmd.errors; 37 import dmd.expression; 38 import dmd.expressionsem; 39 import dmd.func; 40 import dmd.globals; 41 import dmd.hdrgen; 42 import dmd.id; 43 import dmd.identifier; 44 import dmd.init; 45 import dmd.location; 46 import dmd.opover; 47 import dmd.root.ctfloat; 48 import dmd.common.outbuffer; 49 import dmd.root.rmem; 50 import dmd.rootobject; 51 import dmd.root.stringtable; 52 import dmd.target; 53 import dmd.tokens; 54 import dmd.typesem; 55 import dmd.visitor; 56 57 enum LOGDOTEXP = 0; // log ::dotExp() 58 enum LOGDEFAULTINIT = 0; // log ::defaultInit() 59 60 enum SIZE_INVALID = (~cast(uinteger_t)0); // error return from size() functions 61 62 63 /*************************** 64 * Return !=0 if modfrom can be implicitly converted to modto 65 */ 66 bool MODimplicitConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe 67 { 68 if (modfrom == modto) 69 return true; 70 71 //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto); 72 auto X(T, U)(T m, U n) 73 { 74 return ((m << 4) | n); 75 } 76 77 switch (X(modfrom & ~MODFlags.shared_, modto & ~MODFlags.shared_)) 78 { 79 case X(0, MODFlags.const_): 80 case X(MODFlags.wild, MODFlags.const_): 81 case X(MODFlags.wild, MODFlags.wildconst): 82 case X(MODFlags.wildconst, MODFlags.const_): 83 return (modfrom & MODFlags.shared_) == (modto & MODFlags.shared_); 84 85 case X(MODFlags.immutable_, MODFlags.const_): 86 case X(MODFlags.immutable_, MODFlags.wildconst): 87 return true; 88 default: 89 return false; 90 } 91 } 92 93 /*************************** 94 * Return MATCH.exact or MATCH.constant if a method of type '() modfrom' can call a method of type '() modto'. 95 */ 96 MATCH MODmethodConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe 97 { 98 if (modfrom == modto) 99 return MATCH.exact; 100 if (MODimplicitConv(modfrom, modto)) 101 return MATCH.constant; 102 103 auto X(T, U)(T m, U n) 104 { 105 return ((m << 4) | n); 106 } 107 108 switch (X(modfrom, modto)) 109 { 110 case X(0, MODFlags.wild): 111 case X(MODFlags.immutable_, MODFlags.wild): 112 case X(MODFlags.const_, MODFlags.wild): 113 case X(MODFlags.wildconst, MODFlags.wild): 114 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild): 115 case X(MODFlags.shared_ | MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild): 116 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): 117 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild): 118 return MATCH.constant; 119 120 default: 121 return MATCH.nomatch; 122 } 123 } 124 125 /*************************** 126 * Merge mod bits to form common mod. 127 */ 128 MOD MODmerge(MOD mod1, MOD mod2) pure nothrow @nogc @safe 129 { 130 if (mod1 == mod2) 131 return mod1; 132 133 //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2); 134 MOD result = 0; 135 if ((mod1 | mod2) & MODFlags.shared_) 136 { 137 // If either type is shared, the result will be shared 138 result |= MODFlags.shared_; 139 mod1 &= ~MODFlags.shared_; 140 mod2 &= ~MODFlags.shared_; 141 } 142 if (mod1 == 0 || mod1 == MODFlags.mutable || mod1 == MODFlags.const_ || mod2 == 0 || mod2 == MODFlags.mutable || mod2 == MODFlags.const_) 143 { 144 // If either type is mutable or const, the result will be const. 145 result |= MODFlags.const_; 146 } 147 else 148 { 149 // MODFlags.immutable_ vs MODFlags.wild 150 // MODFlags.immutable_ vs MODFlags.wildconst 151 // MODFlags.wild vs MODFlags.wildconst 152 assert(mod1 & MODFlags.wild || mod2 & MODFlags.wild); 153 result |= MODFlags.wildconst; 154 } 155 return result; 156 } 157 158 /********************************* 159 * Store modifier name into buf. 160 */ 161 void MODtoBuffer(ref OutBuffer buf, MOD mod) nothrow @safe 162 { 163 buf.writestring(MODtoString(mod)); 164 } 165 166 /********************************* 167 * Returns: 168 * a human readable representation of `mod`, 169 * which is the token `mod` corresponds to 170 */ 171 const(char)* MODtoChars(MOD mod) nothrow pure 172 { 173 /// Works because we return a literal 174 return MODtoString(mod).ptr; 175 } 176 177 /// Ditto 178 string MODtoString(MOD mod) nothrow pure @safe 179 { 180 final switch (mod) 181 { 182 case 0: 183 return ""; 184 185 case MODFlags.immutable_: 186 return "immutable"; 187 188 case MODFlags.shared_: 189 return "shared"; 190 191 case MODFlags.shared_ | MODFlags.const_: 192 return "shared const"; 193 194 case MODFlags.const_: 195 return "const"; 196 197 case MODFlags.shared_ | MODFlags.wild: 198 return "shared inout"; 199 200 case MODFlags.wild: 201 return "inout"; 202 203 case MODFlags.shared_ | MODFlags.wildconst: 204 return "shared inout const"; 205 206 case MODFlags.wildconst: 207 return "inout const"; 208 } 209 } 210 211 /************************************************* 212 * Pick off one of the trust flags from trust, 213 * and return a string representation of it. 214 */ 215 string trustToString(TRUST trust) pure nothrow @nogc @safe 216 { 217 final switch (trust) 218 { 219 case TRUST.default_: 220 return null; 221 case TRUST.system: 222 return "@system"; 223 case TRUST.trusted: 224 return "@trusted"; 225 case TRUST.safe: 226 return "@safe"; 227 } 228 } 229 230 unittest 231 { 232 assert(trustToString(TRUST.default_) == ""); 233 assert(trustToString(TRUST.system) == "@system"); 234 assert(trustToString(TRUST.trusted) == "@trusted"); 235 assert(trustToString(TRUST.safe) == "@safe"); 236 } 237 238 /************************************ 239 * Convert MODxxxx to STCxxx 240 */ 241 StorageClass ModToStc(uint mod) pure nothrow @nogc @safe 242 { 243 StorageClass stc = 0; 244 if (mod & MODFlags.immutable_) 245 stc |= STC.immutable_; 246 if (mod & MODFlags.const_) 247 stc |= STC.const_; 248 if (mod & MODFlags.wild) 249 stc |= STC.wild; 250 if (mod & MODFlags.shared_) 251 stc |= STC.shared_; 252 return stc; 253 } 254 255 ///Returns true if ty is char, wchar, or dchar 256 bool isSomeChar(TY ty) pure nothrow @nogc @safe 257 { 258 return ty == Tchar || ty == Twchar || ty == Tdchar; 259 } 260 261 /************************************ 262 * Determine mutability of indirections in (ref) t. 263 * 264 * Returns: When the type has any mutable indirections, returns 0. 265 * When all indirections are immutable, returns 2. 266 * Otherwise, when the type has const/inout indirections, returns 1. 267 * 268 * Params: 269 * isref = if true, check `ref t`; otherwise, check just `t` 270 * t = the type that is being checked 271 */ 272 int mutabilityOfType(bool isref, Type t) 273 { 274 if (isref) 275 { 276 if (t.mod & MODFlags.immutable_) 277 return 2; 278 if (t.mod & (MODFlags.const_ | MODFlags.wild)) 279 return 1; 280 return 0; 281 } 282 283 t = t.baseElemOf(); 284 285 if (!t.hasPointers() || t.mod & MODFlags.immutable_) 286 return 2; 287 288 /* Accept immutable(T)[] and immutable(T)* as being strongly pure 289 */ 290 if (t.ty == Tarray || t.ty == Tpointer) 291 { 292 Type tn = t.nextOf().toBasetype(); 293 if (tn.mod & MODFlags.immutable_) 294 return 2; 295 if (tn.mod & (MODFlags.const_ | MODFlags.wild)) 296 return 1; 297 } 298 299 /* The rest of this is too strict; fix later. 300 * For example, the only pointer members of a struct may be immutable, 301 * which would maintain strong purity. 302 * (Just like for dynamic arrays and pointers above.) 303 */ 304 if (t.mod & (MODFlags.const_ | MODFlags.wild)) 305 return 1; 306 307 /* Should catch delegates and function pointers, and fold in their purity 308 */ 309 return 0; 310 } 311 312 /**************** 313 * dotExp() bit flags 314 */ 315 enum DotExpFlag 316 { 317 none = 0, 318 gag = 1, // don't report "not a property" error and just return null 319 noDeref = 2, // the use of the expression will not attempt a dereference 320 noAliasThis = 4, // don't do 'alias this' resolution 321 } 322 323 /// Result of a check whether two types are covariant 324 enum Covariant 325 { 326 distinct = 0, /// types are distinct 327 yes = 1, /// types are covariant 328 no = 2, /// arguments match as far as overloading goes, but types are not covariant 329 fwdref = 3, /// cannot determine covariance because of forward references 330 } 331 332 /*********************************************************** 333 */ 334 extern (C++) abstract class Type : ASTNode 335 { 336 TY ty; 337 MOD mod; // modifiers MODxxxx 338 char* deco; 339 340 static struct Mcache 341 { 342 /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc. 343 * They should not be referenced by anybody but mtype.d. 344 * They can be null if not lazily evaluated yet. 345 * Note that there is no "shared immutable", because that is just immutable 346 * The point of this is to reduce the size of each Type instance as 347 * we bank on the idea that usually only one of variants exist. 348 * It will also speed up code because these are rarely referenced and 349 * so need not be in the cache. 350 */ 351 Type cto; // MODFlags.const_ 352 Type ito; // MODFlags.immutable_ 353 Type sto; // MODFlags.shared_ 354 Type scto; // MODFlags.shared_ | MODFlags.const_ 355 Type wto; // MODFlags.wild 356 Type wcto; // MODFlags.wildconst 357 Type swto; // MODFlags.shared_ | MODFlags.wild 358 Type swcto; // MODFlags.shared_ | MODFlags.wildconst 359 } 360 private Mcache* mcache; 361 362 Type pto; // merged pointer to this type 363 Type rto; // reference to this type 364 Type arrayof; // array of this type 365 366 TypeInfoDeclaration vtinfo; // TypeInfo object for this Type 367 368 type* ctype; // for back end 369 370 extern (C++) __gshared Type tvoid; 371 extern (C++) __gshared Type tint8; 372 extern (C++) __gshared Type tuns8; 373 extern (C++) __gshared Type tint16; 374 extern (C++) __gshared Type tuns16; 375 extern (C++) __gshared Type tint32; 376 extern (C++) __gshared Type tuns32; 377 extern (C++) __gshared Type tint64; 378 extern (C++) __gshared Type tuns64; 379 extern (C++) __gshared Type tint128; 380 extern (C++) __gshared Type tuns128; 381 extern (C++) __gshared Type tfloat32; 382 extern (C++) __gshared Type tfloat64; 383 extern (C++) __gshared Type tfloat80; 384 extern (C++) __gshared Type timaginary32; 385 extern (C++) __gshared Type timaginary64; 386 extern (C++) __gshared Type timaginary80; 387 extern (C++) __gshared Type tcomplex32; 388 extern (C++) __gshared Type tcomplex64; 389 extern (C++) __gshared Type tcomplex80; 390 extern (C++) __gshared Type tbool; 391 extern (C++) __gshared Type tchar; 392 extern (C++) __gshared Type twchar; 393 extern (C++) __gshared Type tdchar; 394 395 // Some special types 396 extern (C++) __gshared Type tshiftcnt; 397 extern (C++) __gshared Type tvoidptr; // void* 398 extern (C++) __gshared Type tstring; // immutable(char)[] 399 extern (C++) __gshared Type twstring; // immutable(wchar)[] 400 extern (C++) __gshared Type tdstring; // immutable(dchar)[] 401 extern (C++) __gshared Type terror; // for error recovery 402 extern (C++) __gshared Type tnull; // for null type 403 extern (C++) __gshared Type tnoreturn; // for bottom type typeof(*null) 404 405 extern (C++) __gshared Type tsize_t; // matches size_t alias 406 extern (C++) __gshared Type tptrdiff_t; // matches ptrdiff_t alias 407 extern (C++) __gshared Type thash_t; // matches hash_t alias 408 409 extern (C++) __gshared ClassDeclaration dtypeinfo; 410 extern (C++) __gshared ClassDeclaration typeinfoclass; 411 extern (C++) __gshared ClassDeclaration typeinfointerface; 412 extern (C++) __gshared ClassDeclaration typeinfostruct; 413 extern (C++) __gshared ClassDeclaration typeinfopointer; 414 extern (C++) __gshared ClassDeclaration typeinfoarray; 415 extern (C++) __gshared ClassDeclaration typeinfostaticarray; 416 extern (C++) __gshared ClassDeclaration typeinfoassociativearray; 417 extern (C++) __gshared ClassDeclaration typeinfovector; 418 extern (C++) __gshared ClassDeclaration typeinfoenum; 419 extern (C++) __gshared ClassDeclaration typeinfofunction; 420 extern (C++) __gshared ClassDeclaration typeinfodelegate; 421 extern (C++) __gshared ClassDeclaration typeinfotypelist; 422 extern (C++) __gshared ClassDeclaration typeinfoconst; 423 extern (C++) __gshared ClassDeclaration typeinfoinvariant; 424 extern (C++) __gshared ClassDeclaration typeinfoshared; 425 extern (C++) __gshared ClassDeclaration typeinfowild; 426 427 extern (C++) __gshared TemplateDeclaration rtinfo; 428 429 extern (C++) __gshared Type[TMAX] basic; 430 431 extern (D) __gshared StringTable!Type stringtable; 432 extern (D) private static immutable ubyte[TMAX] sizeTy = () 433 { 434 ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic); 435 sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray); 436 sizeTy[Tarray] = __traits(classInstanceSize, TypeDArray); 437 sizeTy[Taarray] = __traits(classInstanceSize, TypeAArray); 438 sizeTy[Tpointer] = __traits(classInstanceSize, TypePointer); 439 sizeTy[Treference] = __traits(classInstanceSize, TypeReference); 440 sizeTy[Tfunction] = __traits(classInstanceSize, TypeFunction); 441 sizeTy[Tdelegate] = __traits(classInstanceSize, TypeDelegate); 442 sizeTy[Tident] = __traits(classInstanceSize, TypeIdentifier); 443 sizeTy[Tinstance] = __traits(classInstanceSize, TypeInstance); 444 sizeTy[Ttypeof] = __traits(classInstanceSize, TypeTypeof); 445 sizeTy[Tenum] = __traits(classInstanceSize, TypeEnum); 446 sizeTy[Tstruct] = __traits(classInstanceSize, TypeStruct); 447 sizeTy[Tclass] = __traits(classInstanceSize, TypeClass); 448 sizeTy[Ttuple] = __traits(classInstanceSize, TypeTuple); 449 sizeTy[Tslice] = __traits(classInstanceSize, TypeSlice); 450 sizeTy[Treturn] = __traits(classInstanceSize, TypeReturn); 451 sizeTy[Terror] = __traits(classInstanceSize, TypeError); 452 sizeTy[Tnull] = __traits(classInstanceSize, TypeNull); 453 sizeTy[Tvector] = __traits(classInstanceSize, TypeVector); 454 sizeTy[Ttraits] = __traits(classInstanceSize, TypeTraits); 455 sizeTy[Tmixin] = __traits(classInstanceSize, TypeMixin); 456 sizeTy[Tnoreturn] = __traits(classInstanceSize, TypeNoreturn); 457 sizeTy[Ttag] = __traits(classInstanceSize, TypeTag); 458 return sizeTy; 459 }(); 460 461 final extern (D) this(TY ty) scope @safe 462 { 463 this.ty = ty; 464 } 465 466 const(char)* kind() const nothrow pure @nogc @safe 467 { 468 assert(false); // should be overridden 469 } 470 471 final Type copy() nothrow const 472 { 473 Type t = cast(Type)mem.xmalloc(sizeTy[ty]); 474 memcpy(cast(void*)t, cast(void*)this, sizeTy[ty]); 475 return t; 476 } 477 478 Type syntaxCopy() 479 { 480 fprintf(stderr, "this = %s, ty = %d\n", toChars(), ty); 481 assert(0); 482 } 483 484 override bool equals(const RootObject o) const 485 { 486 Type t = cast(Type)o; 487 //printf("Type::equals(%s, %s)\n", toChars(), t.toChars()); 488 // deco strings are unique 489 // and semantic() has been run 490 if (this == o || ((t && deco == t.deco) && deco !is null)) 491 { 492 //printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); 493 return true; 494 } 495 //if (deco && t && t.deco) printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); 496 return false; 497 } 498 499 final bool equivalent(Type t) 500 { 501 return immutableOf().equals(t.immutableOf()); 502 } 503 504 // kludge for template.isType() 505 override final DYNCAST dyncast() const 506 { 507 return DYNCAST.type; 508 } 509 510 /// Returns a non-zero unique ID for this Type, or returns 0 if the Type does not (yet) have a unique ID. 511 /// If `semantic()` has not been run, 0 is returned. 512 final size_t getUniqueID() const 513 { 514 return cast(size_t) deco; 515 } 516 517 extern (D) 518 final Mcache* getMcache() 519 { 520 if (!mcache) 521 mcache = cast(Mcache*) mem.xcalloc(Mcache.sizeof, 1); 522 return mcache; 523 } 524 525 /******************************* 526 * Covariant means that 'this' can substitute for 't', 527 * i.e. a pure function is a match for an impure type. 528 * Params: 529 * t = type 'this' is covariant with 530 * pstc = if not null, store STCxxxx which would make it covariant 531 * cppCovariant = true if extern(C++) function types should follow C++ covariant rules 532 * Returns: 533 * An enum value of either `Covariant.yes` or a reason it's not covariant. 534 */ 535 final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false) 536 { 537 version (none) 538 { 539 printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars()); 540 printf("deco = %p, %p\n", deco, t.deco); 541 // printf("ty = %d\n", next.ty); 542 printf("mod = %x, %x\n", mod, t.mod); 543 } 544 if (pstc) 545 *pstc = 0; 546 StorageClass stc = 0; 547 548 bool notcovariant = false; 549 550 if (equals(t)) 551 return Covariant.yes; 552 553 TypeFunction t1 = this.isTypeFunction(); 554 TypeFunction t2 = t.isTypeFunction(); 555 556 if (!t1 || !t2) 557 goto Ldistinct; 558 559 if (t1.parameterList.varargs != t2.parameterList.varargs) 560 goto Ldistinct; 561 562 if (t1.parameterList.parameters && t2.parameterList.parameters) 563 { 564 if (t1.parameterList.length != t2.parameterList.length) 565 goto Ldistinct; 566 567 foreach (i, fparam1; t1.parameterList) 568 { 569 Parameter fparam2 = t2.parameterList[i]; 570 Type tp1 = fparam1.type; 571 Type tp2 = fparam2.type; 572 573 if (!tp1.equals(tp2)) 574 { 575 if (tp1.ty == tp2.ty) 576 { 577 if (auto tc1 = tp1.isTypeClass()) 578 { 579 if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) 580 goto Lcov; 581 } 582 else if (auto ts1 = tp1.isTypeStruct()) 583 { 584 if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) 585 goto Lcov; 586 } 587 else if (tp1.ty == Tpointer) 588 { 589 if (tp2.implicitConvTo(tp1)) 590 goto Lcov; 591 } 592 else if (tp1.ty == Tarray) 593 { 594 if (tp2.implicitConvTo(tp1)) 595 goto Lcov; 596 } 597 else if (tp1.ty == Tdelegate) 598 { 599 if (tp2.implicitConvTo(tp1)) 600 goto Lcov; 601 } 602 } 603 goto Ldistinct; 604 } 605 Lcov: 606 notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); 607 608 /* https://issues.dlang.org/show_bug.cgi?id=23135 609 * extern(C++) mutable parameters are not covariant with const. 610 */ 611 if (t1.linkage == LINK.cpp && cppCovariant) 612 { 613 notcovariant |= tp1.isNaked() != tp2.isNaked(); 614 if (auto tpn1 = tp1.nextOf()) 615 notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); 616 } 617 } 618 } 619 else if (t1.parameterList.parameters != t2.parameterList.parameters) 620 { 621 if (t1.parameterList.length || t2.parameterList.length) 622 goto Ldistinct; 623 } 624 625 // The argument lists match 626 if (notcovariant) 627 goto Lnotcovariant; 628 if (t1.linkage != t2.linkage) 629 goto Lnotcovariant; 630 631 { 632 // Return types 633 Type t1n = t1.next; 634 Type t2n = t2.next; 635 636 if (!t1n || !t2n) // happens with return type inference 637 goto Lnotcovariant; 638 639 if (t1n.equals(t2n)) 640 goto Lcovariant; 641 if (t1n.ty == Tclass && t2n.ty == Tclass) 642 { 643 /* If same class type, but t2n is const, then it's 644 * covariant. Do this test first because it can work on 645 * forward references. 646 */ 647 if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) 648 goto Lcovariant; 649 650 // If t1n is forward referenced: 651 ClassDeclaration cd = (cast(TypeClass)t1n).sym; 652 if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) 653 cd.dsymbolSemantic(null); 654 if (!cd.isBaseInfoComplete()) 655 { 656 return Covariant.fwdref; 657 } 658 } 659 if (t1n.ty == Tstruct && t2n.ty == Tstruct) 660 { 661 if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) 662 goto Lcovariant; 663 } 664 else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) 665 { 666 if (t1.isref && t2.isref) 667 { 668 // Treat like pointers to t1n and t2n 669 if (t1n.constConv(t2n) < MATCH.constant) 670 goto Lnotcovariant; 671 } 672 goto Lcovariant; 673 } 674 else if (t1n.ty == Tnull) 675 { 676 // NULL is covariant with any pointer type, but not with any 677 // dynamic arrays, associative arrays or delegates. 678 // https://issues.dlang.org/show_bug.cgi?id=8589 679 // https://issues.dlang.org/show_bug.cgi?id=19618 680 Type t2bn = t2n.toBasetype(); 681 if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) 682 goto Lcovariant; 683 } 684 // bottom type is covariant to any type 685 else if (t1n.ty == Tnoreturn) 686 goto Lcovariant; 687 } 688 goto Lnotcovariant; 689 690 Lcovariant: 691 if (t1.isref != t2.isref) 692 goto Lnotcovariant; 693 694 if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) 695 { 696 StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; 697 StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; 698 if (t1.isreturn) 699 { 700 stc1 |= STC.return_; 701 if (!t1.isScopeQual) 702 stc1 |= STC.ref_; 703 } 704 if (t2.isreturn) 705 { 706 stc2 |= STC.return_; 707 if (!t2.isScopeQual) 708 stc2 |= STC.ref_; 709 } 710 if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) 711 goto Lnotcovariant; 712 } 713 714 // We can subtract 'return ref' from 'this', but cannot add it 715 else if (t1.isreturn && !t2.isreturn) 716 goto Lnotcovariant; 717 718 /* https://issues.dlang.org/show_bug.cgi?id=23135 719 * extern(C++) mutable member functions are not covariant with const. 720 */ 721 if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) 722 goto Lnotcovariant; 723 724 /* Can convert mutable to const 725 */ 726 if (!MODimplicitConv(t2.mod, t1.mod)) 727 { 728 version (none) 729 { 730 //stop attribute inference with const 731 // If adding 'const' will make it covariant 732 if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) 733 stc |= STC.const_; 734 else 735 goto Lnotcovariant; 736 } 737 else 738 { 739 goto Ldistinct; 740 } 741 } 742 743 /* Can convert pure to impure, nothrow to throw, and nogc to gc 744 */ 745 if (!t1.purity && t2.purity) 746 stc |= STC.pure_; 747 748 if (!t1.isnothrow && t2.isnothrow) 749 stc |= STC.nothrow_; 750 751 if (!t1.isnogc && t2.isnogc) 752 stc |= STC.nogc; 753 754 /* Can convert safe/trusted to system 755 */ 756 if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) 757 { 758 // Should we infer trusted or safe? Go with safe. 759 stc |= STC.safe; 760 } 761 762 if (stc) 763 { 764 if (pstc) 765 *pstc = stc; 766 goto Lnotcovariant; 767 } 768 769 //printf("\tcovaraint: 1\n"); 770 return Covariant.yes; 771 772 Ldistinct: 773 //printf("\tcovaraint: 0\n"); 774 return Covariant.distinct; 775 776 Lnotcovariant: 777 //printf("\tcovaraint: 2\n"); 778 return Covariant.no; 779 } 780 781 /******************************** 782 * For pretty-printing a type. 783 */ 784 final override const(char)* toChars() const 785 { 786 OutBuffer buf; 787 buf.reserve(16); 788 HdrGenState hgs; 789 hgs.fullQual = (ty == Tclass && !mod); 790 791 toCBuffer(this, buf, null, hgs); 792 return buf.extractChars(); 793 } 794 795 /// ditto 796 final char* toPrettyChars(bool QualifyTypes = false) 797 { 798 OutBuffer buf; 799 buf.reserve(16); 800 HdrGenState hgs; 801 hgs.fullQual = QualifyTypes; 802 803 toCBuffer(this, buf, null, hgs); 804 return buf.extractChars(); 805 } 806 807 static void _init() 808 { 809 stringtable._init(14_000); 810 811 // Set basic types 812 __gshared TY* basetab = 813 [ 814 Tvoid, 815 Tint8, 816 Tuns8, 817 Tint16, 818 Tuns16, 819 Tint32, 820 Tuns32, 821 Tint64, 822 Tuns64, 823 Tint128, 824 Tuns128, 825 Tfloat32, 826 Tfloat64, 827 Tfloat80, 828 Timaginary32, 829 Timaginary64, 830 Timaginary80, 831 Tcomplex32, 832 Tcomplex64, 833 Tcomplex80, 834 Tbool, 835 Tchar, 836 Twchar, 837 Tdchar, 838 Terror 839 ]; 840 841 for (size_t i = 0; basetab[i] != Terror; i++) 842 { 843 Type t = new TypeBasic(basetab[i]); 844 t = t.merge(); 845 basic[basetab[i]] = t; 846 } 847 basic[Terror] = new TypeError(); 848 849 tnoreturn = new TypeNoreturn(); 850 tnoreturn.deco = tnoreturn.merge().deco; 851 basic[Tnoreturn] = tnoreturn; 852 853 tvoid = basic[Tvoid]; 854 tint8 = basic[Tint8]; 855 tuns8 = basic[Tuns8]; 856 tint16 = basic[Tint16]; 857 tuns16 = basic[Tuns16]; 858 tint32 = basic[Tint32]; 859 tuns32 = basic[Tuns32]; 860 tint64 = basic[Tint64]; 861 tuns64 = basic[Tuns64]; 862 tint128 = basic[Tint128]; 863 tuns128 = basic[Tuns128]; 864 tfloat32 = basic[Tfloat32]; 865 tfloat64 = basic[Tfloat64]; 866 tfloat80 = basic[Tfloat80]; 867 868 timaginary32 = basic[Timaginary32]; 869 timaginary64 = basic[Timaginary64]; 870 timaginary80 = basic[Timaginary80]; 871 872 tcomplex32 = basic[Tcomplex32]; 873 tcomplex64 = basic[Tcomplex64]; 874 tcomplex80 = basic[Tcomplex80]; 875 876 tbool = basic[Tbool]; 877 tchar = basic[Tchar]; 878 twchar = basic[Twchar]; 879 tdchar = basic[Tdchar]; 880 881 tshiftcnt = tint32; 882 terror = basic[Terror]; 883 tnoreturn = basic[Tnoreturn]; 884 tnull = new TypeNull(); 885 tnull.deco = tnull.merge().deco; 886 887 tvoidptr = tvoid.pointerTo(); 888 tstring = tchar.immutableOf().arrayOf(); 889 twstring = twchar.immutableOf().arrayOf(); 890 tdstring = tdchar.immutableOf().arrayOf(); 891 892 const isLP64 = target.isLP64; 893 894 tsize_t = basic[isLP64 ? Tuns64 : Tuns32]; 895 tptrdiff_t = basic[isLP64 ? Tint64 : Tint32]; 896 thash_t = tsize_t; 897 } 898 899 /** 900 * Deinitializes the global state of the compiler. 901 * 902 * This can be used to restore the state set by `_init` to its original 903 * state. 904 */ 905 static void deinitialize() 906 { 907 stringtable = stringtable.init; 908 } 909 910 final uinteger_t size() 911 { 912 return size(Loc.initial); 913 } 914 915 uinteger_t size(const ref Loc loc) 916 { 917 error(loc, "no size for type `%s`", toChars()); 918 return SIZE_INVALID; 919 } 920 921 uint alignsize() 922 { 923 return cast(uint)size(Loc.initial); 924 } 925 926 final Type trySemantic(const ref Loc loc, Scope* sc) 927 { 928 //printf("+trySemantic(%s) %d\n", toChars(), global.errors); 929 930 // Needed to display any deprecations that were gagged 931 auto tcopy = this.syntaxCopy(); 932 933 const errors = global.startGagging(); 934 Type t = typeSemantic(this, loc, sc); 935 if (global.endGagging(errors) || t.ty == Terror) // if any errors happened 936 { 937 t = null; 938 } 939 else 940 { 941 // If `typeSemantic` succeeded, there may have been deprecations that 942 // were gagged due the `startGagging` above. Run again to display 943 // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 944 if (global.gaggedWarnings > 0) 945 typeSemantic(tcopy, loc, sc); 946 } 947 //printf("-trySemantic(%s) %d\n", toChars(), global.errors); 948 return t; 949 } 950 951 /************************************* 952 * This version does a merge even if the deco is already computed. 953 * Necessary for types that have a deco, but are not merged. 954 */ 955 final Type merge2() 956 { 957 //printf("merge2(%s)\n", toChars()); 958 Type t = this; 959 assert(t); 960 if (!t.deco) 961 return t.merge(); 962 963 auto sv = stringtable.lookup(t.deco, strlen(t.deco)); 964 if (sv && sv.value) 965 { 966 t = sv.value; 967 assert(t.deco); 968 } 969 else 970 assert(0); 971 return t; 972 } 973 974 /********************************* 975 * Store this type's modifier name into buf. 976 */ 977 final void modToBuffer(ref OutBuffer buf) nothrow const 978 { 979 if (mod) 980 { 981 buf.writeByte(' '); 982 MODtoBuffer(buf, mod); 983 } 984 } 985 986 /********************************* 987 * Return this type's modifier name. 988 */ 989 final char* modToChars() nothrow const 990 { 991 OutBuffer buf; 992 buf.reserve(16); 993 modToBuffer(buf); 994 return buf.extractChars(); 995 } 996 997 bool isintegral() 998 { 999 return false; 1000 } 1001 1002 // real, imaginary, or complex 1003 bool isfloating() 1004 { 1005 return false; 1006 } 1007 1008 bool isreal() 1009 { 1010 return false; 1011 } 1012 1013 bool isimaginary() 1014 { 1015 return false; 1016 } 1017 1018 bool iscomplex() 1019 { 1020 return false; 1021 } 1022 1023 bool isscalar() 1024 { 1025 return false; 1026 } 1027 1028 bool isunsigned() 1029 { 1030 return false; 1031 } 1032 1033 bool isscope() 1034 { 1035 return false; 1036 } 1037 1038 bool isString() 1039 { 1040 return false; 1041 } 1042 1043 /************************** 1044 * When T is mutable, 1045 * Given: 1046 * T a, b; 1047 * Can we bitwise assign: 1048 * a = b; 1049 * ? 1050 */ 1051 bool isAssignable() 1052 { 1053 return true; 1054 } 1055 1056 /************************** 1057 * Returns true if T can be converted to boolean value. 1058 */ 1059 bool isBoolean() 1060 { 1061 return isscalar(); 1062 } 1063 1064 /********************************* 1065 * Check type to see if it is based on a deprecated symbol. 1066 */ 1067 void checkDeprecated(const ref Loc loc, Scope* sc) 1068 { 1069 if (Dsymbol s = toDsymbol(sc)) 1070 { 1071 s.checkDeprecated(loc, sc); 1072 } 1073 } 1074 1075 final bool isConst() const nothrow pure @nogc @safe 1076 { 1077 return (mod & MODFlags.const_) != 0; 1078 } 1079 1080 final bool isImmutable() const nothrow pure @nogc @safe 1081 { 1082 return (mod & MODFlags.immutable_) != 0; 1083 } 1084 1085 final bool isMutable() const nothrow pure @nogc @safe 1086 { 1087 return (mod & (MODFlags.const_ | MODFlags.immutable_ | MODFlags.wild)) == 0; 1088 } 1089 1090 final bool isShared() const nothrow pure @nogc @safe 1091 { 1092 return (mod & MODFlags.shared_) != 0; 1093 } 1094 1095 final bool isSharedConst() const nothrow pure @nogc @safe 1096 { 1097 return (mod & (MODFlags.shared_ | MODFlags.const_)) == (MODFlags.shared_ | MODFlags.const_); 1098 } 1099 1100 final bool isWild() const nothrow pure @nogc @safe 1101 { 1102 return (mod & MODFlags.wild) != 0; 1103 } 1104 1105 final bool isWildConst() const nothrow pure @nogc @safe 1106 { 1107 return (mod & MODFlags.wildconst) == MODFlags.wildconst; 1108 } 1109 1110 final bool isSharedWild() const nothrow pure @nogc @safe 1111 { 1112 return (mod & (MODFlags.shared_ | MODFlags.wild)) == (MODFlags.shared_ | MODFlags.wild); 1113 } 1114 1115 final bool isNaked() const nothrow pure @nogc @safe 1116 { 1117 return mod == 0; 1118 } 1119 1120 /******************************** 1121 * Return a copy of this type with all attributes null-initialized. 1122 * Useful for creating a type with different modifiers. 1123 */ 1124 final Type nullAttributes() nothrow const 1125 { 1126 uint sz = sizeTy[ty]; 1127 Type t = cast(Type)mem.xmalloc(sz); 1128 memcpy(cast(void*)t, cast(void*)this, sz); 1129 // t.mod = NULL; // leave mod unchanged 1130 t.deco = null; 1131 t.arrayof = null; 1132 t.pto = null; 1133 t.rto = null; 1134 t.vtinfo = null; 1135 t.ctype = null; 1136 t.mcache = null; 1137 if (t.ty == Tstruct) 1138 (cast(TypeStruct)t).att = AliasThisRec.fwdref; 1139 if (t.ty == Tclass) 1140 (cast(TypeClass)t).att = AliasThisRec.fwdref; 1141 return t; 1142 } 1143 1144 /******************************** 1145 * Convert to 'const'. 1146 */ 1147 final Type constOf() 1148 { 1149 //printf("Type::constOf() %p %s\n", this, toChars()); 1150 if (mod == MODFlags.const_) 1151 return this; 1152 if (mcache && mcache.cto) 1153 { 1154 assert(mcache.cto.mod == MODFlags.const_); 1155 return mcache.cto; 1156 } 1157 Type t = makeConst(); 1158 t = t.merge(); 1159 t.fixTo(this); 1160 //printf("-Type::constOf() %p %s\n", t, t.toChars()); 1161 return t; 1162 } 1163 1164 /******************************** 1165 * Convert to 'immutable'. 1166 */ 1167 final Type immutableOf() 1168 { 1169 //printf("Type::immutableOf() %p %s\n", this, toChars()); 1170 if (isImmutable()) 1171 return this; 1172 if (mcache && mcache.ito) 1173 { 1174 assert(mcache.ito.isImmutable()); 1175 return mcache.ito; 1176 } 1177 Type t = makeImmutable(); 1178 t = t.merge(); 1179 t.fixTo(this); 1180 //printf("\t%p\n", t); 1181 return t; 1182 } 1183 1184 /******************************** 1185 * Make type mutable. 1186 */ 1187 final Type mutableOf() 1188 { 1189 //printf("Type::mutableOf() %p, %s\n", this, toChars()); 1190 Type t = this; 1191 if (isImmutable()) 1192 { 1193 getMcache(); 1194 t = mcache.ito; // immutable => naked 1195 assert(!t || (t.isMutable() && !t.isShared())); 1196 } 1197 else if (isConst()) 1198 { 1199 getMcache(); 1200 if (isShared()) 1201 { 1202 if (isWild()) 1203 t = mcache.swcto; // shared wild const -> shared 1204 else 1205 t = mcache.sto; // shared const => shared 1206 } 1207 else 1208 { 1209 if (isWild()) 1210 t = mcache.wcto; // wild const -> naked 1211 else 1212 t = mcache.cto; // const => naked 1213 } 1214 assert(!t || t.isMutable()); 1215 } 1216 else if (isWild()) 1217 { 1218 getMcache(); 1219 if (isShared()) 1220 t = mcache.sto; // shared wild => shared 1221 else 1222 t = mcache.wto; // wild => naked 1223 assert(!t || t.isMutable()); 1224 } 1225 if (!t) 1226 { 1227 t = makeMutable(); 1228 t = t.merge(); 1229 t.fixTo(this); 1230 } 1231 else 1232 t = t.merge(); 1233 assert(t.isMutable()); 1234 return t; 1235 } 1236 1237 final Type sharedOf() 1238 { 1239 //printf("Type::sharedOf() %p, %s\n", this, toChars()); 1240 if (mod == MODFlags.shared_) 1241 return this; 1242 if (mcache && mcache.sto) 1243 { 1244 assert(mcache.sto.mod == MODFlags.shared_); 1245 return mcache.sto; 1246 } 1247 Type t = makeShared(); 1248 t = t.merge(); 1249 t.fixTo(this); 1250 //printf("\t%p\n", t); 1251 return t; 1252 } 1253 1254 final Type sharedConstOf() 1255 { 1256 //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); 1257 if (mod == (MODFlags.shared_ | MODFlags.const_)) 1258 return this; 1259 if (mcache && mcache.scto) 1260 { 1261 assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1262 return mcache.scto; 1263 } 1264 Type t = makeSharedConst(); 1265 t = t.merge(); 1266 t.fixTo(this); 1267 //printf("\t%p\n", t); 1268 return t; 1269 } 1270 1271 /******************************** 1272 * Make type unshared. 1273 * 0 => 0 1274 * const => const 1275 * immutable => immutable 1276 * shared => 0 1277 * shared const => const 1278 * wild => wild 1279 * wild const => wild const 1280 * shared wild => wild 1281 * shared wild const => wild const 1282 */ 1283 final Type unSharedOf() 1284 { 1285 //printf("Type::unSharedOf() %p, %s\n", this, toChars()); 1286 Type t = this; 1287 1288 if (isShared()) 1289 { 1290 getMcache(); 1291 if (isWild()) 1292 { 1293 if (isConst()) 1294 t = mcache.wcto; // shared wild const => wild const 1295 else 1296 t = mcache.wto; // shared wild => wild 1297 } 1298 else 1299 { 1300 if (isConst()) 1301 t = mcache.cto; // shared const => const 1302 else 1303 t = mcache.sto; // shared => naked 1304 } 1305 assert(!t || !t.isShared()); 1306 } 1307 1308 if (!t) 1309 { 1310 t = this.nullAttributes(); 1311 t.mod = mod & ~MODFlags.shared_; 1312 t.ctype = ctype; 1313 t = t.merge(); 1314 t.fixTo(this); 1315 } 1316 else 1317 t = t.merge(); 1318 assert(!t.isShared()); 1319 return t; 1320 } 1321 1322 /******************************** 1323 * Convert to 'wild'. 1324 */ 1325 final Type wildOf() 1326 { 1327 //printf("Type::wildOf() %p %s\n", this, toChars()); 1328 if (mod == MODFlags.wild) 1329 return this; 1330 if (mcache && mcache.wto) 1331 { 1332 assert(mcache.wto.mod == MODFlags.wild); 1333 return mcache.wto; 1334 } 1335 Type t = makeWild(); 1336 t = t.merge(); 1337 t.fixTo(this); 1338 //printf("\t%p %s\n", t, t.toChars()); 1339 return t; 1340 } 1341 1342 final Type wildConstOf() 1343 { 1344 //printf("Type::wildConstOf() %p %s\n", this, toChars()); 1345 if (mod == MODFlags.wildconst) 1346 return this; 1347 if (mcache && mcache.wcto) 1348 { 1349 assert(mcache.wcto.mod == MODFlags.wildconst); 1350 return mcache.wcto; 1351 } 1352 Type t = makeWildConst(); 1353 t = t.merge(); 1354 t.fixTo(this); 1355 //printf("\t%p %s\n", t, t.toChars()); 1356 return t; 1357 } 1358 1359 final Type sharedWildOf() 1360 { 1361 //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); 1362 if (mod == (MODFlags.shared_ | MODFlags.wild)) 1363 return this; 1364 if (mcache && mcache.swto) 1365 { 1366 assert(mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1367 return mcache.swto; 1368 } 1369 Type t = makeSharedWild(); 1370 t = t.merge(); 1371 t.fixTo(this); 1372 //printf("\t%p %s\n", t, t.toChars()); 1373 return t; 1374 } 1375 1376 final Type sharedWildConstOf() 1377 { 1378 //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars()); 1379 if (mod == (MODFlags.shared_ | MODFlags.wildconst)) 1380 return this; 1381 if (mcache && mcache.swcto) 1382 { 1383 assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1384 return mcache.swcto; 1385 } 1386 Type t = makeSharedWildConst(); 1387 t = t.merge(); 1388 t.fixTo(this); 1389 //printf("\t%p %s\n", t, t.toChars()); 1390 return t; 1391 } 1392 1393 /********************************** 1394 * For our new type 'this', which is type-constructed from t, 1395 * fill in the cto, ito, sto, scto, wto shortcuts. 1396 */ 1397 extern (D) final void fixTo(Type t) 1398 { 1399 // If fixing this: immutable(T*) by t: immutable(T)*, 1400 // cache t to this.xto won't break transitivity. 1401 Type mto = null; 1402 Type tn = nextOf(); 1403 if (!tn || ty != Tsarray && tn.mod == t.nextOf().mod) 1404 { 1405 switch (t.mod) 1406 { 1407 case 0: 1408 mto = t; 1409 break; 1410 1411 case MODFlags.const_: 1412 getMcache(); 1413 mcache.cto = t; 1414 break; 1415 1416 case MODFlags.wild: 1417 getMcache(); 1418 mcache.wto = t; 1419 break; 1420 1421 case MODFlags.wildconst: 1422 getMcache(); 1423 mcache.wcto = t; 1424 break; 1425 1426 case MODFlags.shared_: 1427 getMcache(); 1428 mcache.sto = t; 1429 break; 1430 1431 case MODFlags.shared_ | MODFlags.const_: 1432 getMcache(); 1433 mcache.scto = t; 1434 break; 1435 1436 case MODFlags.shared_ | MODFlags.wild: 1437 getMcache(); 1438 mcache.swto = t; 1439 break; 1440 1441 case MODFlags.shared_ | MODFlags.wildconst: 1442 getMcache(); 1443 mcache.swcto = t; 1444 break; 1445 1446 case MODFlags.immutable_: 1447 getMcache(); 1448 mcache.ito = t; 1449 break; 1450 1451 default: 1452 break; 1453 } 1454 } 1455 assert(mod != t.mod); 1456 1457 if (mod) 1458 { 1459 getMcache(); 1460 t.getMcache(); 1461 } 1462 switch (mod) 1463 { 1464 case 0: 1465 break; 1466 1467 case MODFlags.const_: 1468 mcache.cto = mto; 1469 t.mcache.cto = this; 1470 break; 1471 1472 case MODFlags.wild: 1473 mcache.wto = mto; 1474 t.mcache.wto = this; 1475 break; 1476 1477 case MODFlags.wildconst: 1478 mcache.wcto = mto; 1479 t.mcache.wcto = this; 1480 break; 1481 1482 case MODFlags.shared_: 1483 mcache.sto = mto; 1484 t.mcache.sto = this; 1485 break; 1486 1487 case MODFlags.shared_ | MODFlags.const_: 1488 mcache.scto = mto; 1489 t.mcache.scto = this; 1490 break; 1491 1492 case MODFlags.shared_ | MODFlags.wild: 1493 mcache.swto = mto; 1494 t.mcache.swto = this; 1495 break; 1496 1497 case MODFlags.shared_ | MODFlags.wildconst: 1498 mcache.swcto = mto; 1499 t.mcache.swcto = this; 1500 break; 1501 1502 case MODFlags.immutable_: 1503 t.mcache.ito = this; 1504 if (t.mcache.cto) 1505 t.mcache.cto.getMcache().ito = this; 1506 if (t.mcache.sto) 1507 t.mcache.sto.getMcache().ito = this; 1508 if (t.mcache.scto) 1509 t.mcache.scto.getMcache().ito = this; 1510 if (t.mcache.wto) 1511 t.mcache.wto.getMcache().ito = this; 1512 if (t.mcache.wcto) 1513 t.mcache.wcto.getMcache().ito = this; 1514 if (t.mcache.swto) 1515 t.mcache.swto.getMcache().ito = this; 1516 if (t.mcache.swcto) 1517 t.mcache.swcto.getMcache().ito = this; 1518 break; 1519 1520 default: 1521 assert(0); 1522 } 1523 1524 check(); 1525 t.check(); 1526 //printf("fixTo: %s, %s\n", toChars(), t.toChars()); 1527 } 1528 1529 /*************************** 1530 * Look for bugs in constructing types. 1531 */ 1532 extern (D) final void check() 1533 { 1534 if (mcache) 1535 with (mcache) 1536 switch (mod) 1537 { 1538 case 0: 1539 if (cto) 1540 assert(cto.mod == MODFlags.const_); 1541 if (ito) 1542 assert(ito.mod == MODFlags.immutable_); 1543 if (sto) 1544 assert(sto.mod == MODFlags.shared_); 1545 if (scto) 1546 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1547 if (wto) 1548 assert(wto.mod == MODFlags.wild); 1549 if (wcto) 1550 assert(wcto.mod == MODFlags.wildconst); 1551 if (swto) 1552 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1553 if (swcto) 1554 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1555 break; 1556 1557 case MODFlags.const_: 1558 if (cto) 1559 assert(cto.mod == 0); 1560 if (ito) 1561 assert(ito.mod == MODFlags.immutable_); 1562 if (sto) 1563 assert(sto.mod == MODFlags.shared_); 1564 if (scto) 1565 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1566 if (wto) 1567 assert(wto.mod == MODFlags.wild); 1568 if (wcto) 1569 assert(wcto.mod == MODFlags.wildconst); 1570 if (swto) 1571 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1572 if (swcto) 1573 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1574 break; 1575 1576 case MODFlags.wild: 1577 if (cto) 1578 assert(cto.mod == MODFlags.const_); 1579 if (ito) 1580 assert(ito.mod == MODFlags.immutable_); 1581 if (sto) 1582 assert(sto.mod == MODFlags.shared_); 1583 if (scto) 1584 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1585 if (wto) 1586 assert(wto.mod == 0); 1587 if (wcto) 1588 assert(wcto.mod == MODFlags.wildconst); 1589 if (swto) 1590 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1591 if (swcto) 1592 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1593 break; 1594 1595 case MODFlags.wildconst: 1596 assert(!cto || cto.mod == MODFlags.const_); 1597 assert(!ito || ito.mod == MODFlags.immutable_); 1598 assert(!sto || sto.mod == MODFlags.shared_); 1599 assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1600 assert(!wto || wto.mod == MODFlags.wild); 1601 assert(!wcto || wcto.mod == 0); 1602 assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1603 assert(!swcto || swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1604 break; 1605 1606 case MODFlags.shared_: 1607 if (cto) 1608 assert(cto.mod == MODFlags.const_); 1609 if (ito) 1610 assert(ito.mod == MODFlags.immutable_); 1611 if (sto) 1612 assert(sto.mod == 0); 1613 if (scto) 1614 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1615 if (wto) 1616 assert(wto.mod == MODFlags.wild); 1617 if (wcto) 1618 assert(wcto.mod == MODFlags.wildconst); 1619 if (swto) 1620 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1621 if (swcto) 1622 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1623 break; 1624 1625 case MODFlags.shared_ | MODFlags.const_: 1626 if (cto) 1627 assert(cto.mod == MODFlags.const_); 1628 if (ito) 1629 assert(ito.mod == MODFlags.immutable_); 1630 if (sto) 1631 assert(sto.mod == MODFlags.shared_); 1632 if (scto) 1633 assert(scto.mod == 0); 1634 if (wto) 1635 assert(wto.mod == MODFlags.wild); 1636 if (wcto) 1637 assert(wcto.mod == MODFlags.wildconst); 1638 if (swto) 1639 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1640 if (swcto) 1641 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1642 break; 1643 1644 case MODFlags.shared_ | MODFlags.wild: 1645 if (cto) 1646 assert(cto.mod == MODFlags.const_); 1647 if (ito) 1648 assert(ito.mod == MODFlags.immutable_); 1649 if (sto) 1650 assert(sto.mod == MODFlags.shared_); 1651 if (scto) 1652 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1653 if (wto) 1654 assert(wto.mod == MODFlags.wild); 1655 if (wcto) 1656 assert(wcto.mod == MODFlags.wildconst); 1657 if (swto) 1658 assert(swto.mod == 0); 1659 if (swcto) 1660 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1661 break; 1662 1663 case MODFlags.shared_ | MODFlags.wildconst: 1664 assert(!cto || cto.mod == MODFlags.const_); 1665 assert(!ito || ito.mod == MODFlags.immutable_); 1666 assert(!sto || sto.mod == MODFlags.shared_); 1667 assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1668 assert(!wto || wto.mod == MODFlags.wild); 1669 assert(!wcto || wcto.mod == MODFlags.wildconst); 1670 assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1671 assert(!swcto || swcto.mod == 0); 1672 break; 1673 1674 case MODFlags.immutable_: 1675 if (cto) 1676 assert(cto.mod == MODFlags.const_); 1677 if (ito) 1678 assert(ito.mod == 0); 1679 if (sto) 1680 assert(sto.mod == MODFlags.shared_); 1681 if (scto) 1682 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); 1683 if (wto) 1684 assert(wto.mod == MODFlags.wild); 1685 if (wcto) 1686 assert(wcto.mod == MODFlags.wildconst); 1687 if (swto) 1688 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); 1689 if (swcto) 1690 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 1691 break; 1692 1693 default: 1694 assert(0); 1695 } 1696 1697 Type tn = nextOf(); 1698 if (tn && ty != Tfunction && tn.ty != Tfunction && ty != Tenum) 1699 { 1700 // Verify transitivity 1701 switch (mod) 1702 { 1703 case 0: 1704 case MODFlags.const_: 1705 case MODFlags.wild: 1706 case MODFlags.wildconst: 1707 case MODFlags.shared_: 1708 case MODFlags.shared_ | MODFlags.const_: 1709 case MODFlags.shared_ | MODFlags.wild: 1710 case MODFlags.shared_ | MODFlags.wildconst: 1711 case MODFlags.immutable_: 1712 assert(tn.mod == MODFlags.immutable_ || (tn.mod & mod) == mod); 1713 break; 1714 1715 default: 1716 assert(0); 1717 } 1718 tn.check(); 1719 } 1720 } 1721 1722 /************************************* 1723 * Apply STCxxxx bits to existing type. 1724 * Use *before* semantic analysis is run. 1725 */ 1726 extern (D) final Type addSTC(StorageClass stc) 1727 { 1728 Type t = this; 1729 if (t.isImmutable()) 1730 { 1731 } 1732 else if (stc & STC.immutable_) 1733 { 1734 t = t.makeImmutable(); 1735 } 1736 else 1737 { 1738 if ((stc & STC.shared_) && !t.isShared()) 1739 { 1740 if (t.isWild()) 1741 { 1742 if (t.isConst()) 1743 t = t.makeSharedWildConst(); 1744 else 1745 t = t.makeSharedWild(); 1746 } 1747 else 1748 { 1749 if (t.isConst()) 1750 t = t.makeSharedConst(); 1751 else 1752 t = t.makeShared(); 1753 } 1754 } 1755 if ((stc & STC.const_) && !t.isConst()) 1756 { 1757 if (t.isShared()) 1758 { 1759 if (t.isWild()) 1760 t = t.makeSharedWildConst(); 1761 else 1762 t = t.makeSharedConst(); 1763 } 1764 else 1765 { 1766 if (t.isWild()) 1767 t = t.makeWildConst(); 1768 else 1769 t = t.makeConst(); 1770 } 1771 } 1772 if ((stc & STC.wild) && !t.isWild()) 1773 { 1774 if (t.isShared()) 1775 { 1776 if (t.isConst()) 1777 t = t.makeSharedWildConst(); 1778 else 1779 t = t.makeSharedWild(); 1780 } 1781 else 1782 { 1783 if (t.isConst()) 1784 t = t.makeWildConst(); 1785 else 1786 t = t.makeWild(); 1787 } 1788 } 1789 } 1790 return t; 1791 } 1792 1793 /************************************ 1794 * Apply MODxxxx bits to existing type. 1795 */ 1796 final Type castMod(MOD mod) 1797 { 1798 Type t; 1799 switch (mod) 1800 { 1801 case 0: 1802 t = unSharedOf().mutableOf(); 1803 break; 1804 1805 case MODFlags.const_: 1806 t = unSharedOf().constOf(); 1807 break; 1808 1809 case MODFlags.wild: 1810 t = unSharedOf().wildOf(); 1811 break; 1812 1813 case MODFlags.wildconst: 1814 t = unSharedOf().wildConstOf(); 1815 break; 1816 1817 case MODFlags.shared_: 1818 t = mutableOf().sharedOf(); 1819 break; 1820 1821 case MODFlags.shared_ | MODFlags.const_: 1822 t = sharedConstOf(); 1823 break; 1824 1825 case MODFlags.shared_ | MODFlags.wild: 1826 t = sharedWildOf(); 1827 break; 1828 1829 case MODFlags.shared_ | MODFlags.wildconst: 1830 t = sharedWildConstOf(); 1831 break; 1832 1833 case MODFlags.immutable_: 1834 t = immutableOf(); 1835 break; 1836 1837 default: 1838 assert(0); 1839 } 1840 return t; 1841 } 1842 1843 /************************************ 1844 * Add MODxxxx bits to existing type. 1845 * We're adding, not replacing, so adding const to 1846 * a shared type => "shared const" 1847 */ 1848 final Type addMod(MOD mod) 1849 { 1850 /* Add anything to immutable, and it remains immutable 1851 */ 1852 Type t = this; 1853 if (!t.isImmutable()) 1854 { 1855 //printf("addMod(%x) %s\n", mod, toChars()); 1856 switch (mod) 1857 { 1858 case 0: 1859 break; 1860 1861 case MODFlags.const_: 1862 if (isShared()) 1863 { 1864 if (isWild()) 1865 t = sharedWildConstOf(); 1866 else 1867 t = sharedConstOf(); 1868 } 1869 else 1870 { 1871 if (isWild()) 1872 t = wildConstOf(); 1873 else 1874 t = constOf(); 1875 } 1876 break; 1877 1878 case MODFlags.wild: 1879 if (isShared()) 1880 { 1881 if (isConst()) 1882 t = sharedWildConstOf(); 1883 else 1884 t = sharedWildOf(); 1885 } 1886 else 1887 { 1888 if (isConst()) 1889 t = wildConstOf(); 1890 else 1891 t = wildOf(); 1892 } 1893 break; 1894 1895 case MODFlags.wildconst: 1896 if (isShared()) 1897 t = sharedWildConstOf(); 1898 else 1899 t = wildConstOf(); 1900 break; 1901 1902 case MODFlags.shared_: 1903 if (isWild()) 1904 { 1905 if (isConst()) 1906 t = sharedWildConstOf(); 1907 else 1908 t = sharedWildOf(); 1909 } 1910 else 1911 { 1912 if (isConst()) 1913 t = sharedConstOf(); 1914 else 1915 t = sharedOf(); 1916 } 1917 break; 1918 1919 case MODFlags.shared_ | MODFlags.const_: 1920 if (isWild()) 1921 t = sharedWildConstOf(); 1922 else 1923 t = sharedConstOf(); 1924 break; 1925 1926 case MODFlags.shared_ | MODFlags.wild: 1927 if (isConst()) 1928 t = sharedWildConstOf(); 1929 else 1930 t = sharedWildOf(); 1931 break; 1932 1933 case MODFlags.shared_ | MODFlags.wildconst: 1934 t = sharedWildConstOf(); 1935 break; 1936 1937 case MODFlags.immutable_: 1938 t = immutableOf(); 1939 break; 1940 1941 default: 1942 assert(0); 1943 } 1944 } 1945 return t; 1946 } 1947 1948 /************************************ 1949 * Add storage class modifiers to type. 1950 */ 1951 Type addStorageClass(StorageClass stc) 1952 { 1953 /* Just translate to MOD bits and let addMod() do the work 1954 */ 1955 MOD mod = 0; 1956 if (stc & STC.immutable_) 1957 mod = MODFlags.immutable_; 1958 else 1959 { 1960 if (stc & (STC.const_ | STC.in_)) 1961 mod |= MODFlags.const_; 1962 if (stc & STC.wild) 1963 mod |= MODFlags.wild; 1964 if (stc & STC.shared_) 1965 mod |= MODFlags.shared_; 1966 } 1967 return addMod(mod); 1968 } 1969 1970 final Type pointerTo() 1971 { 1972 if (ty == Terror) 1973 return this; 1974 if (!pto) 1975 { 1976 Type t = new TypePointer(this); 1977 if (ty == Tfunction) 1978 { 1979 t.deco = t.merge().deco; 1980 pto = t; 1981 } 1982 else 1983 pto = t.merge(); 1984 } 1985 return pto; 1986 } 1987 1988 final Type referenceTo() 1989 { 1990 if (ty == Terror) 1991 return this; 1992 if (!rto) 1993 { 1994 Type t = new TypeReference(this); 1995 rto = t.merge(); 1996 } 1997 return rto; 1998 } 1999 2000 final Type arrayOf() 2001 { 2002 if (ty == Terror) 2003 return this; 2004 if (!arrayof) 2005 { 2006 Type t = new TypeDArray(this); 2007 arrayof = t.merge(); 2008 } 2009 return arrayof; 2010 } 2011 2012 // Make corresponding static array type without semantic 2013 final Type sarrayOf(dinteger_t dim) 2014 { 2015 assert(deco); 2016 Type t = new TypeSArray(this, new IntegerExp(Loc.initial, dim, Type.tsize_t)); 2017 // according to TypeSArray::semantic() 2018 t = t.addMod(mod); 2019 t = t.merge(); 2020 return t; 2021 } 2022 2023 final bool hasDeprecatedAliasThis() 2024 { 2025 auto ad = isAggregate(this); 2026 return ad && ad.aliasthis && (ad.aliasthis.isDeprecated || ad.aliasthis.sym.isDeprecated); 2027 } 2028 2029 final Type aliasthisOf() 2030 { 2031 auto ad = isAggregate(this); 2032 if (!ad || !ad.aliasthis) 2033 return null; 2034 2035 auto s = ad.aliasthis.sym; 2036 if (s.isAliasDeclaration()) 2037 s = s.toAlias(); 2038 2039 if (s.isTupleDeclaration()) 2040 return null; 2041 2042 if (auto vd = s.isVarDeclaration()) 2043 { 2044 auto t = vd.type; 2045 if (vd.needThis()) 2046 t = t.addMod(this.mod); 2047 return t; 2048 } 2049 Dsymbol callable = s.isFuncDeclaration(); 2050 callable = callable ? callable : s.isTemplateDeclaration(); 2051 if (callable) 2052 { 2053 auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet); 2054 if (!fd || fd.errors || !fd.functionSemantic()) 2055 return Type.terror; 2056 2057 auto t = fd.type.nextOf(); 2058 if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185 2059 return Type.terror; 2060 t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); 2061 return t; 2062 } 2063 if (auto d = s.isDeclaration()) 2064 { 2065 assert(d.type); 2066 return d.type; 2067 } 2068 if (auto ed = s.isEnumDeclaration()) 2069 { 2070 return ed.type; 2071 } 2072 2073 //printf("%s\n", s.kind()); 2074 return null; 2075 } 2076 2077 /** 2078 * Check whether this type has endless `alias this` recursion. 2079 * Returns: 2080 * `true` if this type has an `alias this` that can be implicitly 2081 * converted back to this type itself. 2082 */ 2083 extern (D) final bool checkAliasThisRec() 2084 { 2085 Type tb = toBasetype(); 2086 AliasThisRec* pflag; 2087 if (tb.ty == Tstruct) 2088 pflag = &(cast(TypeStruct)tb).att; 2089 else if (tb.ty == Tclass) 2090 pflag = &(cast(TypeClass)tb).att; 2091 else 2092 return false; 2093 2094 AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask); 2095 if (flag == AliasThisRec.fwdref) 2096 { 2097 Type att = aliasthisOf(); 2098 flag = att && att.implicitConvTo(this) ? AliasThisRec.yes : AliasThisRec.no; 2099 } 2100 *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask)); 2101 return flag == AliasThisRec.yes; 2102 } 2103 2104 Type makeConst() 2105 { 2106 //printf("Type::makeConst() %p, %s\n", this, toChars()); 2107 if (mcache && mcache.cto) 2108 return mcache.cto; 2109 Type t = this.nullAttributes(); 2110 t.mod = MODFlags.const_; 2111 //printf("-Type::makeConst() %p, %s\n", t, toChars()); 2112 return t; 2113 } 2114 2115 Type makeImmutable() 2116 { 2117 if (mcache && mcache.ito) 2118 return mcache.ito; 2119 Type t = this.nullAttributes(); 2120 t.mod = MODFlags.immutable_; 2121 return t; 2122 } 2123 2124 Type makeShared() 2125 { 2126 if (mcache && mcache.sto) 2127 return mcache.sto; 2128 Type t = this.nullAttributes(); 2129 t.mod = MODFlags.shared_; 2130 return t; 2131 } 2132 2133 Type makeSharedConst() 2134 { 2135 if (mcache && mcache.scto) 2136 return mcache.scto; 2137 Type t = this.nullAttributes(); 2138 t.mod = MODFlags.shared_ | MODFlags.const_; 2139 return t; 2140 } 2141 2142 Type makeWild() 2143 { 2144 if (mcache && mcache.wto) 2145 return mcache.wto; 2146 Type t = this.nullAttributes(); 2147 t.mod = MODFlags.wild; 2148 return t; 2149 } 2150 2151 Type makeWildConst() 2152 { 2153 if (mcache && mcache.wcto) 2154 return mcache.wcto; 2155 Type t = this.nullAttributes(); 2156 t.mod = MODFlags.wildconst; 2157 return t; 2158 } 2159 2160 Type makeSharedWild() 2161 { 2162 if (mcache && mcache.swto) 2163 return mcache.swto; 2164 Type t = this.nullAttributes(); 2165 t.mod = MODFlags.shared_ | MODFlags.wild; 2166 return t; 2167 } 2168 2169 Type makeSharedWildConst() 2170 { 2171 if (mcache && mcache.swcto) 2172 return mcache.swcto; 2173 Type t = this.nullAttributes(); 2174 t.mod = MODFlags.shared_ | MODFlags.wildconst; 2175 return t; 2176 } 2177 2178 Type makeMutable() 2179 { 2180 Type t = this.nullAttributes(); 2181 t.mod = mod & MODFlags.shared_; 2182 return t; 2183 } 2184 2185 Dsymbol toDsymbol(Scope* sc) 2186 { 2187 return null; 2188 } 2189 2190 /******************************* 2191 * If this is a shell around another type, 2192 * get that other type. 2193 */ 2194 final Type toBasetype() 2195 { 2196 /* This function is used heavily. 2197 * De-virtualize it so it can be easily inlined. 2198 */ 2199 TypeEnum te; 2200 return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this; 2201 } 2202 2203 bool isBaseOf(Type t, int* poffset) 2204 { 2205 return 0; // assume not 2206 } 2207 2208 /******************************** 2209 * Determine if 'this' can be implicitly converted 2210 * to type 'to'. 2211 * Returns: 2212 * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact 2213 */ 2214 MATCH implicitConvTo(Type to) 2215 { 2216 //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); 2217 //printf("from: %s\n", toChars()); 2218 //printf("to : %s\n", to.toChars()); 2219 if (this.equals(to)) 2220 return MATCH.exact; 2221 return MATCH.nomatch; 2222 } 2223 2224 /******************************* 2225 * Determine if converting 'this' to 'to' is an identity operation, 2226 * a conversion to const operation, or the types aren't the same. 2227 * Returns: 2228 * MATCH.exact 'this' == 'to' 2229 * MATCH.constant 'to' is const 2230 * MATCH.nomatch conversion to mutable or invariant 2231 */ 2232 MATCH constConv(Type to) 2233 { 2234 //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars()); 2235 if (equals(to)) 2236 return MATCH.exact; 2237 if (ty == to.ty && MODimplicitConv(mod, to.mod)) 2238 return MATCH.constant; 2239 return MATCH.nomatch; 2240 } 2241 2242 /*************************************** 2243 * Compute MOD bits matching `this` argument type to wild parameter type. 2244 * Params: 2245 * t = corresponding parameter type 2246 * isRef = parameter is `ref` or `out` 2247 * Returns: 2248 * MOD bits 2249 */ 2250 MOD deduceWild(Type t, bool isRef) 2251 { 2252 //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm.toChars()); 2253 if (t.isWild()) 2254 { 2255 if (isImmutable()) 2256 return MODFlags.immutable_; 2257 else if (isWildConst()) 2258 { 2259 if (t.isWildConst()) 2260 return MODFlags.wild; 2261 else 2262 return MODFlags.wildconst; 2263 } 2264 else if (isWild()) 2265 return MODFlags.wild; 2266 else if (isConst()) 2267 return MODFlags.const_; 2268 else if (isMutable()) 2269 return MODFlags.mutable; 2270 else 2271 assert(0); 2272 } 2273 return 0; 2274 } 2275 2276 Type substWildTo(uint mod) 2277 { 2278 //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod); 2279 Type t; 2280 2281 if (Type tn = nextOf()) 2282 { 2283 // substitution has no effect on function pointer type. 2284 if (ty == Tpointer && tn.ty == Tfunction) 2285 { 2286 t = this; 2287 goto L1; 2288 } 2289 2290 t = tn.substWildTo(mod); 2291 if (t == tn) 2292 t = this; 2293 else 2294 { 2295 if (ty == Tpointer) 2296 t = t.pointerTo(); 2297 else if (ty == Tarray) 2298 t = t.arrayOf(); 2299 else if (ty == Tsarray) 2300 t = new TypeSArray(t, (cast(TypeSArray)this).dim.syntaxCopy()); 2301 else if (ty == Taarray) 2302 { 2303 t = new TypeAArray(t, (cast(TypeAArray)this).index.syntaxCopy()); 2304 } 2305 else if (ty == Tdelegate) 2306 { 2307 t = new TypeDelegate(t.isTypeFunction()); 2308 } 2309 else 2310 assert(0); 2311 2312 t = t.merge(); 2313 } 2314 } 2315 else 2316 t = this; 2317 2318 L1: 2319 if (isWild()) 2320 { 2321 if (mod == MODFlags.immutable_) 2322 { 2323 t = t.immutableOf(); 2324 } 2325 else if (mod == MODFlags.wildconst) 2326 { 2327 t = t.wildConstOf(); 2328 } 2329 else if (mod == MODFlags.wild) 2330 { 2331 if (isWildConst()) 2332 t = t.wildConstOf(); 2333 else 2334 t = t.wildOf(); 2335 } 2336 else if (mod == MODFlags.const_) 2337 { 2338 t = t.constOf(); 2339 } 2340 else 2341 { 2342 if (isWildConst()) 2343 t = t.constOf(); 2344 else 2345 t = t.mutableOf(); 2346 } 2347 } 2348 if (isConst()) 2349 t = t.addMod(MODFlags.const_); 2350 if (isShared()) 2351 t = t.addMod(MODFlags.shared_); 2352 2353 //printf("-Type::substWildTo t = %s\n", t.toChars()); 2354 return t; 2355 } 2356 2357 final Type unqualify(uint m) 2358 { 2359 Type t = mutableOf().unSharedOf(); 2360 2361 Type tn = ty == Tenum ? null : nextOf(); 2362 if (tn && tn.ty != Tfunction) 2363 { 2364 Type utn = tn.unqualify(m); 2365 if (utn != tn) 2366 { 2367 if (ty == Tpointer) 2368 t = utn.pointerTo(); 2369 else if (ty == Tarray) 2370 t = utn.arrayOf(); 2371 else if (ty == Tsarray) 2372 t = new TypeSArray(utn, (cast(TypeSArray)this).dim); 2373 else if (ty == Taarray) 2374 { 2375 t = new TypeAArray(utn, (cast(TypeAArray)this).index); 2376 } 2377 else 2378 assert(0); 2379 2380 t = t.merge(); 2381 } 2382 } 2383 t = t.addMod(mod & ~m); 2384 return t; 2385 } 2386 2387 /************************** 2388 * Return type with the top level of it being mutable. 2389 */ 2390 inout(Type) toHeadMutable() inout 2391 { 2392 if (!mod) 2393 return this; 2394 Type unqualThis = cast(Type) this; 2395 // `mutableOf` needs a mutable `this` only for caching 2396 return cast(inout(Type)) unqualThis.mutableOf(); 2397 } 2398 2399 inout(ClassDeclaration) isClassHandle() inout 2400 { 2401 return null; 2402 } 2403 2404 /************************************ 2405 * Return alignment to use for this type. 2406 */ 2407 structalign_t alignment() 2408 { 2409 structalign_t s; 2410 s.setDefault(); 2411 return s; 2412 } 2413 2414 /*************************************** 2415 * Use when we prefer the default initializer to be a literal, 2416 * rather than a global immutable variable. 2417 */ 2418 Expression defaultInitLiteral(const ref Loc loc) 2419 { 2420 static if (LOGDEFAULTINIT) 2421 { 2422 printf("Type::defaultInitLiteral() '%s'\n", toChars()); 2423 } 2424 return defaultInit(this, loc); 2425 } 2426 2427 // if initializer is 0 2428 bool isZeroInit(const ref Loc loc) 2429 { 2430 return false; // assume not 2431 } 2432 2433 final Identifier getTypeInfoIdent() 2434 { 2435 // _init_10TypeInfo_%s 2436 OutBuffer buf; 2437 buf.reserve(32); 2438 mangleToBuffer(this, buf); 2439 2440 const slice = buf[]; 2441 2442 // Allocate buffer on stack, fail over to using malloc() 2443 char[128] namebuf; 2444 const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; 2445 auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); 2446 2447 const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", 2448 cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); 2449 //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); 2450 assert(0 < length && length < namelen); // don't overflow the buffer 2451 2452 auto id = Identifier.idPool(name[0 .. length]); 2453 2454 if (name != namebuf.ptr) 2455 free(name); 2456 return id; 2457 } 2458 2459 /*************************************** 2460 * Return !=0 if the type or any of its subtypes is wild. 2461 */ 2462 int hasWild() const 2463 { 2464 return mod & MODFlags.wild; 2465 } 2466 2467 /*************************************** 2468 * Return !=0 if type has pointers that need to 2469 * be scanned by the GC during a collection cycle. 2470 */ 2471 bool hasPointers() 2472 { 2473 //printf("Type::hasPointers() %s, %d\n", toChars(), ty); 2474 return false; 2475 } 2476 2477 /************************************* 2478 * Detect if type has pointer fields that are initialized to void. 2479 * Local stack variables with such void fields can remain uninitialized, 2480 * leading to pointer bugs. 2481 * Returns: 2482 * true if so 2483 */ 2484 bool hasVoidInitPointers() 2485 { 2486 return false; 2487 } 2488 2489 /************************************* 2490 * Detect if this is an unsafe type because of the presence of `@system` members 2491 * Returns: 2492 * true if so 2493 */ 2494 bool hasSystemFields() 2495 { 2496 return false; 2497 } 2498 2499 /*************************************** 2500 * Returns: true if type has any invariants 2501 */ 2502 bool hasInvariant() 2503 { 2504 //printf("Type::hasInvariant() %s, %d\n", toChars(), ty); 2505 return false; 2506 } 2507 2508 /************************************* 2509 * If this is a type of something, return that something. 2510 */ 2511 Type nextOf() 2512 { 2513 return null; 2514 } 2515 2516 /************************************* 2517 * If this is a type of static array, return its base element type. 2518 */ 2519 final Type baseElemOf() 2520 { 2521 Type t = toBasetype(); 2522 TypeSArray tsa; 2523 while ((tsa = t.isTypeSArray()) !is null) 2524 t = tsa.next.toBasetype(); 2525 return t; 2526 } 2527 2528 /******************************************* 2529 * Compute number of elements for a (possibly multidimensional) static array, 2530 * or 1 for other types. 2531 * Params: 2532 * loc = for error message 2533 * Returns: 2534 * number of elements, uint.max on overflow 2535 */ 2536 final uint numberOfElems(const ref Loc loc) 2537 { 2538 //printf("Type::numberOfElems()\n"); 2539 uinteger_t n = 1; 2540 Type tb = this; 2541 while ((tb = tb.toBasetype()).ty == Tsarray) 2542 { 2543 bool overflow = false; 2544 n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow); 2545 if (overflow || n >= uint.max) 2546 { 2547 error(loc, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n); 2548 return uint.max; 2549 } 2550 tb = (cast(TypeSArray)tb).next; 2551 } 2552 return cast(uint)n; 2553 } 2554 2555 /**************************************** 2556 * Return the mask that an integral type will 2557 * fit into. 2558 */ 2559 extern (D) final uinteger_t sizemask() 2560 { 2561 uinteger_t m; 2562 switch (toBasetype().ty) 2563 { 2564 case Tbool: 2565 m = 1; 2566 break; 2567 case Tchar: 2568 case Tint8: 2569 case Tuns8: 2570 m = 0xFF; 2571 break; 2572 case Twchar: 2573 case Tint16: 2574 case Tuns16: 2575 m = 0xFFFFU; 2576 break; 2577 case Tdchar: 2578 case Tint32: 2579 case Tuns32: 2580 m = 0xFFFFFFFFU; 2581 break; 2582 case Tint64: 2583 case Tuns64: 2584 m = 0xFFFFFFFFFFFFFFFFUL; 2585 break; 2586 default: 2587 assert(0); 2588 } 2589 return m; 2590 } 2591 2592 /******************************** 2593 * true if when type goes out of scope, it needs a destructor applied. 2594 * Only applies to value types, not ref types. 2595 */ 2596 bool needsDestruction() 2597 { 2598 return false; 2599 } 2600 2601 /******************************** 2602 * true if when type is copied, it needs a copy constructor or postblit 2603 * applied. Only applies to value types, not ref types. 2604 */ 2605 bool needsCopyOrPostblit() 2606 { 2607 return false; 2608 } 2609 2610 /********************************* 2611 * 2612 */ 2613 bool needsNested() 2614 { 2615 return false; 2616 } 2617 2618 /************************************* 2619 * https://issues.dlang.org/show_bug.cgi?id=14488 2620 * Check if the inner most base type is complex or imaginary. 2621 * Should only give alerts when set to emit transitional messages. 2622 * Params: 2623 * loc = The source location. 2624 * sc = scope of the type 2625 */ 2626 extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc) 2627 { 2628 if (sc.isDeprecated()) 2629 return false; 2630 // Don't complain if we're inside a template constraint 2631 // https://issues.dlang.org/show_bug.cgi?id=21831 2632 if (sc.flags & SCOPE.constraint) 2633 return false; 2634 2635 Type t = baseElemOf(); 2636 while (t.ty == Tpointer || t.ty == Tarray) 2637 t = t.nextOf().baseElemOf(); 2638 2639 // Basetype is an opaque enum, nothing to check. 2640 if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) 2641 return false; 2642 2643 if (t.isimaginary() || t.iscomplex()) 2644 { 2645 if (sc.flags & SCOPE.Cfile) 2646 return true; // complex/imaginary not deprecated in C code 2647 Type rt; 2648 switch (t.ty) 2649 { 2650 case Tcomplex32: 2651 case Timaginary32: 2652 rt = Type.tfloat32; 2653 break; 2654 2655 case Tcomplex64: 2656 case Timaginary64: 2657 rt = Type.tfloat64; 2658 break; 2659 2660 case Tcomplex80: 2661 case Timaginary80: 2662 rt = Type.tfloat80; 2663 break; 2664 2665 default: 2666 assert(0); 2667 } 2668 // @@@DEPRECATED_2.117@@@ 2669 // Deprecated in 2.097 - Can be made an error from 2.117. 2670 // The deprecation period is longer than usual as `cfloat`, 2671 // `cdouble`, and `creal` were quite widely used. 2672 if (t.iscomplex()) 2673 { 2674 deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", 2675 toChars(), rt.toChars()); 2676 return true; 2677 } 2678 else 2679 { 2680 deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", 2681 toChars(), rt.toChars()); 2682 return true; 2683 } 2684 } 2685 return false; 2686 } 2687 2688 // For eliminating dynamic_cast 2689 TypeBasic isTypeBasic() 2690 { 2691 return null; 2692 } 2693 2694 final pure inout nothrow @nogc 2695 { 2696 /**************** 2697 * Is this type a pointer to a function? 2698 * Returns: 2699 * the function type if it is 2700 */ 2701 inout(TypeFunction) isPtrToFunction() 2702 { 2703 return (ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction) 2704 ? cast(typeof(return))(cast(TypePointer)this).next 2705 : null; 2706 } 2707 2708 /***************** 2709 * Is this type a function, delegate, or pointer to a function? 2710 * Returns: 2711 * the function type if it is 2712 */ 2713 inout(TypeFunction) isFunction_Delegate_PtrToFunction() 2714 { 2715 return ty == Tfunction ? cast(typeof(return))this : 2716 2717 ty == Tdelegate ? cast(typeof(return))(cast(TypePointer)this).next : 2718 2719 ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction ? 2720 cast(typeof(return))(cast(TypePointer)this).next : 2721 2722 null; 2723 } 2724 } 2725 2726 final pure inout nothrow @nogc @safe 2727 { 2728 inout(TypeError) isTypeError() { return ty == Terror ? cast(typeof(return))this : null; } 2729 inout(TypeVector) isTypeVector() { return ty == Tvector ? cast(typeof(return))this : null; } 2730 inout(TypeSArray) isTypeSArray() { return ty == Tsarray ? cast(typeof(return))this : null; } 2731 inout(TypeDArray) isTypeDArray() { return ty == Tarray ? cast(typeof(return))this : null; } 2732 inout(TypeAArray) isTypeAArray() { return ty == Taarray ? cast(typeof(return))this : null; } 2733 inout(TypePointer) isTypePointer() { return ty == Tpointer ? cast(typeof(return))this : null; } 2734 inout(TypeReference) isTypeReference() { return ty == Treference ? cast(typeof(return))this : null; } 2735 inout(TypeFunction) isTypeFunction() { return ty == Tfunction ? cast(typeof(return))this : null; } 2736 inout(TypeDelegate) isTypeDelegate() { return ty == Tdelegate ? cast(typeof(return))this : null; } 2737 inout(TypeIdentifier) isTypeIdentifier() { return ty == Tident ? cast(typeof(return))this : null; } 2738 inout(TypeInstance) isTypeInstance() { return ty == Tinstance ? cast(typeof(return))this : null; } 2739 inout(TypeTypeof) isTypeTypeof() { return ty == Ttypeof ? cast(typeof(return))this : null; } 2740 inout(TypeReturn) isTypeReturn() { return ty == Treturn ? cast(typeof(return))this : null; } 2741 inout(TypeStruct) isTypeStruct() { return ty == Tstruct ? cast(typeof(return))this : null; } 2742 inout(TypeEnum) isTypeEnum() { return ty == Tenum ? cast(typeof(return))this : null; } 2743 inout(TypeClass) isTypeClass() { return ty == Tclass ? cast(typeof(return))this : null; } 2744 inout(TypeTuple) isTypeTuple() { return ty == Ttuple ? cast(typeof(return))this : null; } 2745 inout(TypeSlice) isTypeSlice() { return ty == Tslice ? cast(typeof(return))this : null; } 2746 inout(TypeNull) isTypeNull() { return ty == Tnull ? cast(typeof(return))this : null; } 2747 inout(TypeMixin) isTypeMixin() { return ty == Tmixin ? cast(typeof(return))this : null; } 2748 inout(TypeTraits) isTypeTraits() { return ty == Ttraits ? cast(typeof(return))this : null; } 2749 inout(TypeNoreturn) isTypeNoreturn() { return ty == Tnoreturn ? cast(typeof(return))this : null; } 2750 inout(TypeTag) isTypeTag() { return ty == Ttag ? cast(typeof(return))this : null; } 2751 } 2752 2753 override void accept(Visitor v) 2754 { 2755 v.visit(this); 2756 } 2757 2758 final TypeFunction toTypeFunction() 2759 { 2760 if (ty != Tfunction) 2761 assert(0); 2762 return cast(TypeFunction)this; 2763 } 2764 2765 extern (D) static Types* arraySyntaxCopy(Types* types) 2766 { 2767 Types* a = null; 2768 if (types) 2769 { 2770 a = new Types(types.length); 2771 foreach (i, t; *types) 2772 { 2773 (*a)[i] = t ? t.syntaxCopy() : null; 2774 } 2775 } 2776 return a; 2777 } 2778 } 2779 2780 /*********************************************************** 2781 */ 2782 extern (C++) final class TypeError : Type 2783 { 2784 extern (D) this() @safe 2785 { 2786 super(Terror); 2787 } 2788 2789 override const(char)* kind() const 2790 { 2791 return "error"; 2792 } 2793 2794 override TypeError syntaxCopy() 2795 { 2796 // No semantic analysis done, no need to copy 2797 return this; 2798 } 2799 2800 override uinteger_t size(const ref Loc loc) 2801 { 2802 return SIZE_INVALID; 2803 } 2804 2805 override Expression defaultInitLiteral(const ref Loc loc) 2806 { 2807 return ErrorExp.get(); 2808 } 2809 2810 override void accept(Visitor v) 2811 { 2812 v.visit(this); 2813 } 2814 } 2815 2816 /*********************************************************** 2817 */ 2818 extern (C++) abstract class TypeNext : Type 2819 { 2820 Type next; 2821 2822 final extern (D) this(TY ty, Type next) @safe 2823 { 2824 super(ty); 2825 this.next = next; 2826 } 2827 2828 override final void checkDeprecated(const ref Loc loc, Scope* sc) 2829 { 2830 Type.checkDeprecated(loc, sc); 2831 if (next) // next can be NULL if TypeFunction and auto return type 2832 next.checkDeprecated(loc, sc); 2833 } 2834 2835 override final int hasWild() const 2836 { 2837 if (ty == Tfunction) 2838 return 0; 2839 if (ty == Tdelegate) 2840 return Type.hasWild(); 2841 return mod & MODFlags.wild || (next && next.hasWild()); 2842 } 2843 2844 /******************************* 2845 * For TypeFunction, nextOf() can return NULL if the function return 2846 * type is meant to be inferred, and semantic() hasn't yet ben run 2847 * on the function. After semantic(), it must no longer be NULL. 2848 */ 2849 override final Type nextOf() 2850 { 2851 return next; 2852 } 2853 2854 override final Type makeConst() 2855 { 2856 //printf("TypeNext::makeConst() %p, %s\n", this, toChars()); 2857 if (mcache && mcache.cto) 2858 { 2859 assert(mcache.cto.mod == MODFlags.const_); 2860 return mcache.cto; 2861 } 2862 TypeNext t = cast(TypeNext)Type.makeConst(); 2863 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 2864 { 2865 if (next.isShared()) 2866 { 2867 if (next.isWild()) 2868 t.next = next.sharedWildConstOf(); 2869 else 2870 t.next = next.sharedConstOf(); 2871 } 2872 else 2873 { 2874 if (next.isWild()) 2875 t.next = next.wildConstOf(); 2876 else 2877 t.next = next.constOf(); 2878 } 2879 } 2880 //printf("TypeNext::makeConst() returns %p, %s\n", t, t.toChars()); 2881 return t; 2882 } 2883 2884 override final Type makeImmutable() 2885 { 2886 //printf("TypeNext::makeImmutable() %s\n", toChars()); 2887 if (mcache && mcache.ito) 2888 { 2889 assert(mcache.ito.isImmutable()); 2890 return mcache.ito; 2891 } 2892 TypeNext t = cast(TypeNext)Type.makeImmutable(); 2893 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 2894 { 2895 t.next = next.immutableOf(); 2896 } 2897 return t; 2898 } 2899 2900 override final Type makeShared() 2901 { 2902 //printf("TypeNext::makeShared() %s\n", toChars()); 2903 if (mcache && mcache.sto) 2904 { 2905 assert(mcache.sto.mod == MODFlags.shared_); 2906 return mcache.sto; 2907 } 2908 TypeNext t = cast(TypeNext)Type.makeShared(); 2909 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 2910 { 2911 if (next.isWild()) 2912 { 2913 if (next.isConst()) 2914 t.next = next.sharedWildConstOf(); 2915 else 2916 t.next = next.sharedWildOf(); 2917 } 2918 else 2919 { 2920 if (next.isConst()) 2921 t.next = next.sharedConstOf(); 2922 else 2923 t.next = next.sharedOf(); 2924 } 2925 } 2926 //printf("TypeNext::makeShared() returns %p, %s\n", t, t.toChars()); 2927 return t; 2928 } 2929 2930 override final Type makeSharedConst() 2931 { 2932 //printf("TypeNext::makeSharedConst() %s\n", toChars()); 2933 if (mcache && mcache.scto) 2934 { 2935 assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); 2936 return mcache.scto; 2937 } 2938 TypeNext t = cast(TypeNext)Type.makeSharedConst(); 2939 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 2940 { 2941 if (next.isWild()) 2942 t.next = next.sharedWildConstOf(); 2943 else 2944 t.next = next.sharedConstOf(); 2945 } 2946 //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t.toChars()); 2947 return t; 2948 } 2949 2950 override final Type makeWild() 2951 { 2952 //printf("TypeNext::makeWild() %s\n", toChars()); 2953 if (mcache && mcache.wto) 2954 { 2955 assert(mcache.wto.mod == MODFlags.wild); 2956 return mcache.wto; 2957 } 2958 TypeNext t = cast(TypeNext)Type.makeWild(); 2959 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 2960 { 2961 if (next.isShared()) 2962 { 2963 if (next.isConst()) 2964 t.next = next.sharedWildConstOf(); 2965 else 2966 t.next = next.sharedWildOf(); 2967 } 2968 else 2969 { 2970 if (next.isConst()) 2971 t.next = next.wildConstOf(); 2972 else 2973 t.next = next.wildOf(); 2974 } 2975 } 2976 //printf("TypeNext::makeWild() returns %p, %s\n", t, t.toChars()); 2977 return t; 2978 } 2979 2980 override final Type makeWildConst() 2981 { 2982 //printf("TypeNext::makeWildConst() %s\n", toChars()); 2983 if (mcache && mcache.wcto) 2984 { 2985 assert(mcache.wcto.mod == MODFlags.wildconst); 2986 return mcache.wcto; 2987 } 2988 TypeNext t = cast(TypeNext)Type.makeWildConst(); 2989 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 2990 { 2991 if (next.isShared()) 2992 t.next = next.sharedWildConstOf(); 2993 else 2994 t.next = next.wildConstOf(); 2995 } 2996 //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t.toChars()); 2997 return t; 2998 } 2999 3000 override final Type makeSharedWild() 3001 { 3002 //printf("TypeNext::makeSharedWild() %s\n", toChars()); 3003 if (mcache && mcache.swto) 3004 { 3005 assert(mcache.swto.isSharedWild()); 3006 return mcache.swto; 3007 } 3008 TypeNext t = cast(TypeNext)Type.makeSharedWild(); 3009 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 3010 { 3011 if (next.isConst()) 3012 t.next = next.sharedWildConstOf(); 3013 else 3014 t.next = next.sharedWildOf(); 3015 } 3016 //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t.toChars()); 3017 return t; 3018 } 3019 3020 override final Type makeSharedWildConst() 3021 { 3022 //printf("TypeNext::makeSharedWildConst() %s\n", toChars()); 3023 if (mcache && mcache.swcto) 3024 { 3025 assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); 3026 return mcache.swcto; 3027 } 3028 TypeNext t = cast(TypeNext)Type.makeSharedWildConst(); 3029 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) 3030 { 3031 t.next = next.sharedWildConstOf(); 3032 } 3033 //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t.toChars()); 3034 return t; 3035 } 3036 3037 override final Type makeMutable() 3038 { 3039 //printf("TypeNext::makeMutable() %p, %s\n", this, toChars()); 3040 TypeNext t = cast(TypeNext)Type.makeMutable(); 3041 if (ty == Tsarray) 3042 { 3043 t.next = next.mutableOf(); 3044 } 3045 //printf("TypeNext::makeMutable() returns %p, %s\n", t, t.toChars()); 3046 return t; 3047 } 3048 3049 override MATCH constConv(Type to) 3050 { 3051 //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars()); 3052 if (equals(to)) 3053 return MATCH.exact; 3054 3055 if (!(ty == to.ty && MODimplicitConv(mod, to.mod))) 3056 return MATCH.nomatch; 3057 3058 Type tn = to.nextOf(); 3059 if (!(tn && next.ty == tn.ty)) 3060 return MATCH.nomatch; 3061 3062 MATCH m; 3063 if (to.isConst()) // whole tail const conversion 3064 { 3065 // Recursive shared level check 3066 m = next.constConv(tn); 3067 if (m == MATCH.exact) 3068 m = MATCH.constant; 3069 } 3070 else 3071 { 3072 //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars()); 3073 m = next.equals(tn) ? MATCH.constant : MATCH.nomatch; 3074 } 3075 return m; 3076 } 3077 3078 override final MOD deduceWild(Type t, bool isRef) 3079 { 3080 if (ty == Tfunction) 3081 return 0; 3082 3083 ubyte wm; 3084 3085 Type tn = t.nextOf(); 3086 if (!isRef && (ty == Tarray || ty == Tpointer) && tn) 3087 { 3088 wm = next.deduceWild(tn, true); 3089 if (!wm) 3090 wm = Type.deduceWild(t, true); 3091 } 3092 else 3093 { 3094 wm = Type.deduceWild(t, isRef); 3095 if (!wm && tn) 3096 wm = next.deduceWild(tn, true); 3097 } 3098 3099 return wm; 3100 } 3101 3102 final void transitive() 3103 { 3104 /* Invoke transitivity of type attributes 3105 */ 3106 next = next.addMod(mod); 3107 } 3108 3109 override void accept(Visitor v) 3110 { 3111 v.visit(this); 3112 } 3113 } 3114 3115 /*********************************************************** 3116 */ 3117 extern (C++) final class TypeBasic : Type 3118 { 3119 const(char)* dstring; 3120 uint flags; 3121 3122 extern (D) this(TY ty) scope 3123 { 3124 super(ty); 3125 const(char)* d; 3126 uint flags = 0; 3127 switch (ty) 3128 { 3129 case Tvoid: 3130 d = Token.toChars(TOK.void_); 3131 break; 3132 3133 case Tint8: 3134 d = Token.toChars(TOK.int8); 3135 flags |= TFlags.integral; 3136 break; 3137 3138 case Tuns8: 3139 d = Token.toChars(TOK.uns8); 3140 flags |= TFlags.integral | TFlags.unsigned; 3141 break; 3142 3143 case Tint16: 3144 d = Token.toChars(TOK.int16); 3145 flags |= TFlags.integral; 3146 break; 3147 3148 case Tuns16: 3149 d = Token.toChars(TOK.uns16); 3150 flags |= TFlags.integral | TFlags.unsigned; 3151 break; 3152 3153 case Tint32: 3154 d = Token.toChars(TOK.int32); 3155 flags |= TFlags.integral; 3156 break; 3157 3158 case Tuns32: 3159 d = Token.toChars(TOK.uns32); 3160 flags |= TFlags.integral | TFlags.unsigned; 3161 break; 3162 3163 case Tfloat32: 3164 d = Token.toChars(TOK.float32); 3165 flags |= TFlags.floating | TFlags.real_; 3166 break; 3167 3168 case Tint64: 3169 d = Token.toChars(TOK.int64); 3170 flags |= TFlags.integral; 3171 break; 3172 3173 case Tuns64: 3174 d = Token.toChars(TOK.uns64); 3175 flags |= TFlags.integral | TFlags.unsigned; 3176 break; 3177 3178 case Tint128: 3179 d = Token.toChars(TOK.int128); 3180 flags |= TFlags.integral; 3181 break; 3182 3183 case Tuns128: 3184 d = Token.toChars(TOK.uns128); 3185 flags |= TFlags.integral | TFlags.unsigned; 3186 break; 3187 3188 case Tfloat64: 3189 d = Token.toChars(TOK.float64); 3190 flags |= TFlags.floating | TFlags.real_; 3191 break; 3192 3193 case Tfloat80: 3194 d = Token.toChars(TOK.float80); 3195 flags |= TFlags.floating | TFlags.real_; 3196 break; 3197 3198 case Timaginary32: 3199 d = Token.toChars(TOK.imaginary32); 3200 flags |= TFlags.floating | TFlags.imaginary; 3201 break; 3202 3203 case Timaginary64: 3204 d = Token.toChars(TOK.imaginary64); 3205 flags |= TFlags.floating | TFlags.imaginary; 3206 break; 3207 3208 case Timaginary80: 3209 d = Token.toChars(TOK.imaginary80); 3210 flags |= TFlags.floating | TFlags.imaginary; 3211 break; 3212 3213 case Tcomplex32: 3214 d = Token.toChars(TOK.complex32); 3215 flags |= TFlags.floating | TFlags.complex; 3216 break; 3217 3218 case Tcomplex64: 3219 d = Token.toChars(TOK.complex64); 3220 flags |= TFlags.floating | TFlags.complex; 3221 break; 3222 3223 case Tcomplex80: 3224 d = Token.toChars(TOK.complex80); 3225 flags |= TFlags.floating | TFlags.complex; 3226 break; 3227 3228 case Tbool: 3229 d = "bool"; 3230 flags |= TFlags.integral | TFlags.unsigned; 3231 break; 3232 3233 case Tchar: 3234 d = Token.toChars(TOK.char_); 3235 flags |= TFlags.integral | TFlags.unsigned; 3236 break; 3237 3238 case Twchar: 3239 d = Token.toChars(TOK.wchar_); 3240 flags |= TFlags.integral | TFlags.unsigned; 3241 break; 3242 3243 case Tdchar: 3244 d = Token.toChars(TOK.dchar_); 3245 flags |= TFlags.integral | TFlags.unsigned; 3246 break; 3247 3248 default: 3249 assert(0); 3250 } 3251 this.dstring = d; 3252 this.flags = flags; 3253 merge(this); 3254 } 3255 3256 override const(char)* kind() const 3257 { 3258 return dstring; 3259 } 3260 3261 override TypeBasic syntaxCopy() 3262 { 3263 // No semantic analysis done on basic types, no need to copy 3264 return this; 3265 } 3266 3267 override uinteger_t size(const ref Loc loc) 3268 { 3269 uint size; 3270 //printf("TypeBasic::size()\n"); 3271 switch (ty) 3272 { 3273 case Tint8: 3274 case Tuns8: 3275 size = 1; 3276 break; 3277 3278 case Tint16: 3279 case Tuns16: 3280 size = 2; 3281 break; 3282 3283 case Tint32: 3284 case Tuns32: 3285 case Tfloat32: 3286 case Timaginary32: 3287 size = 4; 3288 break; 3289 3290 case Tint64: 3291 case Tuns64: 3292 case Tfloat64: 3293 case Timaginary64: 3294 size = 8; 3295 break; 3296 3297 case Tfloat80: 3298 case Timaginary80: 3299 size = target.realsize; 3300 break; 3301 3302 case Tcomplex32: 3303 size = 8; 3304 break; 3305 3306 case Tcomplex64: 3307 case Tint128: 3308 case Tuns128: 3309 size = 16; 3310 break; 3311 3312 case Tcomplex80: 3313 size = target.realsize * 2; 3314 break; 3315 3316 case Tvoid: 3317 //size = Type::size(); // error message 3318 size = 1; 3319 break; 3320 3321 case Tbool: 3322 size = 1; 3323 break; 3324 3325 case Tchar: 3326 size = 1; 3327 break; 3328 3329 case Twchar: 3330 size = 2; 3331 break; 3332 3333 case Tdchar: 3334 size = 4; 3335 break; 3336 3337 default: 3338 assert(0); 3339 } 3340 //printf("TypeBasic::size() = %d\n", size); 3341 return size; 3342 } 3343 3344 override uint alignsize() 3345 { 3346 return target.alignsize(this); 3347 } 3348 3349 override bool isintegral() 3350 { 3351 //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags); 3352 return (flags & TFlags.integral) != 0; 3353 } 3354 3355 override bool isfloating() 3356 { 3357 return (flags & TFlags.floating) != 0; 3358 } 3359 3360 override bool isreal() 3361 { 3362 return (flags & TFlags.real_) != 0; 3363 } 3364 3365 override bool isimaginary() 3366 { 3367 return (flags & TFlags.imaginary) != 0; 3368 } 3369 3370 override bool iscomplex() 3371 { 3372 return (flags & TFlags.complex) != 0; 3373 } 3374 3375 override bool isscalar() 3376 { 3377 return (flags & (TFlags.integral | TFlags.floating)) != 0; 3378 } 3379 3380 override bool isunsigned() 3381 { 3382 return (flags & TFlags.unsigned) != 0; 3383 } 3384 3385 override MATCH implicitConvTo(Type to) 3386 { 3387 //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); 3388 if (this == to) 3389 return MATCH.exact; 3390 3391 if (ty == to.ty) 3392 { 3393 if (mod == to.mod) 3394 return MATCH.exact; 3395 else if (MODimplicitConv(mod, to.mod)) 3396 return MATCH.constant; 3397 else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching 3398 return MATCH.constant; 3399 else 3400 return MATCH.convert; 3401 } 3402 3403 if (ty == Tvoid || to.ty == Tvoid) 3404 return MATCH.nomatch; 3405 if (to.ty == Tbool) 3406 return MATCH.nomatch; 3407 3408 TypeBasic tob; 3409 if (to.ty == Tvector && to.deco) 3410 { 3411 TypeVector tv = cast(TypeVector)to; 3412 tob = tv.elementType(); 3413 } 3414 else if (auto te = to.isTypeEnum()) 3415 { 3416 EnumDeclaration ed = te.sym; 3417 if (ed.isSpecial()) 3418 { 3419 /* Special enums that allow implicit conversions to them 3420 * with a MATCH.convert 3421 */ 3422 tob = to.toBasetype().isTypeBasic(); 3423 } 3424 else 3425 return MATCH.nomatch; 3426 } 3427 else 3428 tob = to.isTypeBasic(); 3429 if (!tob) 3430 return MATCH.nomatch; 3431 3432 if (flags & TFlags.integral) 3433 { 3434 // Disallow implicit conversion of integers to imaginary or complex 3435 if (tob.flags & (TFlags.imaginary | TFlags.complex)) 3436 return MATCH.nomatch; 3437 3438 // If converting from integral to integral 3439 if (tob.flags & TFlags.integral) 3440 { 3441 const sz = size(Loc.initial); 3442 const tosz = tob.size(Loc.initial); 3443 3444 /* Can't convert to smaller size 3445 */ 3446 if (sz > tosz) 3447 return MATCH.nomatch; 3448 /* Can't change sign if same size 3449 */ 3450 //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned) 3451 // return MATCH.nomatch; 3452 } 3453 } 3454 else if (flags & TFlags.floating) 3455 { 3456 // Disallow implicit conversion of floating point to integer 3457 if (tob.flags & TFlags.integral) 3458 return MATCH.nomatch; 3459 3460 assert(tob.flags & TFlags.floating || to.ty == Tvector); 3461 3462 // Disallow implicit conversion from complex to non-complex 3463 if (flags & TFlags.complex && !(tob.flags & TFlags.complex)) 3464 return MATCH.nomatch; 3465 3466 // Disallow implicit conversion of real or imaginary to complex 3467 if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex) 3468 return MATCH.nomatch; 3469 3470 // Disallow implicit conversion to-from real and imaginary 3471 if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary))) 3472 return MATCH.nomatch; 3473 } 3474 return MATCH.convert; 3475 } 3476 3477 override bool isZeroInit(const ref Loc loc) 3478 { 3479 switch (ty) 3480 { 3481 case Tchar: 3482 case Twchar: 3483 case Tdchar: 3484 case Timaginary32: 3485 case Timaginary64: 3486 case Timaginary80: 3487 case Tfloat32: 3488 case Tfloat64: 3489 case Tfloat80: 3490 case Tcomplex32: 3491 case Tcomplex64: 3492 case Tcomplex80: 3493 return false; // no 3494 default: 3495 return true; // yes 3496 } 3497 } 3498 3499 // For eliminating dynamic_cast 3500 override TypeBasic isTypeBasic() 3501 { 3502 return this; 3503 } 3504 3505 override void accept(Visitor v) 3506 { 3507 v.visit(this); 3508 } 3509 } 3510 3511 /*********************************************************** 3512 * The basetype must be one of: 3513 * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2] 3514 * For AVX: 3515 * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4] 3516 */ 3517 extern (C++) final class TypeVector : Type 3518 { 3519 Type basetype; 3520 3521 extern (D) this(Type basetype) @safe 3522 { 3523 super(Tvector); 3524 this.basetype = basetype; 3525 } 3526 3527 static TypeVector create(Type basetype) @safe 3528 { 3529 return new TypeVector(basetype); 3530 } 3531 3532 override const(char)* kind() const 3533 { 3534 return "vector"; 3535 } 3536 3537 override TypeVector syntaxCopy() 3538 { 3539 return new TypeVector(basetype.syntaxCopy()); 3540 } 3541 3542 override uinteger_t size(const ref Loc loc) 3543 { 3544 return basetype.size(); 3545 } 3546 3547 override uint alignsize() 3548 { 3549 return cast(uint)basetype.size(); 3550 } 3551 3552 override bool isintegral() 3553 { 3554 //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags); 3555 return basetype.nextOf().isintegral(); 3556 } 3557 3558 override bool isfloating() 3559 { 3560 return basetype.nextOf().isfloating(); 3561 } 3562 3563 override bool isscalar() 3564 { 3565 return basetype.nextOf().isscalar(); 3566 } 3567 3568 override bool isunsigned() 3569 { 3570 return basetype.nextOf().isunsigned(); 3571 } 3572 3573 override bool isBoolean() 3574 { 3575 return false; 3576 } 3577 3578 override MATCH implicitConvTo(Type to) 3579 { 3580 //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); 3581 if (this == to) 3582 return MATCH.exact; 3583 if (to.ty != Tvector) 3584 return MATCH.nomatch; 3585 3586 TypeVector tv = cast(TypeVector)to; 3587 assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray); 3588 3589 // Can't convert to a vector which has different size. 3590 if (basetype.size() != tv.basetype.size()) 3591 return MATCH.nomatch; 3592 3593 // Allow conversion to void[] 3594 if (tv.basetype.nextOf().ty == Tvoid) 3595 return MATCH.convert; 3596 3597 // Otherwise implicitly convertible only if basetypes are. 3598 return basetype.implicitConvTo(tv.basetype); 3599 } 3600 3601 override Expression defaultInitLiteral(const ref Loc loc) 3602 { 3603 //printf("TypeVector::defaultInitLiteral()\n"); 3604 assert(basetype.ty == Tsarray); 3605 Expression e = basetype.defaultInitLiteral(loc); 3606 auto ve = new VectorExp(loc, e, this); 3607 ve.type = this; 3608 ve.dim = cast(int)(basetype.size(loc) / elementType().size(loc)); 3609 return ve; 3610 } 3611 3612 TypeBasic elementType() 3613 { 3614 assert(basetype.ty == Tsarray); 3615 TypeSArray t = cast(TypeSArray)basetype; 3616 TypeBasic tb = t.nextOf().isTypeBasic(); 3617 assert(tb); 3618 return tb; 3619 } 3620 3621 override bool isZeroInit(const ref Loc loc) 3622 { 3623 return basetype.isZeroInit(loc); 3624 } 3625 3626 override void accept(Visitor v) 3627 { 3628 v.visit(this); 3629 } 3630 } 3631 3632 /*********************************************************** 3633 */ 3634 extern (C++) abstract class TypeArray : TypeNext 3635 { 3636 final extern (D) this(TY ty, Type next) @safe 3637 { 3638 super(ty, next); 3639 } 3640 3641 override void accept(Visitor v) 3642 { 3643 v.visit(this); 3644 } 3645 } 3646 3647 /*********************************************************** 3648 * Static array, one with a fixed dimension 3649 */ 3650 extern (C++) final class TypeSArray : TypeArray 3651 { 3652 Expression dim; 3653 3654 extern (D) this(Type t, Expression dim) @safe 3655 { 3656 super(Tsarray, t); 3657 //printf("TypeSArray(%s)\n", dim.toChars()); 3658 this.dim = dim; 3659 } 3660 3661 extern (D) this(Type t) // for incomplete type 3662 { 3663 super(Tsarray, t); 3664 //printf("TypeSArray()\n"); 3665 this.dim = new IntegerExp(0); 3666 } 3667 3668 override const(char)* kind() const 3669 { 3670 return "sarray"; 3671 } 3672 3673 override TypeSArray syntaxCopy() 3674 { 3675 Type t = next.syntaxCopy(); 3676 Expression e = dim.syntaxCopy(); 3677 auto result = new TypeSArray(t, e); 3678 result.mod = mod; 3679 return result; 3680 } 3681 3682 /*** 3683 * C11 6.7.6.2-4 incomplete array type 3684 * Returns: true if incomplete type 3685 */ 3686 bool isIncomplete() 3687 { 3688 return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0; 3689 } 3690 3691 override uinteger_t size(const ref Loc loc) 3692 { 3693 //printf("TypeSArray::size()\n"); 3694 const n = numberOfElems(loc); 3695 const elemsize = baseElemOf().size(loc); 3696 bool overflow = false; 3697 const sz = mulu(n, elemsize, overflow); 3698 if (overflow || sz >= uint.max) 3699 { 3700 if (elemsize != SIZE_INVALID && n != uint.max) 3701 error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz); 3702 return SIZE_INVALID; 3703 } 3704 return sz; 3705 } 3706 3707 override uint alignsize() 3708 { 3709 return next.alignsize(); 3710 } 3711 3712 override bool isString() 3713 { 3714 TY nty = next.toBasetype().ty; 3715 return nty.isSomeChar; 3716 } 3717 3718 override bool isZeroInit(const ref Loc loc) 3719 { 3720 return next.isZeroInit(loc); 3721 } 3722 3723 override structalign_t alignment() 3724 { 3725 return next.alignment(); 3726 } 3727 3728 override MATCH constConv(Type to) 3729 { 3730 if (auto tsa = to.isTypeSArray()) 3731 { 3732 if (!dim.equals(tsa.dim)) 3733 return MATCH.nomatch; 3734 } 3735 return TypeNext.constConv(to); 3736 } 3737 3738 override MATCH implicitConvTo(Type to) 3739 { 3740 //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); 3741 if (auto ta = to.isTypeDArray()) 3742 { 3743 if (!MODimplicitConv(next.mod, ta.next.mod)) 3744 return MATCH.nomatch; 3745 3746 /* Allow conversion to void[] 3747 */ 3748 if (ta.next.ty == Tvoid) 3749 { 3750 return MATCH.convert; 3751 } 3752 3753 MATCH m = next.constConv(ta.next); 3754 if (m > MATCH.nomatch) 3755 { 3756 return MATCH.convert; 3757 } 3758 return MATCH.nomatch; 3759 } 3760 if (auto tsa = to.isTypeSArray()) 3761 { 3762 if (this == to) 3763 return MATCH.exact; 3764 3765 if (dim.equals(tsa.dim)) 3766 { 3767 MATCH m = next.implicitConvTo(tsa.next); 3768 3769 /* Allow conversion to non-interface base class. 3770 */ 3771 if (m == MATCH.convert && 3772 next.ty == Tclass) 3773 { 3774 if (auto toc = tsa.next.isTypeClass) 3775 { 3776 if (!toc.sym.isInterfaceDeclaration) 3777 return MATCH.convert; 3778 } 3779 } 3780 3781 /* Since static arrays are value types, allow 3782 * conversions from const elements to non-const 3783 * ones, just like we allow conversion from const int 3784 * to int. 3785 */ 3786 if (m >= MATCH.constant) 3787 { 3788 if (mod != to.mod) 3789 m = MATCH.constant; 3790 return m; 3791 } 3792 } 3793 } 3794 return MATCH.nomatch; 3795 } 3796 3797 override Expression defaultInitLiteral(const ref Loc loc) 3798 { 3799 static if (LOGDEFAULTINIT) 3800 { 3801 printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars()); 3802 } 3803 size_t d = cast(size_t)dim.toInteger(); 3804 Expression elementinit; 3805 if (next.ty == Tvoid) 3806 elementinit = tuns8.defaultInitLiteral(loc); 3807 else 3808 elementinit = next.defaultInitLiteral(loc); 3809 auto elements = new Expressions(d); 3810 foreach (ref e; *elements) 3811 e = null; 3812 auto ae = new ArrayLiteralExp(Loc.initial, this, elementinit, elements); 3813 return ae; 3814 } 3815 3816 override bool hasPointers() 3817 { 3818 /* Don't want to do this, because: 3819 * struct S { T* array[0]; } 3820 * may be a variable length struct. 3821 */ 3822 //if (dim.toInteger() == 0) 3823 // return false; 3824 3825 if (next.ty == Tvoid) 3826 { 3827 // Arrays of void contain arbitrary data, which may include pointers 3828 return true; 3829 } 3830 else 3831 return next.hasPointers(); 3832 } 3833 3834 override bool hasSystemFields() 3835 { 3836 return next.hasSystemFields(); 3837 } 3838 3839 override bool hasVoidInitPointers() 3840 { 3841 return next.hasVoidInitPointers(); 3842 } 3843 3844 override bool hasInvariant() 3845 { 3846 return next.hasInvariant(); 3847 } 3848 3849 override bool needsDestruction() 3850 { 3851 return next.needsDestruction(); 3852 } 3853 3854 override bool needsCopyOrPostblit() 3855 { 3856 return next.needsCopyOrPostblit(); 3857 } 3858 3859 /********************************* 3860 * 3861 */ 3862 override bool needsNested() 3863 { 3864 return next.needsNested(); 3865 } 3866 3867 override void accept(Visitor v) 3868 { 3869 v.visit(this); 3870 } 3871 } 3872 3873 /*********************************************************** 3874 * Dynamic array, no dimension 3875 */ 3876 extern (C++) final class TypeDArray : TypeArray 3877 { 3878 extern (D) this(Type t) @safe 3879 { 3880 super(Tarray, t); 3881 //printf("TypeDArray(t = %p)\n", t); 3882 } 3883 3884 override const(char)* kind() const 3885 { 3886 return "darray"; 3887 } 3888 3889 override TypeDArray syntaxCopy() 3890 { 3891 Type t = next.syntaxCopy(); 3892 if (t == next) 3893 return this; 3894 3895 auto result = new TypeDArray(t); 3896 result.mod = mod; 3897 return result; 3898 } 3899 3900 override uinteger_t size(const ref Loc loc) 3901 { 3902 //printf("TypeDArray::size()\n"); 3903 return target.ptrsize * 2; 3904 } 3905 3906 override uint alignsize() 3907 { 3908 // A DArray consists of two ptr-sized values, so align it on pointer size 3909 // boundary 3910 return target.ptrsize; 3911 } 3912 3913 override bool isString() 3914 { 3915 TY nty = next.toBasetype().ty; 3916 return nty.isSomeChar; 3917 } 3918 3919 override bool isZeroInit(const ref Loc loc) 3920 { 3921 return true; 3922 } 3923 3924 override bool isBoolean() 3925 { 3926 return true; 3927 } 3928 3929 override MATCH implicitConvTo(Type to) 3930 { 3931 //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); 3932 if (equals(to)) 3933 return MATCH.exact; 3934 3935 if (auto ta = to.isTypeDArray()) 3936 { 3937 if (!MODimplicitConv(next.mod, ta.next.mod)) 3938 return MATCH.nomatch; // not const-compatible 3939 3940 /* Allow conversion to void[] 3941 */ 3942 if (next.ty != Tvoid && ta.next.ty == Tvoid) 3943 { 3944 return MATCH.convert; 3945 } 3946 3947 MATCH m = next.constConv(ta.next); 3948 if (m > MATCH.nomatch) 3949 { 3950 if (m == MATCH.exact && mod != to.mod) 3951 m = MATCH.constant; 3952 return m; 3953 } 3954 } 3955 return Type.implicitConvTo(to); 3956 } 3957 3958 override bool hasPointers() 3959 { 3960 return true; 3961 } 3962 3963 override void accept(Visitor v) 3964 { 3965 v.visit(this); 3966 } 3967 } 3968 3969 /*********************************************************** 3970 */ 3971 extern (C++) final class TypeAArray : TypeArray 3972 { 3973 Type index; // key type 3974 Loc loc; 3975 3976 extern (D) this(Type t, Type index) @safe 3977 { 3978 super(Taarray, t); 3979 this.index = index; 3980 } 3981 3982 static TypeAArray create(Type t, Type index) @safe 3983 { 3984 return new TypeAArray(t, index); 3985 } 3986 3987 override const(char)* kind() const 3988 { 3989 return "aarray"; 3990 } 3991 3992 override TypeAArray syntaxCopy() 3993 { 3994 Type t = next.syntaxCopy(); 3995 Type ti = index.syntaxCopy(); 3996 if (t == next && ti == index) 3997 return this; 3998 3999 auto result = new TypeAArray(t, ti); 4000 result.mod = mod; 4001 return result; 4002 } 4003 4004 override uinteger_t size(const ref Loc loc) 4005 { 4006 return target.ptrsize; 4007 } 4008 4009 override bool isZeroInit(const ref Loc loc) 4010 { 4011 return true; 4012 } 4013 4014 override bool isBoolean() 4015 { 4016 return true; 4017 } 4018 4019 override bool hasPointers() 4020 { 4021 return true; 4022 } 4023 4024 override MATCH implicitConvTo(Type to) 4025 { 4026 //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); 4027 if (equals(to)) 4028 return MATCH.exact; 4029 4030 if (auto ta = to.isTypeAArray()) 4031 { 4032 if (!MODimplicitConv(next.mod, ta.next.mod)) 4033 return MATCH.nomatch; // not const-compatible 4034 4035 if (!MODimplicitConv(index.mod, ta.index.mod)) 4036 return MATCH.nomatch; // not const-compatible 4037 4038 MATCH m = next.constConv(ta.next); 4039 MATCH mi = index.constConv(ta.index); 4040 if (m > MATCH.nomatch && mi > MATCH.nomatch) 4041 { 4042 return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch; 4043 } 4044 } 4045 return Type.implicitConvTo(to); 4046 } 4047 4048 override MATCH constConv(Type to) 4049 { 4050 if (auto taa = to.isTypeAArray()) 4051 { 4052 MATCH mindex = index.constConv(taa.index); 4053 MATCH mkey = next.constConv(taa.next); 4054 // Pick the worst match 4055 return mkey < mindex ? mkey : mindex; 4056 } 4057 return Type.constConv(to); 4058 } 4059 4060 override void accept(Visitor v) 4061 { 4062 v.visit(this); 4063 } 4064 } 4065 4066 /*********************************************************** 4067 */ 4068 extern (C++) final class TypePointer : TypeNext 4069 { 4070 extern (D) this(Type t) @safe 4071 { 4072 super(Tpointer, t); 4073 } 4074 4075 static TypePointer create(Type t) @safe 4076 { 4077 return new TypePointer(t); 4078 } 4079 4080 override const(char)* kind() const 4081 { 4082 return "pointer"; 4083 } 4084 4085 override TypePointer syntaxCopy() 4086 { 4087 Type t = next.syntaxCopy(); 4088 if (t == next) 4089 return this; 4090 4091 auto result = new TypePointer(t); 4092 result.mod = mod; 4093 return result; 4094 } 4095 4096 override uinteger_t size(const ref Loc loc) 4097 { 4098 return target.ptrsize; 4099 } 4100 4101 override MATCH implicitConvTo(Type to) 4102 { 4103 //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars()); 4104 if (equals(to)) 4105 return MATCH.exact; 4106 4107 // Only convert between pointers 4108 auto tp = to.isTypePointer(); 4109 if (!tp) 4110 return MATCH.nomatch; 4111 4112 assert(this.next); 4113 assert(tp.next); 4114 4115 // Conversion to void* 4116 if (tp.next.ty == Tvoid) 4117 { 4118 // Function pointer conversion doesn't check constness? 4119 if (this.next.ty == Tfunction) 4120 return MATCH.convert; 4121 4122 if (!MODimplicitConv(next.mod, tp.next.mod)) 4123 return MATCH.nomatch; // not const-compatible 4124 4125 return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert; 4126 } 4127 4128 // Conversion between function pointers 4129 if (auto thisTf = this.next.isTypeFunction()) 4130 return thisTf.implicitPointerConv(tp.next); 4131 4132 // Default, no implicit conversion between the pointer targets 4133 MATCH m = next.constConv(tp.next); 4134 4135 if (m == MATCH.exact && mod != to.mod) 4136 m = MATCH.constant; 4137 return m; 4138 } 4139 4140 override MATCH constConv(Type to) 4141 { 4142 if (next.ty == Tfunction) 4143 { 4144 if (to.nextOf() && next.equals((cast(TypeNext)to).next)) 4145 return Type.constConv(to); 4146 else 4147 return MATCH.nomatch; 4148 } 4149 return TypeNext.constConv(to); 4150 } 4151 4152 override bool isscalar() 4153 { 4154 return true; 4155 } 4156 4157 override bool isZeroInit(const ref Loc loc) 4158 { 4159 return true; 4160 } 4161 4162 override bool hasPointers() 4163 { 4164 return true; 4165 } 4166 4167 override void accept(Visitor v) 4168 { 4169 v.visit(this); 4170 } 4171 } 4172 4173 /*********************************************************** 4174 */ 4175 extern (C++) final class TypeReference : TypeNext 4176 { 4177 extern (D) this(Type t) @safe 4178 { 4179 super(Treference, t); 4180 // BUG: what about references to static arrays? 4181 } 4182 4183 override const(char)* kind() const 4184 { 4185 return "reference"; 4186 } 4187 4188 override TypeReference syntaxCopy() 4189 { 4190 Type t = next.syntaxCopy(); 4191 if (t == next) 4192 return this; 4193 4194 auto result = new TypeReference(t); 4195 result.mod = mod; 4196 return result; 4197 } 4198 4199 override uinteger_t size(const ref Loc loc) 4200 { 4201 return target.ptrsize; 4202 } 4203 4204 override bool isZeroInit(const ref Loc loc) 4205 { 4206 return true; 4207 } 4208 4209 override void accept(Visitor v) 4210 { 4211 v.visit(this); 4212 } 4213 } 4214 4215 enum RET : int 4216 { 4217 regs = 1, // returned in registers 4218 stack = 2, // returned on stack 4219 } 4220 4221 enum TRUSTformat : int 4222 { 4223 TRUSTformatDefault, // do not emit @system when trust == TRUST.default_ 4224 TRUSTformatSystem, // emit @system when trust == TRUST.default_ 4225 } 4226 4227 alias TRUSTformatDefault = TRUSTformat.TRUSTformatDefault; 4228 alias TRUSTformatSystem = TRUSTformat.TRUSTformatSystem; 4229 4230 /*********************************************************** 4231 */ 4232 extern (C++) final class TypeFunction : TypeNext 4233 { 4234 // .next is the return type 4235 4236 ParameterList parameterList; // function parameters 4237 4238 // These flags can be accessed like `bool` properties, 4239 // getters and setters are generated for them 4240 private extern (D) static struct BitFields 4241 { 4242 bool isnothrow; /// nothrow 4243 bool isnogc; /// is @nogc 4244 bool isproperty; /// can be called without parentheses 4245 bool isref; /// returns a reference 4246 bool isreturn; /// 'this' is returned by ref 4247 bool isScopeQual; /// 'this' is scope 4248 bool isreturninferred; /// 'this' is return from inference 4249 bool isscopeinferred; /// 'this' is scope from inference 4250 bool islive; /// is @live 4251 bool incomplete; /// return type or default arguments removed 4252 bool isInOutParam; /// inout on the parameters 4253 bool isInOutQual; /// inout on the qualifier 4254 bool isctor; /// the function is a constructor 4255 bool isreturnscope; /// `this` is returned by value 4256 } 4257 4258 import dmd.common.bitfields : generateBitFields; 4259 mixin(generateBitFields!(BitFields, ushort)); 4260 4261 LINK linkage; // calling convention 4262 TRUST trust; // level of trust 4263 PURE purity = PURE.impure; 4264 byte inuse; 4265 Expressions* fargs; // function arguments 4266 4267 extern (D) this(ParameterList pl, Type treturn, LINK linkage, StorageClass stc = 0) @safe 4268 { 4269 super(Tfunction, treturn); 4270 //if (!treturn) *(char*)0=0; 4271 // assert(treturn); 4272 assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.max); 4273 this.parameterList = pl; 4274 this.linkage = linkage; 4275 4276 if (stc & STC.pure_) 4277 this.purity = PURE.fwdref; 4278 if (stc & STC.nothrow_) 4279 this.isnothrow = true; 4280 if (stc & STC.nogc) 4281 this.isnogc = true; 4282 if (stc & STC.property) 4283 this.isproperty = true; 4284 if (stc & STC.live) 4285 this.islive = true; 4286 4287 if (stc & STC.ref_) 4288 this.isref = true; 4289 if (stc & STC.return_) 4290 this.isreturn = true; 4291 if (stc & STC.returnScope) 4292 this.isreturnscope = true; 4293 if (stc & STC.returninferred) 4294 this.isreturninferred = true; 4295 if (stc & STC.scope_) 4296 this.isScopeQual = true; 4297 if (stc & STC.scopeinferred) 4298 this.isscopeinferred = true; 4299 4300 this.trust = TRUST.default_; 4301 if (stc & STC.safe) 4302 this.trust = TRUST.safe; 4303 else if (stc & STC.system) 4304 this.trust = TRUST.system; 4305 else if (stc & STC.trusted) 4306 this.trust = TRUST.trusted; 4307 } 4308 4309 static TypeFunction create(Parameters* parameters, Type treturn, ubyte varargs, LINK linkage, StorageClass stc = 0) @safe 4310 { 4311 return new TypeFunction(ParameterList(parameters, cast(VarArg)varargs), treturn, linkage, stc); 4312 } 4313 4314 override const(char)* kind() const 4315 { 4316 return "function"; 4317 } 4318 4319 override TypeFunction syntaxCopy() 4320 { 4321 Type treturn = next ? next.syntaxCopy() : null; 4322 auto t = new TypeFunction(parameterList.syntaxCopy(), treturn, linkage); 4323 t.mod = mod; 4324 t.isnothrow = isnothrow; 4325 t.isnogc = isnogc; 4326 t.islive = islive; 4327 t.purity = purity; 4328 t.isproperty = isproperty; 4329 t.isref = isref; 4330 t.isreturn = isreturn; 4331 t.isreturnscope = isreturnscope; 4332 t.isScopeQual = isScopeQual; 4333 t.isreturninferred = isreturninferred; 4334 t.isscopeinferred = isscopeinferred; 4335 t.isInOutParam = isInOutParam; 4336 t.isInOutQual = isInOutQual; 4337 t.trust = trust; 4338 t.fargs = fargs; 4339 t.isctor = isctor; 4340 return t; 4341 } 4342 4343 /******************************************** 4344 * Set 'purity' field of 'this'. 4345 * Do this lazily, as the parameter types might be forward referenced. 4346 */ 4347 void purityLevel() 4348 { 4349 TypeFunction tf = this; 4350 if (tf.purity != PURE.fwdref) 4351 return; 4352 4353 purity = PURE.const_; // assume strong until something weakens it 4354 4355 /* Evaluate what kind of purity based on the modifiers for the parameters 4356 */ 4357 foreach (i, fparam; tf.parameterList) 4358 { 4359 Type t = fparam.type; 4360 if (!t) 4361 continue; 4362 4363 if (fparam.storageClass & (STC.lazy_ | STC.out_)) 4364 { 4365 purity = PURE.weak; 4366 break; 4367 } 4368 const pref = (fparam.storageClass & STC.ref_) != 0; 4369 if (mutabilityOfType(pref, t) == 0) 4370 purity = PURE.weak; 4371 } 4372 4373 tf.purity = purity; 4374 } 4375 4376 /******************************************** 4377 * Return true if there are lazy parameters. 4378 */ 4379 bool hasLazyParameters() 4380 { 4381 foreach (i, fparam; parameterList) 4382 { 4383 if (fparam.isLazy()) 4384 return true; 4385 } 4386 return false; 4387 } 4388 4389 /******************************* 4390 * Check for `extern (D) U func(T t, ...)` variadic function type, 4391 * which has `_arguments[]` added as the first argument. 4392 * Returns: 4393 * true if D-style variadic 4394 */ 4395 bool isDstyleVariadic() const pure nothrow 4396 { 4397 return linkage == LINK.d && parameterList.varargs == VarArg.variadic; 4398 } 4399 4400 /************************************ 4401 * Take the specified storage class for p, 4402 * and use the function signature to infer whether 4403 * STC.scope_ and STC.return_ should be OR'd in. 4404 * (This will not affect the name mangling.) 4405 * Params: 4406 * tthis = type of `this` parameter, null if none 4407 * p = parameter to this function 4408 * outerVars = context variables p could escape into, if any 4409 * indirect = is this for an indirect or virtual function call? 4410 * Returns: 4411 * storage class with STC.scope_ or STC.return_ OR'd in 4412 */ 4413 StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null, 4414 bool indirect = false) 4415 { 4416 //printf("parameterStorageClass(p: %s)\n", p.toChars()); 4417 auto stc = p.storageClass; 4418 4419 // When the preview switch is enable, `in` parameters are `scope` 4420 if (stc & STC.in_ && global.params.previewIn) 4421 return stc | STC.scope_; 4422 4423 if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) 4424 return stc; 4425 4426 /* If haven't inferred the return type yet, can't infer storage classes 4427 */ 4428 if (!nextOf() || !isnothrow()) 4429 return stc; 4430 4431 purityLevel(); 4432 4433 static bool mayHavePointers(Type t) 4434 { 4435 if (auto ts = t.isTypeStruct()) 4436 { 4437 auto sym = ts.sym; 4438 if (sym.members && !sym.determineFields() && sym.type != Type.terror) 4439 // struct is forward referenced, so "may have" pointers 4440 return true; 4441 } 4442 return t.hasPointers(); 4443 } 4444 4445 // See if p can escape via any of the other parameters 4446 if (purity == PURE.weak) 4447 { 4448 /* 4449 * Indirect calls may escape p through a nested context 4450 * See: 4451 * https://issues.dlang.org/show_bug.cgi?id=24212 4452 * https://issues.dlang.org/show_bug.cgi?id=24213 4453 */ 4454 if (indirect) 4455 return stc; 4456 4457 // Check escaping through parameters 4458 foreach (i, fparam; parameterList) 4459 { 4460 Type t = fparam.type; 4461 if (!t) 4462 continue; 4463 t = t.baseElemOf(); // punch thru static arrays 4464 if (t.isMutable() && t.hasPointers()) 4465 { 4466 if (fparam.isReference() && fparam != p) 4467 return stc; 4468 4469 if (t.ty == Tdelegate) 4470 return stc; // could escape thru delegate 4471 4472 if (t.ty == Tclass) 4473 return stc; 4474 4475 /* if t is a pointer to mutable pointer 4476 */ 4477 if (auto tn = t.nextOf()) 4478 { 4479 if (tn.isMutable() && mayHavePointers(tn)) 4480 return stc; // escape through pointers 4481 } 4482 } 4483 } 4484 4485 // Check escaping through `this` 4486 if (tthis && tthis.isMutable()) 4487 { 4488 foreach (VarDeclaration v; isAggregate(tthis).fields) 4489 { 4490 if (v.hasPointers()) 4491 return stc; 4492 } 4493 } 4494 4495 // Check escaping through nested context 4496 if (outerVars && this.isMutable()) 4497 { 4498 foreach (VarDeclaration v; *outerVars) 4499 { 4500 if (v.hasPointers()) 4501 return stc; 4502 } 4503 } 4504 } 4505 4506 // Check escaping through return value 4507 Type tret = nextOf().toBasetype(); 4508 if (isref || tret.hasPointers()) 4509 { 4510 return stc | STC.scope_ | STC.return_ | STC.returnScope; 4511 } 4512 else 4513 return stc | STC.scope_; 4514 } 4515 4516 override Type addStorageClass(StorageClass stc) 4517 { 4518 //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0); 4519 TypeFunction t = Type.addStorageClass(stc).toTypeFunction(); 4520 if ((stc & STC.pure_ && !t.purity) || 4521 (stc & STC.nothrow_ && !t.isnothrow) || 4522 (stc & STC.nogc && !t.isnogc) || 4523 (stc & STC.scope_ && !t.isScopeQual) || 4524 (stc & STC.safe && t.trust < TRUST.trusted)) 4525 { 4526 // Klunky to change these 4527 auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0); 4528 tf.mod = t.mod; 4529 tf.fargs = fargs; 4530 tf.purity = t.purity; 4531 tf.isnothrow = t.isnothrow; 4532 tf.isnogc = t.isnogc; 4533 tf.isproperty = t.isproperty; 4534 tf.isref = t.isref; 4535 tf.isreturn = t.isreturn; 4536 tf.isreturnscope = t.isreturnscope; 4537 tf.isScopeQual = t.isScopeQual; 4538 tf.isreturninferred = t.isreturninferred; 4539 tf.isscopeinferred = t.isscopeinferred; 4540 tf.trust = t.trust; 4541 tf.isInOutParam = t.isInOutParam; 4542 tf.isInOutQual = t.isInOutQual; 4543 tf.isctor = t.isctor; 4544 4545 if (stc & STC.pure_) 4546 tf.purity = PURE.fwdref; 4547 if (stc & STC.nothrow_) 4548 tf.isnothrow = true; 4549 if (stc & STC.nogc) 4550 tf.isnogc = true; 4551 if (stc & STC.safe) 4552 tf.trust = TRUST.safe; 4553 if (stc & STC.scope_) 4554 { 4555 tf.isScopeQual = true; 4556 if (stc & STC.scopeinferred) 4557 tf.isscopeinferred = true; 4558 } 4559 4560 tf.deco = tf.merge().deco; 4561 t = tf; 4562 } 4563 return t; 4564 } 4565 4566 override Type substWildTo(uint) 4567 { 4568 if (!iswild && !(mod & MODFlags.wild)) 4569 return this; 4570 4571 // Substitude inout qualifier of function type to mutable or immutable 4572 // would break type system. Instead substitude inout to the most weak 4573 // qualifer - const. 4574 uint m = MODFlags.const_; 4575 4576 assert(next); 4577 Type tret = next.substWildTo(m); 4578 Parameters* params = parameterList.parameters; 4579 if (mod & MODFlags.wild) 4580 params = parameterList.parameters.copy(); 4581 for (size_t i = 0; i < params.length; i++) 4582 { 4583 Parameter p = (*params)[i]; 4584 Type t = p.type.substWildTo(m); 4585 if (t == p.type) 4586 continue; 4587 if (params == parameterList.parameters) 4588 params = parameterList.parameters.copy(); 4589 (*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null); 4590 } 4591 if (next == tret && params == parameterList.parameters) 4592 return this; 4593 4594 // Similar to TypeFunction::syntaxCopy; 4595 auto t = new TypeFunction(ParameterList(params, parameterList.varargs), tret, linkage); 4596 t.mod = ((mod & MODFlags.wild) ? (mod & ~MODFlags.wild) | MODFlags.const_ : mod); 4597 t.isnothrow = isnothrow; 4598 t.isnogc = isnogc; 4599 t.purity = purity; 4600 t.isproperty = isproperty; 4601 t.isref = isref; 4602 t.isreturn = isreturn; 4603 t.isreturnscope = isreturnscope; 4604 t.isScopeQual = isScopeQual; 4605 t.isreturninferred = isreturninferred; 4606 t.isscopeinferred = isscopeinferred; 4607 t.isInOutParam = false; 4608 t.isInOutQual = false; 4609 t.trust = trust; 4610 t.fargs = fargs; 4611 t.isctor = isctor; 4612 return t.merge(); 4613 } 4614 4615 // arguments get specially formatted 4616 private const(char)* getParamError(Expression arg, Parameter par) 4617 { 4618 if (global.gag && !global.params.v.showGaggedErrors) 4619 return null; 4620 // show qualification when toChars() is the same but types are different 4621 // https://issues.dlang.org/show_bug.cgi?id=19948 4622 // when comparing the type with strcmp, we need to drop the qualifier 4623 bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && 4624 strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; 4625 auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); 4626 OutBuffer buf; 4627 // only mention rvalue if it's relevant 4628 const rv = !arg.isLvalue() && par.isReference(); 4629 buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", 4630 rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, 4631 parameterToChars(par, this, qual)); 4632 return buf.extractChars(); 4633 } 4634 4635 private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args) 4636 { 4637 if (global.gag && !global.params.v.showGaggedErrors) 4638 return null; 4639 OutBuffer buf; 4640 buf.printf(format, args); 4641 return buf.extractChars(); 4642 } 4643 4644 /******************************** 4645 * 'args' are being matched to function 'this' 4646 * Determine match level. 4647 * Params: 4648 * tthis = type of `this` pointer, null if not member function 4649 * argumentList = arguments to function call 4650 * flag = 1: performing a partial ordering match 4651 * pMessage = address to store error message, or null 4652 * sc = context 4653 * Returns: 4654 * MATCHxxxx 4655 */ 4656 extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) 4657 { 4658 //printf("TypeFunction::callMatch() %s\n", toChars()); 4659 MATCH match = MATCH.exact; // assume exact match 4660 ubyte wildmatch = 0; 4661 4662 if (tthis) 4663 { 4664 Type t = tthis; 4665 if (t.toBasetype().ty == Tpointer) 4666 t = t.toBasetype().nextOf(); // change struct* to struct 4667 if (t.mod != mod) 4668 { 4669 if (MODimplicitConv(t.mod, mod)) 4670 match = MATCH.constant; 4671 else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_)) 4672 { 4673 match = MATCH.constant; 4674 } 4675 else 4676 return MATCH.nomatch; 4677 } 4678 if (isWild()) 4679 { 4680 if (t.isWild()) 4681 wildmatch |= MODFlags.wild; 4682 else if (t.isConst()) 4683 wildmatch |= MODFlags.const_; 4684 else if (t.isImmutable()) 4685 wildmatch |= MODFlags.immutable_; 4686 else 4687 wildmatch |= MODFlags.mutable; 4688 } 4689 } 4690 4691 const nparams = parameterList.length; 4692 if (argumentList.length > nparams) 4693 { 4694 if (parameterList.varargs == VarArg.none) 4695 { 4696 // suppress early exit if an error message is wanted, 4697 // so we can check any matching args are valid 4698 if (!pMessage) 4699 return MATCH.nomatch; 4700 } 4701 // too many args; no match 4702 match = MATCH.convert; // match ... with a "conversion" match level 4703 } 4704 4705 // https://issues.dlang.org/show_bug.cgi?id=22997 4706 if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) 4707 { 4708 OutBuffer buf; 4709 buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); 4710 if (pMessage) 4711 *pMessage = buf.extractChars(); 4712 return MATCH.nomatch; 4713 } 4714 auto resolvedArgs = resolveNamedArgs(argumentList, pMessage); 4715 Expression[] args; 4716 if (!resolvedArgs) 4717 { 4718 if (!pMessage || *pMessage) 4719 return MATCH.nomatch; 4720 4721 // if no message was provided, it was because of overflow which will be diagnosed below 4722 match = MATCH.nomatch; 4723 args = argumentList.arguments ? (*argumentList.arguments)[] : null; 4724 } 4725 else 4726 { 4727 args = (*resolvedArgs)[]; 4728 } 4729 4730 foreach (u, p; parameterList) 4731 { 4732 if (u >= args.length) 4733 break; 4734 4735 Expression arg = args[u]; 4736 if (!arg) 4737 continue; // default argument 4738 4739 Type tprm = p.type; 4740 Type targ = arg.type; 4741 4742 if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) 4743 { 4744 const isRef = p.isReference(); 4745 wildmatch |= targ.deduceWild(tprm, isRef); 4746 } 4747 } 4748 if (wildmatch) 4749 { 4750 /* Calculate wild matching modifier 4751 */ 4752 if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) 4753 wildmatch = MODFlags.const_; 4754 else if (wildmatch & MODFlags.immutable_) 4755 wildmatch = MODFlags.immutable_; 4756 else if (wildmatch & MODFlags.wild) 4757 wildmatch = MODFlags.wild; 4758 else 4759 { 4760 assert(wildmatch & MODFlags.mutable); 4761 wildmatch = MODFlags.mutable; 4762 } 4763 } 4764 4765 foreach (u, p; parameterList) 4766 { 4767 MATCH m; 4768 4769 assert(p); 4770 4771 // One or more arguments remain 4772 if (u < args.length) 4773 { 4774 Expression arg = args[u]; 4775 if (!arg) 4776 continue; // default argument 4777 m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage); 4778 } 4779 else if (p.defaultArg) 4780 continue; 4781 4782 /* prefer matching the element type rather than the array 4783 * type when more arguments are present with T[]... 4784 */ 4785 if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) 4786 goto L1; 4787 4788 //printf("\tm = %d\n", m); 4789 if (m == MATCH.nomatch) // if no match 4790 { 4791 L1: 4792 if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param 4793 { 4794 auto trailingArgs = args[u .. $]; 4795 if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage)) 4796 return vmatch < match ? vmatch : match; 4797 // Error message was already generated in `matchTypeSafeVarArgs` 4798 return MATCH.nomatch; 4799 } 4800 if (pMessage && u >= args.length) 4801 *pMessage = getMatchError("missing argument for parameter #%d: `%s`", 4802 u + 1, parameterToChars(p, this, false)); 4803 // If an error happened previously, `pMessage` was already filled 4804 else if (pMessage && !*pMessage) 4805 *pMessage = getParamError(args[u], p); 4806 4807 return MATCH.nomatch; 4808 } 4809 if (m < match) 4810 match = m; // pick worst match 4811 } 4812 4813 if (pMessage && !parameterList.varargs && args.length > nparams) 4814 { 4815 // all parameters had a match, but there are surplus args 4816 *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length); 4817 return MATCH.nomatch; 4818 } 4819 //printf("match = %d\n", match); 4820 return match; 4821 } 4822 4823 /******************************** 4824 * Convert an `argumentList`, which may contain named arguments, into 4825 * a list of arguments in the order of the parameter list. 4826 * 4827 * Params: 4828 * argumentList = array of function arguments 4829 * pMessage = address to store error message, or `null` 4830 * Returns: re-ordered argument list, or `null` on error 4831 */ 4832 extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, const(char)** pMessage) 4833 { 4834 Expression[] args = argumentList.arguments ? (*argumentList.arguments)[] : null; 4835 Identifier[] names = argumentList.names ? (*argumentList.names)[] : null; 4836 auto newArgs = new Expressions(parameterList.length); 4837 newArgs.zero(); 4838 size_t ci = 0; 4839 bool hasNamedArgs = false; 4840 foreach (i, arg; args) 4841 { 4842 if (!arg) 4843 { 4844 ci++; 4845 continue; 4846 } 4847 auto name = i < names.length ? names[i] : null; 4848 if (name) 4849 { 4850 hasNamedArgs = true; 4851 const pi = findParameterIndex(name); 4852 if (pi == -1) 4853 { 4854 if (pMessage) 4855 *pMessage = getMatchError("no parameter named `%s`", name.toChars()); 4856 return null; 4857 } 4858 ci = pi; 4859 } 4860 if (ci >= newArgs.length) 4861 { 4862 if (!parameterList.varargs) 4863 { 4864 // Without named args, let the caller diagnose argument overflow 4865 if (hasNamedArgs && pMessage) 4866 *pMessage = getMatchError("argument `%s` goes past end of parameter list", arg.toChars()); 4867 return null; 4868 } 4869 while (ci >= newArgs.length) 4870 newArgs.push(null); 4871 } 4872 4873 if ((*newArgs)[ci]) 4874 { 4875 if (pMessage) 4876 *pMessage = getMatchError("parameter `%s` assigned twice", parameterList[ci].toChars()); 4877 return null; 4878 } 4879 (*newArgs)[ci++] = arg; 4880 } 4881 foreach (i, arg; (*newArgs)[]) 4882 { 4883 if (arg || parameterList[i].defaultArg) 4884 continue; 4885 4886 if (parameterList.varargs != VarArg.none && i + 1 == newArgs.length) 4887 continue; 4888 4889 if (pMessage) 4890 *pMessage = getMatchError("missing argument for parameter #%d: `%s`", 4891 i + 1, parameterToChars(parameterList[i], this, false)); 4892 return null; 4893 } 4894 // strip trailing nulls from default arguments 4895 size_t e = newArgs.length; 4896 while (e > 0 && (*newArgs)[e - 1] is null) 4897 { 4898 --e; 4899 } 4900 newArgs.setDim(e); 4901 return newArgs; 4902 } 4903 4904 /+ 4905 + Checks whether this function type is convertible to ` to` 4906 + when used in a function pointer / delegate. 4907 + 4908 + Params: 4909 + to = target type 4910 + 4911 + Returns: 4912 + MATCH.nomatch: `to` is not a covaraint function 4913 + MATCH.convert: `to` is a covaraint function 4914 + MATCH.exact: `to` is identical to this function 4915 +/ 4916 private MATCH implicitPointerConv(Type to) 4917 { 4918 assert(to); 4919 4920 if (this.equals(to)) 4921 return MATCH.constant; 4922 4923 if (this.covariant(to) == Covariant.yes) 4924 { 4925 Type tret = this.nextOf(); 4926 Type toret = to.nextOf(); 4927 if (tret.ty == Tclass && toret.ty == Tclass) 4928 { 4929 /* https://issues.dlang.org/show_bug.cgi?id=10219 4930 * Check covariant interface return with offset tweaking. 4931 * interface I {} 4932 * class C : Object, I {} 4933 * I function() dg = function C() {} // should be error 4934 */ 4935 int offset = 0; 4936 if (toret.isBaseOf(tret, &offset) && offset != 0) 4937 return MATCH.nomatch; 4938 } 4939 return MATCH.convert; 4940 } 4941 4942 return MATCH.nomatch; 4943 } 4944 4945 /** Extends TypeNext.constConv by also checking for matching attributes **/ 4946 override MATCH constConv(Type to) 4947 { 4948 // Attributes need to match exactly, otherwise it's an implicit conversion 4949 if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to)) 4950 return MATCH.nomatch; 4951 4952 return super.constConv(to); 4953 } 4954 4955 extern (D) bool checkRetType(const ref Loc loc) 4956 { 4957 Type tb = next.toBasetype(); 4958 if (tb.ty == Tfunction) 4959 { 4960 error(loc, "functions cannot return a function"); 4961 next = Type.terror; 4962 } 4963 if (tb.ty == Ttuple) 4964 { 4965 error(loc, "functions cannot return a sequence (use `std.typecons.Tuple`)"); 4966 next = Type.terror; 4967 } 4968 if (!isref && (tb.ty == Tstruct || tb.ty == Tsarray)) 4969 { 4970 if (auto ts = tb.baseElemOf().isTypeStruct()) 4971 { 4972 if (!ts.sym.members) 4973 { 4974 error(loc, "functions cannot return opaque type `%s` by value", tb.toChars()); 4975 next = Type.terror; 4976 } 4977 } 4978 } 4979 if (tb.ty == Terror) 4980 return true; 4981 return false; 4982 } 4983 4984 4985 /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise. 4986 bool iswild() const pure nothrow @safe @nogc 4987 { 4988 return isInOutParam || isInOutQual; 4989 } 4990 4991 /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other` 4992 extern (D) bool attributesEqual(const scope TypeFunction other, bool trustSystemEqualsDefault = true) const pure nothrow @safe @nogc 4993 { 4994 // @@@DEPRECATED_2.112@@@ 4995 // See semantic2.d Semantic2Visitor.visit(FuncDeclaration): 4996 // Two overloads that are identical except for one having an explicit `@system` 4997 // attribute is currently in deprecation, and will become an error in 2.104 for 4998 // `extern(C)`, and 2.112 for `extern(D)` code respectively. Once the deprecation 4999 // period has passed, the trustSystemEqualsDefault=true behaviour should be made 5000 // the default, then we can remove the `cannot overload extern(...) function` 5001 // errors as they will become dead code as a result. 5002 return (this.trust == other.trust || 5003 (trustSystemEqualsDefault && this.trust <= TRUST.system && other.trust <= TRUST.system)) && 5004 this.purity == other.purity && 5005 this.isnothrow == other.isnothrow && 5006 this.isnogc == other.isnogc && 5007 this.islive == other.islive; 5008 } 5009 5010 override void accept(Visitor v) 5011 { 5012 v.visit(this); 5013 } 5014 5015 /** 5016 * Look for the index of parameter `ident` in the parameter list 5017 * 5018 * Params: 5019 * ident = identifier of parameter to search for 5020 * Returns: index of parameter with name `ident` or -1 if not found 5021 */ 5022 private extern(D) ptrdiff_t findParameterIndex(Identifier ident) 5023 { 5024 foreach (i, p; this.parameterList) 5025 { 5026 if (p.ident == ident) 5027 return i; 5028 } 5029 return -1; 5030 } 5031 } 5032 5033 /*********************************************************** 5034 */ 5035 extern (C++) final class TypeDelegate : TypeNext 5036 { 5037 // .next is a TypeFunction 5038 5039 extern (D) this(TypeFunction t) @safe 5040 { 5041 super(Tfunction, t); 5042 ty = Tdelegate; 5043 } 5044 5045 static TypeDelegate create(TypeFunction t) @safe 5046 { 5047 return new TypeDelegate(t); 5048 } 5049 5050 override const(char)* kind() const 5051 { 5052 return "delegate"; 5053 } 5054 5055 override TypeDelegate syntaxCopy() 5056 { 5057 auto tf = next.syntaxCopy().isTypeFunction(); 5058 if (tf == next) 5059 return this; 5060 5061 auto result = new TypeDelegate(tf); 5062 result.mod = mod; 5063 return result; 5064 } 5065 5066 override Type addStorageClass(StorageClass stc) 5067 { 5068 TypeDelegate t = cast(TypeDelegate)Type.addStorageClass(stc); 5069 return t; 5070 } 5071 5072 override uinteger_t size(const ref Loc loc) 5073 { 5074 return target.ptrsize * 2; 5075 } 5076 5077 override uint alignsize() 5078 { 5079 return target.ptrsize; 5080 } 5081 5082 override MATCH implicitConvTo(Type to) 5083 { 5084 //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to); 5085 //printf("from: %s\n", toChars()); 5086 //printf("to : %s\n", to.toChars()); 5087 if (this.equals(to)) 5088 return MATCH.exact; 5089 5090 if (auto toDg = to.isTypeDelegate()) 5091 { 5092 MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next); 5093 5094 // Retain the old behaviour for this refactoring 5095 // Should probably be changed to constant to match function pointers 5096 if (m > MATCH.convert) 5097 m = MATCH.convert; 5098 5099 return m; 5100 } 5101 5102 return MATCH.nomatch; 5103 } 5104 5105 override bool isZeroInit(const ref Loc loc) 5106 { 5107 return true; 5108 } 5109 5110 override bool isBoolean() 5111 { 5112 return true; 5113 } 5114 5115 override bool hasPointers() 5116 { 5117 return true; 5118 } 5119 5120 override void accept(Visitor v) 5121 { 5122 v.visit(this); 5123 } 5124 } 5125 5126 /** 5127 * This is a shell containing a TraitsExp that can be 5128 * either resolved to a type or to a symbol. 5129 * 5130 * The point is to allow AliasDeclarationY to use `__traits()`, see https://issues.dlang.org/show_bug.cgi?id=7804. 5131 */ 5132 extern (C++) final class TypeTraits : Type 5133 { 5134 Loc loc; 5135 /// The expression to resolve as type or symbol. 5136 TraitsExp exp; 5137 /// Cached type/symbol after semantic analysis. 5138 RootObject obj; 5139 5140 final extern (D) this(const ref Loc loc, TraitsExp exp) @safe 5141 { 5142 super(Ttraits); 5143 this.loc = loc; 5144 this.exp = exp; 5145 } 5146 5147 override const(char)* kind() const 5148 { 5149 return "traits"; 5150 } 5151 5152 override TypeTraits syntaxCopy() 5153 { 5154 TraitsExp te = exp.syntaxCopy(); 5155 TypeTraits tt = new TypeTraits(loc, te); 5156 tt.mod = mod; 5157 return tt; 5158 } 5159 5160 override Dsymbol toDsymbol(Scope* sc) 5161 { 5162 Type t; 5163 Expression e; 5164 Dsymbol s; 5165 resolve(this, loc, sc, e, t, s); 5166 if (t && t.ty != Terror) 5167 s = t.toDsymbol(sc); 5168 else if (e) 5169 s = getDsymbol(e); 5170 5171 return s; 5172 } 5173 5174 override void accept(Visitor v) 5175 { 5176 v.visit(this); 5177 } 5178 5179 override uinteger_t size(const ref Loc loc) 5180 { 5181 return SIZE_INVALID; 5182 } 5183 } 5184 5185 /****** 5186 * Implements mixin types. 5187 * 5188 * Semantic analysis will convert it to a real type. 5189 */ 5190 extern (C++) final class TypeMixin : Type 5191 { 5192 Loc loc; 5193 Expressions* exps; 5194 RootObject obj; // cached result of semantic analysis. 5195 5196 extern (D) this(const ref Loc loc, Expressions* exps) @safe 5197 { 5198 super(Tmixin); 5199 this.loc = loc; 5200 this.exps = exps; 5201 } 5202 5203 override const(char)* kind() const 5204 { 5205 return "mixin"; 5206 } 5207 5208 override TypeMixin syntaxCopy() 5209 { 5210 return new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); 5211 } 5212 5213 override Dsymbol toDsymbol(Scope* sc) 5214 { 5215 Type t; 5216 Expression e; 5217 Dsymbol s; 5218 resolve(this, loc, sc, e, t, s); 5219 if (t) 5220 s = t.toDsymbol(sc); 5221 else if (e) 5222 s = getDsymbol(e); 5223 5224 return s; 5225 } 5226 5227 override void accept(Visitor v) 5228 { 5229 v.visit(this); 5230 } 5231 } 5232 5233 /*********************************************************** 5234 */ 5235 extern (C++) abstract class TypeQualified : Type 5236 { 5237 Loc loc; 5238 5239 // array of Identifier and TypeInstance, 5240 // representing ident.ident!tiargs.ident. ... etc. 5241 Objects idents; 5242 5243 final extern (D) this(TY ty, Loc loc) 5244 { 5245 super(ty); 5246 this.loc = loc; 5247 } 5248 5249 // abstract override so that using `TypeQualified.syntaxCopy` gets 5250 // us a `TypeQualified` 5251 abstract override TypeQualified syntaxCopy(); 5252 5253 extern (D) final void syntaxCopyHelper(TypeQualified t) 5254 { 5255 //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t.toChars(), toChars()); 5256 idents.setDim(t.idents.length); 5257 for (size_t i = 0; i < idents.length; i++) 5258 { 5259 RootObject id = t.idents[i]; 5260 with (DYNCAST) final switch (id.dyncast()) 5261 { 5262 case object: 5263 break; 5264 case expression: 5265 Expression e = cast(Expression)id; 5266 e = e.syntaxCopy(); 5267 id = e; 5268 break; 5269 case dsymbol: 5270 TemplateInstance ti = cast(TemplateInstance)id; 5271 ti = ti.syntaxCopy(null); 5272 id = ti; 5273 break; 5274 case type: 5275 Type tx = cast(Type)id; 5276 tx = tx.syntaxCopy(); 5277 id = tx; 5278 break; 5279 case identifier: 5280 case tuple: 5281 case parameter: 5282 case statement: 5283 case condition: 5284 case templateparameter: 5285 case initializer: 5286 } 5287 idents[i] = id; 5288 } 5289 } 5290 5291 extern (D) final void addIdent(Identifier ident) 5292 { 5293 idents.push(ident); 5294 } 5295 5296 extern (D) final void addInst(TemplateInstance inst) 5297 { 5298 idents.push(inst); 5299 } 5300 5301 extern (D) final void addIndex(RootObject e) 5302 { 5303 idents.push(e); 5304 } 5305 5306 override uinteger_t size(const ref Loc loc) 5307 { 5308 error(this.loc, "size of type `%s` is not known", toChars()); 5309 return SIZE_INVALID; 5310 } 5311 5312 override void accept(Visitor v) 5313 { 5314 v.visit(this); 5315 } 5316 } 5317 5318 /*********************************************************** 5319 */ 5320 extern (C++) final class TypeIdentifier : TypeQualified 5321 { 5322 Identifier ident; 5323 5324 // The symbol representing this identifier, before alias resolution 5325 Dsymbol originalSymbol; 5326 5327 extern (D) this(const ref Loc loc, Identifier ident) 5328 { 5329 super(Tident, loc); 5330 this.ident = ident; 5331 } 5332 5333 static TypeIdentifier create(const ref Loc loc, Identifier ident) 5334 { 5335 return new TypeIdentifier(loc, ident); 5336 } 5337 5338 override const(char)* kind() const 5339 { 5340 return "identifier"; 5341 } 5342 5343 override TypeIdentifier syntaxCopy() 5344 { 5345 auto t = new TypeIdentifier(loc, ident); 5346 t.syntaxCopyHelper(this); 5347 t.mod = mod; 5348 return t; 5349 } 5350 5351 /***************************************** 5352 * See if type resolves to a symbol, if so, 5353 * return that symbol. 5354 */ 5355 override Dsymbol toDsymbol(Scope* sc) 5356 { 5357 //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); 5358 if (!sc) 5359 return null; 5360 5361 Type t; 5362 Expression e; 5363 Dsymbol s; 5364 resolve(this, loc, sc, e, t, s); 5365 if (t && t.ty != Tident) 5366 s = t.toDsymbol(sc); 5367 if (e) 5368 s = getDsymbol(e); 5369 5370 return s; 5371 } 5372 5373 override void accept(Visitor v) 5374 { 5375 v.visit(this); 5376 } 5377 } 5378 5379 /*********************************************************** 5380 * Similar to TypeIdentifier, but with a TemplateInstance as the root 5381 */ 5382 extern (C++) final class TypeInstance : TypeQualified 5383 { 5384 TemplateInstance tempinst; 5385 5386 extern (D) this(const ref Loc loc, TemplateInstance tempinst) 5387 { 5388 super(Tinstance, loc); 5389 this.tempinst = tempinst; 5390 } 5391 5392 override const(char)* kind() const 5393 { 5394 return "instance"; 5395 } 5396 5397 override TypeInstance syntaxCopy() 5398 { 5399 //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.length); 5400 auto t = new TypeInstance(loc, tempinst.syntaxCopy(null)); 5401 t.syntaxCopyHelper(this); 5402 t.mod = mod; 5403 return t; 5404 } 5405 5406 override Dsymbol toDsymbol(Scope* sc) 5407 { 5408 Type t; 5409 Expression e; 5410 Dsymbol s; 5411 //printf("TypeInstance::semantic(%s)\n", toChars()); 5412 resolve(this, loc, sc, e, t, s); 5413 if (t && t.ty != Tinstance) 5414 s = t.toDsymbol(sc); 5415 return s; 5416 } 5417 5418 override void accept(Visitor v) 5419 { 5420 v.visit(this); 5421 } 5422 } 5423 5424 /*********************************************************** 5425 */ 5426 extern (C++) final class TypeTypeof : TypeQualified 5427 { 5428 Expression exp; 5429 int inuse; 5430 5431 extern (D) this(const ref Loc loc, Expression exp) 5432 { 5433 super(Ttypeof, loc); 5434 this.exp = exp; 5435 } 5436 5437 override const(char)* kind() const 5438 { 5439 return "typeof"; 5440 } 5441 5442 override TypeTypeof syntaxCopy() 5443 { 5444 //printf("TypeTypeof::syntaxCopy() %s\n", toChars()); 5445 auto t = new TypeTypeof(loc, exp.syntaxCopy()); 5446 t.syntaxCopyHelper(this); 5447 t.mod = mod; 5448 return t; 5449 } 5450 5451 override Dsymbol toDsymbol(Scope* sc) 5452 { 5453 //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); 5454 Expression e; 5455 Type t; 5456 Dsymbol s; 5457 resolve(this, loc, sc, e, t, s); 5458 return s; 5459 } 5460 5461 override uinteger_t size(const ref Loc loc) 5462 { 5463 if (exp.type) 5464 return exp.type.size(loc); 5465 else 5466 return TypeQualified.size(loc); 5467 } 5468 5469 override void accept(Visitor v) 5470 { 5471 v.visit(this); 5472 } 5473 } 5474 5475 /*********************************************************** 5476 */ 5477 extern (C++) final class TypeReturn : TypeQualified 5478 { 5479 extern (D) this(const ref Loc loc) 5480 { 5481 super(Treturn, loc); 5482 } 5483 5484 override const(char)* kind() const 5485 { 5486 return "return"; 5487 } 5488 5489 override TypeReturn syntaxCopy() 5490 { 5491 auto t = new TypeReturn(loc); 5492 t.syntaxCopyHelper(this); 5493 t.mod = mod; 5494 return t; 5495 } 5496 5497 override Dsymbol toDsymbol(Scope* sc) 5498 { 5499 Expression e; 5500 Type t; 5501 Dsymbol s; 5502 resolve(this, loc, sc, e, t, s); 5503 return s; 5504 } 5505 5506 override void accept(Visitor v) 5507 { 5508 v.visit(this); 5509 } 5510 } 5511 5512 /*********************************************************** 5513 */ 5514 extern (C++) final class TypeStruct : Type 5515 { 5516 StructDeclaration sym; 5517 AliasThisRec att = AliasThisRec.fwdref; 5518 bool inuse = false; // struct currently subject of recursive method call 5519 5520 extern (D) this(StructDeclaration sym) @safe 5521 { 5522 super(Tstruct); 5523 this.sym = sym; 5524 } 5525 5526 static TypeStruct create(StructDeclaration sym) @safe 5527 { 5528 return new TypeStruct(sym); 5529 } 5530 5531 override const(char)* kind() const 5532 { 5533 return "struct"; 5534 } 5535 5536 override uinteger_t size(const ref Loc loc) 5537 { 5538 return sym.size(loc); 5539 } 5540 5541 override uint alignsize() 5542 { 5543 sym.size(Loc.initial); // give error for forward references 5544 return sym.alignsize; 5545 } 5546 5547 override TypeStruct syntaxCopy() 5548 { 5549 return this; 5550 } 5551 5552 override Dsymbol toDsymbol(Scope* sc) 5553 { 5554 return sym; 5555 } 5556 5557 override structalign_t alignment() 5558 { 5559 if (sym.alignment.isUnknown()) 5560 sym.size(sym.loc); 5561 return sym.alignment; 5562 } 5563 5564 /*************************************** 5565 * Use when we prefer the default initializer to be a literal, 5566 * rather than a global immutable variable. 5567 */ 5568 override Expression defaultInitLiteral(const ref Loc loc) 5569 { 5570 static if (LOGDEFAULTINIT) 5571 { 5572 printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); 5573 } 5574 sym.size(loc); 5575 if (sym.sizeok != Sizeok.done) 5576 return ErrorExp.get(); 5577 5578 auto structelems = new Expressions(sym.nonHiddenFields()); 5579 uint offset = 0; 5580 foreach (j; 0 .. structelems.length) 5581 { 5582 VarDeclaration vd = sym.fields[j]; 5583 Expression e; 5584 if (vd.inuse) 5585 { 5586 error(loc, "circular reference to `%s`", vd.toPrettyChars()); 5587 return ErrorExp.get(); 5588 } 5589 if (vd.offset < offset || vd.type.size() == 0) 5590 e = null; 5591 else if (vd._init) 5592 { 5593 if (vd._init.isVoidInitializer()) 5594 e = null; 5595 else 5596 e = vd.getConstInitializer(false); 5597 } 5598 else 5599 e = vd.type.defaultInitLiteral(loc); 5600 if (e && e.op == EXP.error) 5601 return e; 5602 if (e) 5603 offset = vd.offset + cast(uint)vd.type.size(); 5604 (*structelems)[j] = e; 5605 } 5606 auto structinit = new StructLiteralExp(loc, sym, structelems); 5607 5608 /* Copy from the initializer symbol for larger symbols, 5609 * otherwise the literals expressed as code get excessively large. 5610 */ 5611 if (size(loc) > target.ptrsize * 4 && !needsNested()) 5612 structinit.useStaticInit = true; 5613 5614 structinit.type = this; 5615 return structinit; 5616 } 5617 5618 override bool isZeroInit(const ref Loc loc) 5619 { 5620 // Determine zeroInit here, as this can be called before semantic2 5621 sym.determineSize(sym.loc); 5622 return sym.zeroInit; 5623 } 5624 5625 override bool isAssignable() 5626 { 5627 bool assignable = true; 5628 uint offset = ~0; // dead-store initialize to prevent spurious warning 5629 5630 sym.determineSize(sym.loc); 5631 5632 /* If any of the fields are const or immutable, 5633 * then one cannot assign this struct. 5634 */ 5635 for (size_t i = 0; i < sym.fields.length; i++) 5636 { 5637 VarDeclaration v = sym.fields[i]; 5638 //printf("%s [%d] v = (%s) %s, v.offset = %d, v.parent = %s\n", sym.toChars(), i, v.kind(), v.toChars(), v.offset, v.parent.kind()); 5639 if (i == 0) 5640 { 5641 } 5642 else if (v.offset == offset) 5643 { 5644 /* If any fields of anonymous union are assignable, 5645 * then regard union as assignable. 5646 * This is to support unsafe things like Rebindable templates. 5647 */ 5648 if (assignable) 5649 continue; 5650 } 5651 else 5652 { 5653 if (!assignable) 5654 return false; 5655 } 5656 assignable = v.type.isMutable() && v.type.isAssignable(); 5657 offset = v.offset; 5658 //printf(" -> assignable = %d\n", assignable); 5659 } 5660 5661 return assignable; 5662 } 5663 5664 override bool isBoolean() 5665 { 5666 return false; 5667 } 5668 5669 override bool needsDestruction() 5670 { 5671 return sym.dtor !is null; 5672 } 5673 5674 override bool needsCopyOrPostblit() 5675 { 5676 return sym.hasCopyCtor || sym.postblit; 5677 } 5678 5679 override bool needsNested() 5680 { 5681 if (inuse) return false; // circular type, error instead of crashing 5682 5683 inuse = true; 5684 scope(exit) inuse = false; 5685 5686 if (sym.isNested()) 5687 return true; 5688 5689 for (size_t i = 0; i < sym.fields.length; i++) 5690 { 5691 VarDeclaration v = sym.fields[i]; 5692 if (!v.isDataseg() && v.type.needsNested()) 5693 return true; 5694 } 5695 return false; 5696 } 5697 5698 override bool hasPointers() 5699 { 5700 if (sym.members && !sym.determineFields() && sym.type != Type.terror) 5701 error(sym.loc, "no size because of forward references"); 5702 5703 sym.determineTypeProperties(); 5704 return sym.hasPointerField; 5705 } 5706 5707 override bool hasVoidInitPointers() 5708 { 5709 sym.size(Loc.initial); // give error for forward references 5710 sym.determineTypeProperties(); 5711 return sym.hasVoidInitPointers; 5712 } 5713 5714 override bool hasSystemFields() 5715 { 5716 sym.size(Loc.initial); // give error for forward references 5717 sym.determineTypeProperties(); 5718 return sym.hasSystemFields; 5719 } 5720 5721 override bool hasInvariant() 5722 { 5723 sym.size(Loc.initial); // give error for forward references 5724 sym.determineTypeProperties(); 5725 return sym.hasInvariant() || sym.hasFieldWithInvariant; 5726 } 5727 5728 extern (D) MATCH implicitConvToWithoutAliasThis(Type to) 5729 { 5730 MATCH m; 5731 5732 if (ty == to.ty && sym == (cast(TypeStruct)to).sym) 5733 { 5734 m = MATCH.exact; // exact match 5735 if (mod != to.mod) 5736 { 5737 m = MATCH.constant; 5738 if (MODimplicitConv(mod, to.mod)) 5739 { 5740 } 5741 else 5742 { 5743 /* Check all the fields. If they can all be converted, 5744 * allow the conversion. 5745 */ 5746 uint offset = ~0; // dead-store to prevent spurious warning 5747 for (size_t i = 0; i < sym.fields.length; i++) 5748 { 5749 VarDeclaration v = sym.fields[i]; 5750 if (i == 0) 5751 { 5752 } 5753 else if (v.offset == offset) 5754 { 5755 if (m > MATCH.nomatch) 5756 continue; 5757 } 5758 else 5759 { 5760 if (m == MATCH.nomatch) 5761 return m; 5762 } 5763 5764 // 'from' type 5765 Type tvf = v.type.addMod(mod); 5766 5767 // 'to' type 5768 Type tv = v.type.addMod(to.mod); 5769 5770 // field match 5771 MATCH mf = tvf.implicitConvTo(tv); 5772 //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf); 5773 5774 if (mf == MATCH.nomatch) 5775 return mf; 5776 if (mf < m) // if field match is worse 5777 m = mf; 5778 offset = v.offset; 5779 } 5780 } 5781 } 5782 } 5783 return m; 5784 } 5785 5786 extern (D) MATCH implicitConvToThroughAliasThis(Type to) 5787 { 5788 MATCH m; 5789 if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing)) 5790 { 5791 if (auto ato = aliasthisOf()) 5792 { 5793 att = cast(AliasThisRec)(att | AliasThisRec.tracing); 5794 m = ato.implicitConvTo(to); 5795 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); 5796 } 5797 else 5798 m = MATCH.nomatch; // no match 5799 } 5800 return m; 5801 } 5802 5803 override MATCH implicitConvTo(Type to) 5804 { 5805 //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars()); 5806 MATCH m = implicitConvToWithoutAliasThis(to); 5807 return m ? m : implicitConvToThroughAliasThis(to); 5808 } 5809 5810 override MATCH constConv(Type to) 5811 { 5812 if (equals(to)) 5813 return MATCH.exact; 5814 if (ty == to.ty && sym == (cast(TypeStruct)to).sym && MODimplicitConv(mod, to.mod)) 5815 return MATCH.constant; 5816 return MATCH.nomatch; 5817 } 5818 5819 override MOD deduceWild(Type t, bool isRef) 5820 { 5821 if (ty == t.ty && sym == (cast(TypeStruct)t).sym) 5822 return Type.deduceWild(t, isRef); 5823 5824 ubyte wm = 0; 5825 5826 if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) 5827 { 5828 if (auto ato = aliasthisOf()) 5829 { 5830 att = cast(AliasThisRec)(att | AliasThisRec.tracing); 5831 wm = ato.deduceWild(t, isRef); 5832 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); 5833 } 5834 } 5835 5836 return wm; 5837 } 5838 5839 override inout(Type) toHeadMutable() inout 5840 { 5841 return this; 5842 } 5843 5844 override void accept(Visitor v) 5845 { 5846 v.visit(this); 5847 } 5848 } 5849 5850 /*********************************************************** 5851 */ 5852 extern (C++) final class TypeEnum : Type 5853 { 5854 EnumDeclaration sym; 5855 5856 extern (D) this(EnumDeclaration sym) @safe 5857 { 5858 super(Tenum); 5859 this.sym = sym; 5860 } 5861 5862 override const(char)* kind() const 5863 { 5864 return "enum"; 5865 } 5866 5867 override TypeEnum syntaxCopy() 5868 { 5869 return this; 5870 } 5871 5872 override uinteger_t size(const ref Loc loc) 5873 { 5874 return sym.getMemtype(loc).size(loc); 5875 } 5876 5877 Type memType(const ref Loc loc = Loc.initial) 5878 { 5879 return sym.getMemtype(loc); 5880 } 5881 5882 override uint alignsize() 5883 { 5884 Type t = memType(); 5885 if (t.ty == Terror) 5886 return 4; 5887 return t.alignsize(); 5888 } 5889 5890 override Dsymbol toDsymbol(Scope* sc) 5891 { 5892 return sym; 5893 } 5894 5895 override bool isintegral() 5896 { 5897 return memType().isintegral(); 5898 } 5899 5900 override bool isfloating() 5901 { 5902 return memType().isfloating(); 5903 } 5904 5905 override bool isreal() 5906 { 5907 return memType().isreal(); 5908 } 5909 5910 override bool isimaginary() 5911 { 5912 return memType().isimaginary(); 5913 } 5914 5915 override bool iscomplex() 5916 { 5917 return memType().iscomplex(); 5918 } 5919 5920 override bool isscalar() 5921 { 5922 return memType().isscalar(); 5923 } 5924 5925 override bool isunsigned() 5926 { 5927 return memType().isunsigned(); 5928 } 5929 5930 override bool isBoolean() 5931 { 5932 return memType().isBoolean(); 5933 } 5934 5935 override bool isString() 5936 { 5937 return memType().isString(); 5938 } 5939 5940 override bool isAssignable() 5941 { 5942 return memType().isAssignable(); 5943 } 5944 5945 override bool needsDestruction() 5946 { 5947 return memType().needsDestruction(); 5948 } 5949 5950 override bool needsCopyOrPostblit() 5951 { 5952 return memType().needsCopyOrPostblit(); 5953 } 5954 5955 override bool needsNested() 5956 { 5957 return memType().needsNested(); 5958 } 5959 5960 override MATCH implicitConvTo(Type to) 5961 { 5962 MATCH m; 5963 //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars()); 5964 if (ty == to.ty && sym == (cast(TypeEnum)to).sym) 5965 m = (mod == to.mod) ? MATCH.exact : MATCH.constant; 5966 else if (sym.getMemtype(Loc.initial).implicitConvTo(to)) 5967 m = MATCH.convert; // match with conversions 5968 else 5969 m = MATCH.nomatch; // no match 5970 return m; 5971 } 5972 5973 override MATCH constConv(Type to) 5974 { 5975 if (equals(to)) 5976 return MATCH.exact; 5977 if (ty == to.ty && sym == (cast(TypeEnum)to).sym && MODimplicitConv(mod, to.mod)) 5978 return MATCH.constant; 5979 return MATCH.nomatch; 5980 } 5981 5982 extern (D) Type toBasetype2() 5983 { 5984 if (!sym.members && !sym.memtype) 5985 return this; 5986 auto tb = sym.getMemtype(Loc.initial).toBasetype(); 5987 return tb.castMod(mod); // retain modifier bits from 'this' 5988 } 5989 5990 override bool isZeroInit(const ref Loc loc) 5991 { 5992 return sym.getDefaultValue(loc).toBool().hasValue(false); 5993 } 5994 5995 override bool hasPointers() 5996 { 5997 return memType().hasPointers(); 5998 } 5999 6000 override bool hasVoidInitPointers() 6001 { 6002 return memType().hasVoidInitPointers(); 6003 } 6004 6005 override bool hasSystemFields() 6006 { 6007 return memType().hasSystemFields(); 6008 } 6009 6010 override bool hasInvariant() 6011 { 6012 return memType().hasInvariant(); 6013 } 6014 6015 override Type nextOf() 6016 { 6017 return memType().nextOf(); 6018 } 6019 6020 override void accept(Visitor v) 6021 { 6022 v.visit(this); 6023 } 6024 } 6025 6026 /*********************************************************** 6027 */ 6028 extern (C++) final class TypeClass : Type 6029 { 6030 ClassDeclaration sym; 6031 AliasThisRec att = AliasThisRec.fwdref; 6032 CPPMANGLE cppmangle = CPPMANGLE.def; 6033 6034 extern (D) this(ClassDeclaration sym) @safe 6035 { 6036 super(Tclass); 6037 this.sym = sym; 6038 } 6039 6040 override const(char)* kind() const 6041 { 6042 return "class"; 6043 } 6044 6045 override uinteger_t size(const ref Loc loc) 6046 { 6047 return target.ptrsize; 6048 } 6049 6050 override TypeClass syntaxCopy() 6051 { 6052 return this; 6053 } 6054 6055 override Dsymbol toDsymbol(Scope* sc) 6056 { 6057 return sym; 6058 } 6059 6060 override inout(ClassDeclaration) isClassHandle() inout 6061 { 6062 return sym; 6063 } 6064 6065 override bool isBaseOf(Type t, int* poffset) 6066 { 6067 if (t && t.ty == Tclass) 6068 { 6069 ClassDeclaration cd = (cast(TypeClass)t).sym; 6070 if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) 6071 cd.dsymbolSemantic(null); 6072 if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) 6073 sym.dsymbolSemantic(null); 6074 6075 if (sym.isBaseOf(cd, poffset)) 6076 return true; 6077 } 6078 return false; 6079 } 6080 6081 extern (D) MATCH implicitConvToWithoutAliasThis(Type to) 6082 { 6083 // Run semantic before checking whether class is convertible 6084 ClassDeclaration cdto = to.isClassHandle(); 6085 if (cdto) 6086 { 6087 //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete()); 6088 if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete()) 6089 cdto.dsymbolSemantic(null); 6090 if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) 6091 sym.dsymbolSemantic(null); 6092 } 6093 MATCH m = constConv(to); 6094 if (m > MATCH.nomatch) 6095 return m; 6096 6097 if (cdto && cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod)) 6098 { 6099 //printf("'to' is base\n"); 6100 return MATCH.convert; 6101 } 6102 return MATCH.nomatch; 6103 } 6104 6105 extern (D) MATCH implicitConvToThroughAliasThis(Type to) 6106 { 6107 MATCH m; 6108 if (sym.aliasthis && !(att & AliasThisRec.tracing)) 6109 { 6110 if (auto ato = aliasthisOf()) 6111 { 6112 att = cast(AliasThisRec)(att | AliasThisRec.tracing); 6113 m = ato.implicitConvTo(to); 6114 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); 6115 } 6116 } 6117 return m; 6118 } 6119 6120 override MATCH implicitConvTo(Type to) 6121 { 6122 //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars()); 6123 MATCH m = implicitConvToWithoutAliasThis(to); 6124 return m ? m : implicitConvToThroughAliasThis(to); 6125 } 6126 6127 override MATCH constConv(Type to) 6128 { 6129 if (equals(to)) 6130 return MATCH.exact; 6131 if (ty == to.ty && sym == (cast(TypeClass)to).sym && MODimplicitConv(mod, to.mod)) 6132 return MATCH.constant; 6133 6134 /* Conversion derived to const(base) 6135 */ 6136 int offset = 0; 6137 if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod)) 6138 { 6139 // Disallow: 6140 // derived to base 6141 // inout(derived) to inout(base) 6142 if (!to.isMutable() && !to.isWild()) 6143 return MATCH.convert; 6144 } 6145 6146 return MATCH.nomatch; 6147 } 6148 6149 override MOD deduceWild(Type t, bool isRef) 6150 { 6151 ClassDeclaration cd = t.isClassHandle(); 6152 if (cd && (sym == cd || cd.isBaseOf(sym, null))) 6153 return Type.deduceWild(t, isRef); 6154 6155 ubyte wm = 0; 6156 6157 if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) 6158 { 6159 if (auto ato = aliasthisOf()) 6160 { 6161 att = cast(AliasThisRec)(att | AliasThisRec.tracing); 6162 wm = ato.deduceWild(t, isRef); 6163 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); 6164 } 6165 } 6166 6167 return wm; 6168 } 6169 6170 override inout(Type) toHeadMutable() inout 6171 { 6172 return this; 6173 } 6174 6175 override bool isZeroInit(const ref Loc loc) 6176 { 6177 return true; 6178 } 6179 6180 override bool isscope() 6181 { 6182 return sym.stack; 6183 } 6184 6185 override bool isBoolean() 6186 { 6187 return true; 6188 } 6189 6190 override bool hasPointers() 6191 { 6192 return true; 6193 } 6194 6195 override void accept(Visitor v) 6196 { 6197 v.visit(this); 6198 } 6199 } 6200 6201 /*********************************************************** 6202 */ 6203 extern (C++) final class TypeTuple : Type 6204 { 6205 // 'logically immutable' cached global - don't modify! 6206 __gshared TypeTuple empty = new TypeTuple(); 6207 6208 Parameters* arguments; // types making up the tuple 6209 6210 extern (D) this(Parameters* arguments) @safe 6211 { 6212 super(Ttuple); 6213 //printf("TypeTuple(this = %p)\n", this); 6214 this.arguments = arguments; 6215 //printf("TypeTuple() %p, %s\n", this, toChars()); 6216 debug 6217 { 6218 if (arguments) 6219 { 6220 for (size_t i = 0; i < arguments.length; i++) 6221 { 6222 Parameter arg = (*arguments)[i]; 6223 assert(arg && arg.type); 6224 } 6225 } 6226 } 6227 } 6228 6229 /**************** 6230 * Form TypeTuple from the types of the expressions. 6231 * Assume exps[] is already tuple expanded. 6232 */ 6233 extern (D) this(Expressions* exps) 6234 { 6235 super(Ttuple); 6236 auto arguments = new Parameters(exps ? exps.length : 0); 6237 if (exps) 6238 { 6239 for (size_t i = 0; i < exps.length; i++) 6240 { 6241 Expression e = (*exps)[i]; 6242 if (e.type.ty == Ttuple) 6243 error(e.loc, "cannot form sequence of sequences"); 6244 auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null); 6245 (*arguments)[i] = arg; 6246 } 6247 } 6248 this.arguments = arguments; 6249 //printf("TypeTuple() %p, %s\n", this, toChars()); 6250 } 6251 6252 static TypeTuple create(Parameters* arguments) @safe 6253 { 6254 return new TypeTuple(arguments); 6255 } 6256 6257 /******************************************* 6258 * Type tuple with 0, 1 or 2 types in it. 6259 */ 6260 extern (D) this() @safe 6261 { 6262 super(Ttuple); 6263 arguments = new Parameters(); 6264 } 6265 6266 extern (D) this(Type t1) 6267 { 6268 super(Ttuple); 6269 arguments = new Parameters(); 6270 arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null)); 6271 } 6272 6273 extern (D) this(Type t1, Type t2) 6274 { 6275 super(Ttuple); 6276 arguments = new Parameters(); 6277 arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null)); 6278 arguments.push(new Parameter(Loc.initial, 0, t2, null, null, null)); 6279 } 6280 6281 static TypeTuple create() @safe 6282 { 6283 return new TypeTuple(); 6284 } 6285 6286 static TypeTuple create(Type t1) 6287 { 6288 return new TypeTuple(t1); 6289 } 6290 6291 static TypeTuple create(Type t1, Type t2) 6292 { 6293 return new TypeTuple(t1, t2); 6294 } 6295 6296 override const(char)* kind() const 6297 { 6298 return "sequence"; 6299 } 6300 6301 override TypeTuple syntaxCopy() 6302 { 6303 Parameters* args = Parameter.arraySyntaxCopy(arguments); 6304 auto t = new TypeTuple(args); 6305 t.mod = mod; 6306 return t; 6307 } 6308 6309 override bool equals(const RootObject o) const 6310 { 6311 Type t = cast(Type)o; 6312 //printf("TypeTuple::equals(%s, %s)\n", toChars(), t.toChars()); 6313 if (this == t) 6314 return true; 6315 if (auto tt = t.isTypeTuple()) 6316 { 6317 if (arguments.length == tt.arguments.length) 6318 { 6319 for (size_t i = 0; i < tt.arguments.length; i++) 6320 { 6321 const Parameter arg1 = (*arguments)[i]; 6322 Parameter arg2 = (*tt.arguments)[i]; 6323 if (!arg1.type.equals(arg2.type)) 6324 return false; 6325 } 6326 return true; 6327 } 6328 } 6329 return false; 6330 } 6331 6332 override MATCH implicitConvTo(Type to) 6333 { 6334 if (this == to) 6335 return MATCH.exact; 6336 if (auto tt = to.isTypeTuple()) 6337 { 6338 if (arguments.length == tt.arguments.length) 6339 { 6340 MATCH m = MATCH.exact; 6341 for (size_t i = 0; i < tt.arguments.length; i++) 6342 { 6343 Parameter arg1 = (*arguments)[i]; 6344 Parameter arg2 = (*tt.arguments)[i]; 6345 MATCH mi = arg1.type.implicitConvTo(arg2.type); 6346 if (mi < m) 6347 m = mi; 6348 } 6349 return m; 6350 } 6351 } 6352 return MATCH.nomatch; 6353 } 6354 6355 override void accept(Visitor v) 6356 { 6357 v.visit(this); 6358 } 6359 } 6360 6361 /*********************************************************** 6362 * This is so we can slice a TypeTuple 6363 */ 6364 extern (C++) final class TypeSlice : TypeNext 6365 { 6366 Expression lwr; 6367 Expression upr; 6368 6369 extern (D) this(Type next, Expression lwr, Expression upr) @safe 6370 { 6371 super(Tslice, next); 6372 //printf("TypeSlice[%s .. %s]\n", lwr.toChars(), upr.toChars()); 6373 this.lwr = lwr; 6374 this.upr = upr; 6375 } 6376 6377 override const(char)* kind() const 6378 { 6379 return "slice"; 6380 } 6381 6382 override TypeSlice syntaxCopy() 6383 { 6384 auto t = new TypeSlice(next.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy()); 6385 t.mod = mod; 6386 return t; 6387 } 6388 6389 override void accept(Visitor v) 6390 { 6391 v.visit(this); 6392 } 6393 } 6394 6395 /*********************************************************** 6396 */ 6397 extern (C++) final class TypeNull : Type 6398 { 6399 extern (D) this() @safe 6400 { 6401 //printf("TypeNull %p\n", this); 6402 super(Tnull); 6403 } 6404 6405 override const(char)* kind() const 6406 { 6407 return "null"; 6408 } 6409 6410 override TypeNull syntaxCopy() 6411 { 6412 // No semantic analysis done, no need to copy 6413 return this; 6414 } 6415 6416 override MATCH implicitConvTo(Type to) 6417 { 6418 //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to); 6419 //printf("from: %s\n", toChars()); 6420 //printf("to : %s\n", to.toChars()); 6421 MATCH m = Type.implicitConvTo(to); 6422 if (m != MATCH.nomatch) 6423 return m; 6424 6425 // NULL implicitly converts to any pointer type or dynamic array 6426 //if (type.ty == Tpointer && type.nextOf().ty == Tvoid) 6427 { 6428 Type tb = to.toBasetype(); 6429 if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate) 6430 return MATCH.constant; 6431 } 6432 6433 return MATCH.nomatch; 6434 } 6435 6436 override bool hasPointers() 6437 { 6438 /* Although null isn't dereferencable, treat it as a pointer type for 6439 * attribute inference, generic code, etc. 6440 */ 6441 return true; 6442 } 6443 6444 override bool isBoolean() 6445 { 6446 return true; 6447 } 6448 6449 override uinteger_t size(const ref Loc loc) 6450 { 6451 return tvoidptr.size(loc); 6452 } 6453 6454 override void accept(Visitor v) 6455 { 6456 v.visit(this); 6457 } 6458 } 6459 6460 /*********************************************************** 6461 */ 6462 extern (C++) final class TypeNoreturn : Type 6463 { 6464 extern (D) this() @safe 6465 { 6466 //printf("TypeNoreturn %p\n", this); 6467 super(Tnoreturn); 6468 } 6469 6470 override const(char)* kind() const 6471 { 6472 return "noreturn"; 6473 } 6474 6475 override TypeNoreturn syntaxCopy() 6476 { 6477 // No semantic analysis done, no need to copy 6478 return this; 6479 } 6480 6481 override MATCH implicitConvTo(Type to) 6482 { 6483 //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to); 6484 //printf("from: %s\n", toChars()); 6485 //printf("to : %s\n", to.toChars()); 6486 if (this.equals(to)) 6487 return MATCH.exact; 6488 6489 // Different qualifiers? 6490 if (to.ty == Tnoreturn) 6491 return MATCH.constant; 6492 6493 // Implicitly convertible to any type 6494 return MATCH.convert; 6495 } 6496 6497 override MATCH constConv(Type to) 6498 { 6499 // Either another noreturn or conversion to any type 6500 return this.implicitConvTo(to); 6501 } 6502 6503 override bool isBoolean() 6504 { 6505 return true; // bottom type can be implicitly converted to any other type 6506 } 6507 6508 override uinteger_t size(const ref Loc loc) 6509 { 6510 return 0; 6511 } 6512 6513 override uint alignsize() 6514 { 6515 return 0; 6516 } 6517 6518 override void accept(Visitor v) 6519 { 6520 v.visit(this); 6521 } 6522 } 6523 6524 /*********************************************************** 6525 * Unlike D, C can declare/define struct/union/enum tag names 6526 * inside Declarators, instead of separately as in D. 6527 * The order these appear in the symbol table must be in lexical 6528 * order. There isn't enough info at the parsing stage to determine if 6529 * it's a declaration or a reference to an existing name, so this Type 6530 * collects the necessary info and defers it to semantic(). 6531 */ 6532 extern (C++) final class TypeTag : Type 6533 { 6534 Loc loc; /// location of declaration 6535 TOK tok; /// TOK.struct_, TOK.union_, TOK.enum_ 6536 structalign_t packalign; /// alignment of struct/union fields 6537 Identifier id; /// tag name identifier 6538 Type base; /// base type for enums otherwise null 6539 Dsymbols* members; /// members of struct, null if none 6540 6541 Type resolved; /// type after semantic() in case there are more others 6542 /// pointing to this instance, which can happen with 6543 /// struct S { int a; } s1, *s2; 6544 MOD mod; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment) 6545 6546 extern (D) this(const ref Loc loc, TOK tok, Identifier id, structalign_t packalign, Type base, Dsymbols* members) @safe 6547 { 6548 //printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this); 6549 super(Ttag); 6550 this.loc = loc; 6551 this.tok = tok; 6552 this.id = id; 6553 this.packalign = packalign; 6554 this.base = base; 6555 this.members = members; 6556 this.mod = 0; 6557 } 6558 6559 override const(char)* kind() const 6560 { 6561 return "tag"; 6562 } 6563 6564 override TypeTag syntaxCopy() 6565 { 6566 //printf("TypeTag syntaxCopy()\n"); 6567 // No semantic analysis done, no need to copy 6568 return this; 6569 } 6570 6571 override void accept(Visitor v) 6572 { 6573 v.visit(this); 6574 } 6575 } 6576 6577 /*********************************************************** 6578 * Represents a function's formal parameters + variadics info. 6579 * Length, indexing and iteration are based on a depth-first tuple expansion. 6580 * https://dlang.org/spec/function.html#ParameterList 6581 */ 6582 extern (C++) struct ParameterList 6583 { 6584 /// The raw (unexpanded) formal parameters, possibly containing tuples. 6585 Parameters* parameters; 6586 StorageClass stc; // storage class of ... 6587 VarArg varargs = VarArg.none; 6588 bool hasIdentifierList; // true if C identifier-list style 6589 6590 this(Parameters* parameters, VarArg varargs = VarArg.none, StorageClass stc = 0) @safe 6591 { 6592 this.parameters = parameters; 6593 this.varargs = varargs; 6594 this.stc = stc; 6595 } 6596 6597 /// Returns the number of expanded parameters. Complexity: O(N). 6598 size_t length() 6599 { 6600 return Parameter.dim(parameters); 6601 } 6602 6603 /// Returns the expanded parameter at the given index, or null if out of 6604 /// bounds. Complexity: O(i). 6605 Parameter opIndex(size_t i) 6606 { 6607 return Parameter.getNth(parameters, i); 6608 } 6609 6610 /// Iterates over the expanded parameters. Complexity: O(N). 6611 /// Prefer this to avoid the O(N + N^2/2) complexity of calculating length 6612 /// and calling N times opIndex. 6613 extern (D) int opApply(scope Parameter.ForeachDg dg) 6614 { 6615 return Parameter._foreach(parameters, dg); 6616 } 6617 6618 /// Iterates over the expanded parameters, matching them with the unexpanded 6619 /// ones, for semantic processing 6620 extern (D) int opApply(scope Parameter.SemanticForeachDg dg) 6621 { 6622 return Parameter._foreach(this.parameters, dg); 6623 } 6624 6625 extern (D) ParameterList syntaxCopy() 6626 { 6627 return ParameterList(Parameter.arraySyntaxCopy(parameters), varargs); 6628 } 6629 6630 /// Compares this to another ParameterList (and expands tuples if necessary) 6631 extern (D) bool opEquals(scope ref ParameterList other) const 6632 { 6633 if (stc != other.stc || varargs != other.varargs || (!parameters != !other.parameters)) 6634 return false; 6635 6636 if (this.parameters is other.parameters) 6637 return true; 6638 6639 size_t idx; 6640 bool diff; 6641 6642 // Pairwise compare each parameter 6643 // Can this avoid the O(n) indexing for the second list? 6644 foreach (_, p1; cast() this) 6645 { 6646 auto p2 = other[idx++]; 6647 if (!p2 || p1 != p2) { 6648 diff = true; 6649 break; 6650 } 6651 } 6652 6653 // Ensure no remaining parameters in `other` 6654 return !diff && other[idx] is null; 6655 } 6656 6657 /// Returns: `true` if any parameter has a default argument 6658 extern(D) bool hasDefaultArgs() 6659 { 6660 foreach (oidx, oparam, eidx, eparam; this) 6661 { 6662 if (eparam.defaultArg) 6663 return true; 6664 } 6665 return false; 6666 } 6667 6668 // Returns: `true` if any parameter doesn't have a default argument 6669 extern(D) bool hasArgsWithoutDefault() 6670 { 6671 foreach (oidx, oparam, eidx, eparam; this) 6672 { 6673 if (!eparam.defaultArg) 6674 return true; 6675 } 6676 return false; 6677 } 6678 } 6679 6680 6681 /*********************************************************** 6682 */ 6683 extern (C++) final class Parameter : ASTNode 6684 { 6685 import dmd.attrib : UserAttributeDeclaration; 6686 6687 Loc loc; 6688 StorageClass storageClass; 6689 Type type; 6690 Identifier ident; 6691 Expression defaultArg; 6692 UserAttributeDeclaration userAttribDecl; // user defined attributes 6693 6694 extern (D) this(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe 6695 { 6696 this.loc = loc; 6697 this.type = type; 6698 this.ident = ident; 6699 this.storageClass = storageClass; 6700 this.defaultArg = defaultArg; 6701 this.userAttribDecl = userAttribDecl; 6702 } 6703 6704 static Parameter create(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe 6705 { 6706 return new Parameter(loc, storageClass, type, ident, defaultArg, userAttribDecl); 6707 } 6708 6709 Parameter syntaxCopy() 6710 { 6711 return new Parameter(loc, storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? userAttribDecl.syntaxCopy(null) : null); 6712 } 6713 6714 /**************************************************** 6715 * Determine if parameter is a lazy array of delegates. 6716 * If so, return the return type of those delegates. 6717 * If not, return NULL. 6718 * 6719 * Returns T if the type is one of the following forms: 6720 * T delegate()[] 6721 * T delegate()[dim] 6722 */ 6723 Type isLazyArray() 6724 { 6725 Type tb = type.toBasetype(); 6726 if (tb.ty == Tsarray || tb.ty == Tarray) 6727 { 6728 Type tel = (cast(TypeArray)tb).next.toBasetype(); 6729 if (auto td = tel.isTypeDelegate()) 6730 { 6731 TypeFunction tf = td.next.toTypeFunction(); 6732 if (tf.parameterList.varargs == VarArg.none && tf.parameterList.length == 0) 6733 { 6734 return tf.next; // return type of delegate 6735 } 6736 } 6737 } 6738 return null; 6739 } 6740 6741 /// Returns: Whether the function parameter is lazy 6742 bool isLazy() const @safe pure nothrow @nogc 6743 { 6744 return (this.storageClass & (STC.lazy_)) != 0; 6745 } 6746 6747 /// Returns: Whether the function parameter is a reference (out / ref) 6748 bool isReference() const @safe pure nothrow @nogc 6749 { 6750 return (this.storageClass & (STC.ref_ | STC.out_)) != 0; 6751 } 6752 6753 // kludge for template.isType() 6754 override DYNCAST dyncast() const 6755 { 6756 return DYNCAST.parameter; 6757 } 6758 6759 override void accept(Visitor v) 6760 { 6761 v.visit(this); 6762 } 6763 6764 extern (D) static Parameters* arraySyntaxCopy(Parameters* parameters) 6765 { 6766 Parameters* params = null; 6767 if (parameters) 6768 { 6769 params = new Parameters(parameters.length); 6770 for (size_t i = 0; i < params.length; i++) 6771 (*params)[i] = (*parameters)[i].syntaxCopy(); 6772 } 6773 return params; 6774 } 6775 6776 /*************************************** 6777 * Determine number of arguments, folding in tuples. 6778 */ 6779 static size_t dim(Parameters* parameters) 6780 { 6781 size_t nargs = 0; 6782 6783 int dimDg(size_t n, Parameter p) 6784 { 6785 ++nargs; 6786 return 0; 6787 } 6788 6789 _foreach(parameters, &dimDg); 6790 return nargs; 6791 } 6792 6793 /** 6794 * Get nth `Parameter`, folding in tuples. 6795 * 6796 * Since `parameters` can include tuples, which would increase its 6797 * length, this function allows to get the `nth` parameter as if 6798 * all tuples transitively contained in `parameters` were flattened. 6799 * 6800 * Params: 6801 * parameters = Array of `Parameter` to iterate over 6802 * nth = Index of the desired parameter. 6803 * 6804 * Returns: 6805 * The parameter at index `nth` (taking tuples into account), 6806 * or `null` if out of bound. 6807 */ 6808 static Parameter getNth(Parameters* parameters, size_t nth) 6809 { 6810 Parameter param; 6811 6812 int getNthParamDg(size_t n, Parameter p) 6813 { 6814 if (n == nth) 6815 { 6816 param = p; 6817 return 1; 6818 } 6819 return 0; 6820 } 6821 6822 int res = _foreach(parameters, &getNthParamDg); 6823 return res ? param : null; 6824 } 6825 6826 /// Type of delegate when iterating solely on the parameters 6827 alias ForeachDg = extern (D) int delegate(size_t paramidx, Parameter param); 6828 /// Type of delegate when iterating on both the original set of parameters, 6829 /// and the type tuple. Useful for semantic analysis. 6830 /// 'o' stands for 'original' and 'e' stands for 'expanded'. 6831 alias SemanticForeachDg = extern (D) int delegate( 6832 size_t oidx, Parameter oparam, size_t eidx, Parameter eparam); 6833 6834 /*************************************** 6835 * Expands tuples in args in depth first order. Calls 6836 * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter. 6837 * If dg returns !=0, stops and returns that value else returns 0. 6838 * Use this function to avoid the O(N + N^2/2) complexity of 6839 * calculating dim and calling N times getNth. 6840 */ 6841 extern (D) static int _foreach(Parameters* parameters, scope ForeachDg dg) 6842 { 6843 assert(dg !is null); 6844 return _foreach(parameters, (_oidx, _oparam, idx, param) => dg(idx, param)); 6845 } 6846 6847 /// Ditto 6848 extern (D) static int _foreach( 6849 Parameters* parameters, scope SemanticForeachDg dg) 6850 { 6851 assert(dg !is null); 6852 if (parameters is null) 6853 return 0; 6854 6855 size_t eidx; 6856 foreach (oidx; 0 .. parameters.length) 6857 { 6858 Parameter oparam = (*parameters)[oidx]; 6859 if (auto r = _foreachImpl(dg, oidx, oparam, eidx, /* eparam */ oparam)) 6860 return r; 6861 } 6862 return 0; 6863 } 6864 6865 /// Implementation of the iteration process, which recurses in itself 6866 /// and just forwards `oidx` and `oparam`. 6867 extern (D) private static int _foreachImpl(scope SemanticForeachDg dg, 6868 size_t oidx, Parameter oparam, ref size_t eidx, Parameter eparam) 6869 { 6870 if (eparam is null) 6871 return 0; 6872 6873 Type t = eparam.type.toBasetype(); 6874 if (auto tu = t.isTypeTuple()) 6875 { 6876 // Check for empty tuples 6877 if (tu.arguments is null) 6878 return 0; 6879 6880 foreach (nidx; 0 .. tu.arguments.length) 6881 { 6882 Parameter nextep = (*tu.arguments)[nidx]; 6883 if (auto r = _foreachImpl(dg, oidx, oparam, eidx, nextep)) 6884 return r; 6885 } 6886 } 6887 else 6888 { 6889 if (auto r = dg(oidx, oparam, eidx, eparam)) 6890 return r; 6891 // The only place where we should increment eidx is here, 6892 // as a TypeTuple doesn't count as a parameter (for arity) 6893 // it it is empty. 6894 eidx++; 6895 } 6896 return 0; 6897 } 6898 6899 override const(char)* toChars() const 6900 { 6901 return ident ? ident.toChars() : "__anonymous_param"; 6902 } 6903 6904 /********************************* 6905 * Compute covariance of parameters `this` and `p` 6906 * as determined by the storage classes of both. 6907 * 6908 * Params: 6909 * returnByRef = true if the function returns by ref 6910 * p = Parameter to compare with 6911 * previewIn = Whether `-preview=in` is being used, and thus if 6912 * `in` means `scope [ref]`. 6913 * 6914 * Returns: 6915 * true = `this` can be used in place of `p` 6916 * false = nope 6917 */ 6918 bool isCovariant(bool returnByRef, const Parameter p, bool previewIn = global.params.previewIn) 6919 const pure nothrow @nogc @safe 6920 { 6921 ulong thisSTC = this.storageClass; 6922 ulong otherSTC = p.storageClass; 6923 6924 if (previewIn) 6925 { 6926 if (thisSTC & STC.in_) 6927 thisSTC |= STC.scope_; 6928 if (otherSTC & STC.in_) 6929 otherSTC |= STC.scope_; 6930 } 6931 6932 const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0); 6933 if ((thisSTC & mask) != (otherSTC & mask)) 6934 return false; 6935 return isCovariantScope(returnByRef, thisSTC, otherSTC); 6936 } 6937 6938 extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe 6939 { 6940 // Workaround for failing covariance when finding a common type of delegates, 6941 // some of which have parameters with inferred scope 6942 // https://issues.dlang.org/show_bug.cgi?id=21285 6943 // The root cause is that scopeinferred is not part of the mangle, and mangle 6944 // is used for type equality checks 6945 if (to & STC.returninferred) 6946 to &= ~STC.return_; 6947 // note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope 6948 if (to & STC.scopeinferred && !(to & STC.return_)) 6949 to &= ~STC.scope_; 6950 6951 if (from == to) 6952 return true; 6953 6954 /* result is true if the 'from' can be used as a 'to' 6955 */ 6956 6957 if ((from ^ to) & STC.ref_) // differing in 'ref' means no covariance 6958 return false; 6959 6960 /* workaround until we get STC.returnScope reliably set correctly 6961 */ 6962 if (returnByRef) 6963 { 6964 from &= ~STC.returnScope; 6965 to &= ~STC.returnScope; 6966 } 6967 else 6968 { 6969 from |= STC.returnScope; 6970 to |= STC.returnScope; 6971 } 6972 return covariant[buildScopeRef(from)][buildScopeRef(to)]; 6973 } 6974 6975 extern (D) private static bool[ScopeRef.max + 1][ScopeRef.max + 1] covariantInit() pure nothrow @nogc @safe 6976 { 6977 /* Initialize covariant[][] with this: 6978 6979 From\To n rs s 6980 None X 6981 ReturnScope X X 6982 Scope X X X 6983 6984 From\To r rr rs rr-s r-rs 6985 Ref X X 6986 ReturnRef X 6987 RefScope X X X X X 6988 ReturnRef-Scope X X 6989 Ref-ReturnScope X X X 6990 */ 6991 bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant; 6992 6993 foreach (i; 0 .. ScopeRef.max + 1) 6994 { 6995 covariant[i][i] = true; 6996 covariant[ScopeRef.RefScope][i] = true; 6997 } 6998 covariant[ScopeRef.ReturnScope][ScopeRef.None] = true; 6999 covariant[ScopeRef.Scope ][ScopeRef.None] = true; 7000 covariant[ScopeRef.Scope ][ScopeRef.ReturnScope] = true; 7001 7002 covariant[ScopeRef.Ref ][ScopeRef.ReturnRef] = true; 7003 covariant[ScopeRef.ReturnRef_Scope][ScopeRef.ReturnRef] = true; 7004 covariant[ScopeRef.Ref_ReturnScope][ScopeRef.Ref ] = true; 7005 covariant[ScopeRef.Ref_ReturnScope][ScopeRef.ReturnRef] = true; 7006 7007 return covariant; 7008 } 7009 7010 extern (D) private static immutable bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant = covariantInit(); 7011 7012 extern (D) bool opEquals(const Parameter other) const 7013 { 7014 return this.storageClass == other.storageClass 7015 && this.type == other.type; 7016 } 7017 } 7018 7019 /************************************************************* 7020 * For printing two types with qualification when necessary. 7021 * Params: 7022 * t1 = The first type to receive the type name for 7023 * t2 = The second type to receive the type name for 7024 * Returns: 7025 * The fully-qualified names of both types if the two type names are not the same, 7026 * or the unqualified names of both types if the two type names are the same. 7027 */ 7028 const(char*)[2] toAutoQualChars(Type t1, Type t2) 7029 { 7030 auto s1 = t1.toChars(); 7031 auto s2 = t2.toChars(); 7032 // show qualification only if it's different 7033 if (!t1.equals(t2) && strcmp(s1, s2) == 0) 7034 { 7035 s1 = t1.toPrettyChars(true); 7036 s2 = t2.toPrettyChars(true); 7037 } 7038 return [s1, s2]; 7039 } 7040 7041 7042 /** 7043 * For each active modifier (MODFlags.const_, MODFlags.immutable_, etc) call `fp` with a 7044 * void* for the work param and a string representation of the attribute. 7045 */ 7046 void modifiersApply(const TypeFunction tf, void delegate(string) dg) 7047 { 7048 immutable ubyte[4] modsArr = [MODFlags.const_, MODFlags.immutable_, MODFlags.wild, MODFlags.shared_]; 7049 7050 foreach (modsarr; modsArr) 7051 { 7052 if (tf.mod & modsarr) 7053 { 7054 dg(MODtoString(modsarr)); 7055 } 7056 } 7057 } 7058 7059 /** 7060 * For each active attribute (ref/const/nogc/etc) call `fp` with a void* for the 7061 * work param and a string representation of the attribute. 7062 */ 7063 void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTformat trustFormat = TRUSTformatDefault) 7064 { 7065 if (tf.purity) 7066 dg("pure"); 7067 if (tf.isnothrow) 7068 dg("nothrow"); 7069 if (tf.isnogc) 7070 dg("@nogc"); 7071 if (tf.isproperty) 7072 dg("@property"); 7073 if (tf.isref) 7074 dg("ref"); 7075 if (tf.isreturn && !tf.isreturninferred) 7076 dg("return"); 7077 if (tf.isScopeQual && !tf.isscopeinferred) 7078 dg("scope"); 7079 if (tf.islive) 7080 dg("@live"); 7081 7082 TRUST trustAttrib = tf.trust; 7083 7084 if (trustAttrib == TRUST.default_) 7085 { 7086 if (trustFormat != TRUSTformatSystem) 7087 return; 7088 trustAttrib = TRUST.system; // avoid calling with an empty string 7089 } 7090 7091 dg(trustToString(trustAttrib)); 7092 } 7093 7094 /** 7095 * If the type is a class or struct, returns the symbol for it, 7096 * else null. 7097 */ 7098 extern (C++) AggregateDeclaration isAggregate(Type t) 7099 { 7100 t = t.toBasetype(); 7101 if (t.ty == Tclass) 7102 return (cast(TypeClass)t).sym; 7103 if (t.ty == Tstruct) 7104 return (cast(TypeStruct)t).sym; 7105 return null; 7106 } 7107 7108 /*************************************************** 7109 * Determine if type t can be indexed or sliced given that it is not an 7110 * aggregate with operator overloads. 7111 * Params: 7112 * t = type to check 7113 * Returns: 7114 * true if an expression of type t can be e1 in an array expression 7115 */ 7116 bool isIndexableNonAggregate(Type t) 7117 { 7118 t = t.toBasetype(); 7119 return (t.ty == Tpointer || t.ty == Tsarray || t.ty == Tarray || t.ty == Taarray || 7120 t.ty == Ttuple || t.ty == Tvector); 7121 } 7122 7123 /*************************************************** 7124 * Determine if type t is copyable. 7125 * Params: 7126 * t = type to check 7127 * Returns: 7128 * true if we can copy it 7129 */ 7130 bool isCopyable(Type t) 7131 { 7132 //printf("isCopyable() %s\n", t.toChars()); 7133 if (auto ts = t.isTypeStruct()) 7134 { 7135 if (ts.sym.postblit && 7136 ts.sym.postblit.storage_class & STC.disable) 7137 return false; 7138 if (ts.sym.hasCopyCtor) 7139 { 7140 // check if there is a matching overload of the copy constructor and whether it is disabled or not 7141 // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 7142 Dsymbol ctor = search_function(ts.sym, Id.ctor); 7143 assert(ctor); 7144 scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue 7145 el.type = cast() ts; 7146 Expressions* args = new Expressions(); 7147 args.push(el); 7148 FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); 7149 if (!f || f.storage_class & STC.disable) 7150 return false; 7151 } 7152 } 7153 return true; 7154 } 7155 7156 /*************************************** 7157 * Computes how a parameter may be returned. 7158 * Shrinking the representation is necessary because StorageClass is so wide 7159 * Params: 7160 * stc = storage class of parameter 7161 * Returns: 7162 * value from enum ScopeRef 7163 */ 7164 ScopeRef buildScopeRef(StorageClass stc) pure nothrow @nogc @safe 7165 { 7166 if (stc & STC.out_) 7167 stc |= STC.ref_; // treat `out` and `ref` the same 7168 7169 ScopeRef result; 7170 final switch (stc & (STC.ref_ | STC.scope_ | STC.return_)) 7171 { 7172 case 0: result = ScopeRef.None; break; 7173 7174 /* can occur in case test/compilable/testsctreturn.d 7175 * related to https://issues.dlang.org/show_bug.cgi?id=20149 7176 * where inout adds `return` without `scope` or `ref` 7177 */ 7178 case STC.return_: result = ScopeRef.Return; break; 7179 7180 case STC.ref_: result = ScopeRef.Ref; break; 7181 case STC.scope_: result = ScopeRef.Scope; break; 7182 case STC.return_ | STC.ref_: result = ScopeRef.ReturnRef; break; 7183 case STC.return_ | STC.scope_: result = ScopeRef.ReturnScope; break; 7184 case STC.ref_ | STC.scope_: result = ScopeRef.RefScope; break; 7185 7186 case STC.return_ | STC.ref_ | STC.scope_: 7187 result = stc & STC.returnScope ? ScopeRef.Ref_ReturnScope 7188 : ScopeRef.ReturnRef_Scope; 7189 break; 7190 } 7191 return result; 7192 } 7193 7194 /** 7195 * Classification of 'scope-return-ref' possibilities 7196 */ 7197 enum ScopeRef 7198 { 7199 None, 7200 Scope, 7201 ReturnScope, 7202 Ref, 7203 ReturnRef, 7204 RefScope, 7205 ReturnRef_Scope, 7206 Ref_ReturnScope, 7207 Return, 7208 } 7209 7210 /********************************* 7211 * Give us a nice string for debugging purposes. 7212 * Params: 7213 * sr = value 7214 * Returns: 7215 * corresponding string 7216 */ 7217 const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe 7218 { 7219 with (ScopeRef) 7220 { 7221 static immutable char*[ScopeRef.max + 1] names = 7222 [ 7223 None: "None", 7224 Scope: "Scope", 7225 ReturnScope: "ReturnScope", 7226 Ref: "Ref", 7227 ReturnRef: "ReturnRef", 7228 RefScope: "RefScope", 7229 ReturnRef_Scope: "ReturnRef_Scope", 7230 Ref_ReturnScope: "Ref_ReturnScope", 7231 Return: "Return", 7232 ]; 7233 return names[sr]; 7234 } 7235 } 7236 7237 /** 7238 * Used by `callMatch` to check if the copy constructor may be called to 7239 * copy the argument 7240 * 7241 * This is done by seeing if a call to the copy constructor can be made: 7242 * ``` 7243 * typeof(tprm) __copytmp; 7244 * copytmp.__copyCtor(arg); 7245 * ``` 7246 */ 7247 private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, 7248 Expression arg, Type tprm, Scope* sc, const(char)** pMessage) 7249 { 7250 auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); 7251 tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; 7252 tmp.dsymbolSemantic(sc); 7253 Expression ve = new VarExp(arg.loc, tmp); 7254 Expression e = new DotIdExp(arg.loc, ve, Id.ctor); 7255 e = new CallExp(arg.loc, e, arg); 7256 //printf("e = %s\n", e.toChars()); 7257 if (.trySemantic(e, sc)) 7258 return true; 7259 7260 if (pMessage) 7261 { 7262 /* https://issues.dlang.org/show_bug.cgi?id=22202 7263 * 7264 * If a function was deduced by semantic on the CallExp, 7265 * it means that resolveFuncCall completed succesfully. 7266 * Therefore, there exists a callable copy constructor, 7267 * however, it cannot be called because scope constraints 7268 * such as purity, safety or nogc. 7269 */ 7270 OutBuffer buf; 7271 auto callExp = e.isCallExp(); 7272 if (auto f = callExp.f) 7273 { 7274 char[] s; 7275 if (!f.isPure && sc.func.setImpure()) 7276 s ~= "pure "; 7277 if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) 7278 s ~= "@safe "; 7279 if (!f.isNogc && sc.func.setGC(arg.loc, null)) 7280 s ~= "nogc "; 7281 if (s) 7282 { 7283 s[$-1] = '\0'; 7284 buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); 7285 } 7286 else if (f.isGenerated() && f.isDisabled()) 7287 { 7288 /* https://issues.dlang.org/show_bug.cgi?id=23097 7289 * Compiler generated copy constructor failed. 7290 */ 7291 buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", 7292 argStruct.toChars()); 7293 } 7294 else 7295 { 7296 /* Although a copy constructor may exist, no suitable match was found. 7297 * i.e: `inout` constructor creates `const` object, not mutable. 7298 * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. 7299 */ 7300 goto Lnocpctor; 7301 } 7302 } 7303 else 7304 { 7305 Lnocpctor: 7306 buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", 7307 argStruct.toChars(), arg.type.toChars(), tprm.toChars()); 7308 } 7309 7310 *pMessage = buf.extractChars(); 7311 } 7312 return false; 7313 } 7314 7315 /** 7316 * Match a single parameter to an argument. 7317 * 7318 * This function is called by `TypeFunction.callMatch` while iterating over 7319 * the list of parameter. Here we check if `arg` is a match for `p`, 7320 * which is mostly about checking if `arg.type` converts to `p`'s type 7321 * and some check about value reference. 7322 * 7323 * Params: 7324 * tf = The `TypeFunction`, only used for error reporting 7325 * p = The parameter of `tf` being matched 7326 * arg = Argument being passed (bound) to `p` 7327 * wildmatch = Wild (`inout`) matching level, derived from the full argument list 7328 * flag = A non-zero value means we're doing a partial ordering check 7329 * (no value semantic check) 7330 * sc = Scope we are in 7331 * pMessage = A buffer to write the error in, or `null` 7332 * 7333 * Returns: Whether `trailingArgs` match `p`. 7334 */ 7335 private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, 7336 Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) 7337 { 7338 //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); 7339 MATCH m; 7340 Type targ = arg.type; 7341 Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; 7342 7343 if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) 7344 m = MATCH.convert; 7345 else if (flag) 7346 { 7347 // for partial ordering, value is an irrelevant mockup, just look at the type 7348 m = targ.implicitConvTo(tprm); 7349 } 7350 else 7351 { 7352 const isRef = p.isReference(); 7353 StructDeclaration argStruct, prmStruct; 7354 7355 // first look for a copy constructor 7356 if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) 7357 { 7358 // if the argument and the parameter are of the same unqualified struct type 7359 argStruct = (cast(TypeStruct)targ).sym; 7360 prmStruct = (cast(TypeStruct)tprm).sym; 7361 } 7362 7363 // check if the copy constructor may be called to copy the argument 7364 if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) 7365 { 7366 if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) 7367 return MATCH.nomatch; 7368 m = MATCH.exact; 7369 } 7370 else 7371 { 7372 import dmd.dcast : cimplicitConvTo; 7373 m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); 7374 } 7375 } 7376 7377 // Non-lvalues do not match ref or out parameters 7378 if (p.isReference()) 7379 { 7380 // https://issues.dlang.org/show_bug.cgi?id=13783 7381 // Don't use toBasetype() to handle enum types. 7382 Type ta = targ; 7383 Type tp = tprm; 7384 //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); 7385 7386 if (m && !arg.isLvalue()) 7387 { 7388 if (p.storageClass & STC.out_) 7389 { 7390 if (pMessage) *pMessage = tf.getParamError(arg, p); 7391 return MATCH.nomatch; 7392 } 7393 7394 if (arg.op == EXP.string_ && tp.ty == Tsarray) 7395 { 7396 if (ta.ty != Tsarray) 7397 { 7398 Type tn = tp.nextOf().castMod(ta.nextOf().mod); 7399 dinteger_t dim = (cast(StringExp)arg).len; 7400 ta = tn.sarrayOf(dim); 7401 } 7402 } 7403 else if (arg.op == EXP.slice && tp.ty == Tsarray) 7404 { 7405 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] 7406 if (ta.ty != Tsarray) 7407 { 7408 Type tn = ta.nextOf(); 7409 dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); 7410 ta = tn.sarrayOf(dim); 7411 } 7412 } 7413 else if ((p.storageClass & STC.in_) && global.params.previewIn) 7414 { 7415 // Allow converting a literal to an `in` which is `ref` 7416 if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) 7417 { 7418 Type tn = tp.nextOf(); 7419 dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); 7420 ta = tn.sarrayOf(dim); 7421 } 7422 7423 // Need to make this a rvalue through a temporary 7424 m = MATCH.convert; 7425 } 7426 else if (global.params.rvalueRefParam != FeatureState.enabled || 7427 p.storageClass & STC.out_ || 7428 !arg.type.isCopyable()) // can't copy to temp for ref parameter 7429 { 7430 if (pMessage) *pMessage = tf.getParamError(arg, p); 7431 return MATCH.nomatch; 7432 } 7433 else 7434 { 7435 /* in functionParameters() we'll convert this 7436 * rvalue into a temporary 7437 */ 7438 m = MATCH.convert; 7439 } 7440 } 7441 7442 /* If the match is not already perfect or if the arg 7443 is not a lvalue then try the `alias this` chain 7444 see https://issues.dlang.org/show_bug.cgi?id=15674 7445 and https://issues.dlang.org/show_bug.cgi?id=21905 7446 */ 7447 if (ta != tp || !arg.isLvalue()) 7448 { 7449 Type firsttab = ta.toBasetype(); 7450 while (1) 7451 { 7452 Type tab = ta.toBasetype(); 7453 Type tat = tab.aliasthisOf(); 7454 if (!tat || !tat.implicitConvTo(tprm)) 7455 break; 7456 if (tat == tab || tat == firsttab) 7457 break; 7458 ta = tat; 7459 } 7460 } 7461 7462 /* A ref variable should work like a head-const reference. 7463 * e.g. disallows: 7464 * ref T <- an lvalue of const(T) argument 7465 * ref T[dim] <- an lvalue of const(T[dim]) argument 7466 */ 7467 if (!ta.constConv(tp)) 7468 { 7469 if (pMessage) *pMessage = tf.getParamError(arg, p); 7470 return MATCH.nomatch; 7471 } 7472 } 7473 return m; 7474 } 7475 7476 /** 7477 * Match the remaining arguments `trailingArgs` with parameter `p`. 7478 * 7479 * Assume we already checked that `p` is the last parameter of `tf`, 7480 * and we want to know whether the arguments would match `p`. 7481 * 7482 * Params: 7483 * tf = The `TypeFunction`, only used for error reporting 7484 * p = The last parameter of `tf` which is variadic 7485 * trailingArgs = The remaining arguments that should match `p` 7486 * pMessage = A buffer to write the error in, or `null` 7487 * 7488 * Returns: Whether `trailingArgs` match `p`. 7489 */ 7490 private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, 7491 Expression[] trailingArgs, const(char)** pMessage) 7492 { 7493 Type tb = p.type.toBasetype(); 7494 7495 switch (tb.ty) 7496 { 7497 case Tsarray: 7498 TypeSArray tsa = cast(TypeSArray)tb; 7499 dinteger_t sz = tsa.dim.toInteger(); 7500 if (sz != trailingArgs.length) 7501 { 7502 if (pMessage) 7503 *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", 7504 sz, trailingArgs.length); 7505 return MATCH.nomatch; 7506 } 7507 goto case Tarray; 7508 case Tarray: 7509 { 7510 MATCH match = MATCH.exact; 7511 TypeArray ta = cast(TypeArray)tb; 7512 foreach (arg; trailingArgs) 7513 { 7514 MATCH m; 7515 assert(arg); 7516 7517 /* If lazy array of delegates, 7518 * convert arg(s) to delegate(s) 7519 */ 7520 Type tret = p.isLazyArray(); 7521 if (tret) 7522 { 7523 if (ta.next.equals(arg.type)) 7524 m = MATCH.exact; 7525 else if (tret.toBasetype().ty == Tvoid) 7526 m = MATCH.convert; 7527 else 7528 { 7529 m = arg.implicitConvTo(tret); 7530 if (m == MATCH.nomatch) 7531 m = arg.implicitConvTo(ta.next); 7532 } 7533 } 7534 else 7535 m = arg.implicitConvTo(ta.next); 7536 7537 if (m == MATCH.nomatch) 7538 { 7539 if (pMessage) *pMessage = tf.getParamError(arg, p); 7540 return MATCH.nomatch; 7541 } 7542 if (m < match) 7543 match = m; 7544 } 7545 return match; 7546 } 7547 case Tclass: 7548 // We leave it up to the actual constructor call to do the matching. 7549 return MATCH.exact; 7550 7551 default: 7552 // We can have things as `foo(int[int] wat...)` but they only match 7553 // with an associative array proper. 7554 if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); 7555 return MATCH.nomatch; 7556 } 7557 } 7558 7559 /** 7560 * Creates an appropriate vector type for `tv` that will hold one boolean 7561 * result for each element of the vector type. The result of vector comparisons 7562 * is a single or doubleword mask of all 1s (comparison true) or all 0s 7563 * (comparison false). This SIMD mask type does not have an equivalent D type, 7564 * however its closest equivalent would be an integer vector of the same unit 7565 * size and length. 7566 * 7567 * Params: 7568 * tv = The `TypeVector` to build a vector from. 7569 * Returns: 7570 * A vector type suitable for the result of a vector comparison operation. 7571 */ 7572 TypeVector toBooleanVector(TypeVector tv) 7573 { 7574 Type telem = tv.elementType(); 7575 switch (telem.ty) 7576 { 7577 case Tvoid: 7578 case Tint8: 7579 case Tuns8: 7580 case Tint16: 7581 case Tuns16: 7582 case Tint32: 7583 case Tuns32: 7584 case Tint64: 7585 case Tuns64: 7586 // No need to build an equivalent mask type. 7587 return tv; 7588 7589 case Tfloat32: 7590 telem = Type.tuns32; 7591 break; 7592 7593 case Tfloat64: 7594 telem = Type.tuns64; 7595 break; 7596 7597 default: 7598 assert(0); 7599 } 7600 7601 TypeSArray tsa = tv.basetype.isTypeSArray(); 7602 assert(tsa !is null); 7603 7604 return new TypeVector(new TypeSArray(telem, tsa.dim)); 7605 } 7606 7607 /************************************************* 7608 * Dispatch to function based on static type of Type. 7609 */ 7610 mixin template VisitType(Result) 7611 { 7612 Result VisitType(Type t) 7613 { 7614 final switch (t.ty) 7615 { 7616 case TY.Tvoid: 7617 case TY.Tint8: 7618 case TY.Tuns8: 7619 case TY.Tint16: 7620 case TY.Tuns16: 7621 case TY.Tint32: 7622 case TY.Tuns32: 7623 case TY.Tint64: 7624 case TY.Tuns64: 7625 case TY.Tfloat32: 7626 case TY.Tfloat64: 7627 case TY.Tfloat80: 7628 case TY.Timaginary32: 7629 case TY.Timaginary64: 7630 case TY.Timaginary80: 7631 case TY.Tcomplex32: 7632 case TY.Tcomplex64: 7633 case TY.Tcomplex80: 7634 case TY.Tbool: 7635 case TY.Tchar: 7636 case TY.Twchar: 7637 case TY.Tdchar: 7638 case TY.Tint128: 7639 case TY.Tuns128: mixin(visitTYCase("Basic")); 7640 case TY.Tarray: mixin(visitTYCase("DArray")); 7641 case TY.Tsarray: mixin(visitTYCase("SArray")); 7642 case TY.Taarray: mixin(visitTYCase("AArray")); 7643 case TY.Tpointer: mixin(visitTYCase("Pointer")); 7644 case TY.Treference: mixin(visitTYCase("Reference")); 7645 case TY.Tfunction: mixin(visitTYCase("Function")); 7646 case TY.Tident: mixin(visitTYCase("Identifier")); 7647 case TY.Tclass: mixin(visitTYCase("Class")); 7648 case TY.Tstruct: mixin(visitTYCase("Struct")); 7649 case TY.Tenum: mixin(visitTYCase("Enum")); 7650 case TY.Tdelegate: mixin(visitTYCase("Delegate")); 7651 case TY.Terror: mixin(visitTYCase("Error")); 7652 case TY.Tinstance: mixin(visitTYCase("Instance")); 7653 case TY.Ttypeof: mixin(visitTYCase("Typeof")); 7654 case TY.Ttuple: mixin(visitTYCase("Tuple")); 7655 case TY.Tslice: mixin(visitTYCase("Slice")); 7656 case TY.Treturn: mixin(visitTYCase("Return")); 7657 case TY.Tnull: mixin(visitTYCase("Null")); 7658 case TY.Tvector: mixin(visitTYCase("Vector")); 7659 case TY.Ttraits: mixin(visitTYCase("Traits")); 7660 case TY.Tmixin: mixin(visitTYCase("Mixin")); 7661 case TY.Tnoreturn: mixin(visitTYCase("Noreturn")); 7662 case TY.Ttag: mixin(visitTYCase("Tag")); 7663 case TY.Tnone: assert(0); 7664 } 7665 } 7666 } 7667 7668 /**************************************** 7669 * CTFE-only helper function for VisitInitializer. 7670 * Params: 7671 * handler = string for the name of the visit handler 7672 * Returns: boilerplate code for a case 7673 */ 7674 pure string visitTYCase(string handler) @safe 7675 { 7676 if (__ctfe) 7677 { 7678 return 7679 " 7680 enum isVoid = is(Result == void); 7681 auto tx = t.isType"~handler~"(); 7682 static if (__traits(compiles, visit"~handler~"(tx))) 7683 { 7684 static if (isVoid) 7685 { 7686 visit"~handler~"(tx); 7687 return; 7688 } 7689 else 7690 { 7691 if (Result r = visit"~handler~"(tx)) 7692 return r; 7693 return Result.init; 7694 } 7695 } 7696 else static if (__traits(compiles, visitDefaultCase(t))) 7697 { 7698 static if (isVoid) 7699 { 7700 visitDefaultCase(tx); 7701 return; 7702 } 7703 else 7704 { 7705 if (Result r = visitDefaultCase(t)) 7706 return r; 7707 return Result.init; 7708 } 7709 } 7710 else 7711 static assert(0, "~handler~"); 7712 "; 7713 } 7714 assert(0); 7715 } 7716 7717 7718 /** 7719 * Returns: 7720 * `TypeIdentifier` corresponding to `object.Throwable` 7721 */ 7722 TypeIdentifier getThrowable() 7723 { 7724 auto tid = new TypeIdentifier(Loc.initial, Id.empty); 7725 tid.addIdent(Id.object); 7726 tid.addIdent(Id.Throwable); 7727 return tid; 7728 } 7729 7730 /** 7731 * Returns: 7732 * TypeIdentifier corresponding to `object.Exception` 7733 */ 7734 TypeIdentifier getException() 7735 { 7736 auto tid = new TypeIdentifier(Loc.initial, Id.empty); 7737 tid.addIdent(Id.object); 7738 tid.addIdent(Id.Exception); 7739 return tid; 7740 }