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