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