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