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