d: Merge upstream dmd, druntime f1a045928e
[official-gcc.git] / gcc / d / dmd / mtype.d
blob626bf7431f008eeb54e1ba1eef65057c75aa8c26
1 /**
2 * Defines a D type.
4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d)
8 * Documentation: https://dlang.org/phobos/dmd_mtype.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mtype.d
12 module dmd.mtype;
14 import core.checkedint;
15 import core.stdc.stdarg;
16 import core.stdc.stdio;
17 import core.stdc.stdlib;
18 import core.stdc.string;
20 import dmd.aggregate;
21 import dmd.arraytypes;
22 import dmd.astenums;
23 import dmd.ast_node;
24 import dmd.gluelayer;
25 import dmd.dclass;
26 import dmd.dcast;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dmangle;
30 import dmd.dscope;
31 import dmd.dstruct;
32 import dmd.dsymbol;
33 import dmd.dsymbolsem;
34 import dmd.dtemplate;
35 import dmd.errors;
36 import dmd.expression;
37 import dmd.func;
38 import dmd.globals;
39 import dmd.hdrgen;
40 import dmd.id;
41 import dmd.identifier;
42 import dmd.init;
43 import dmd.location;
44 import dmd.opover;
45 import dmd.root.ctfloat;
46 import dmd.common.outbuffer;
47 import dmd.root.rmem;
48 import dmd.rootobject;
49 import dmd.root.stringtable;
50 import dmd.target;
51 import dmd.tokens;
52 import dmd.typesem;
53 import dmd.visitor;
55 enum LOGDOTEXP = 0; // log ::dotExp()
56 enum LOGDEFAULTINIT = 0; // log ::defaultInit()
58 enum SIZE_INVALID = (~cast(uinteger_t)0); // error return from size() functions
61 /***************************
62 * Return !=0 if modfrom can be implicitly converted to modto
64 bool MODimplicitConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
66 if (modfrom == modto)
67 return true;
69 //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
70 auto X(T, U)(T m, U n)
72 return ((m << 4) | n);
75 switch (X(modfrom & ~MODFlags.shared_, modto & ~MODFlags.shared_))
77 case X(0, MODFlags.const_):
78 case X(MODFlags.wild, MODFlags.const_):
79 case X(MODFlags.wild, MODFlags.wildconst):
80 case X(MODFlags.wildconst, MODFlags.const_):
81 return (modfrom & MODFlags.shared_) == (modto & MODFlags.shared_);
83 case X(MODFlags.immutable_, MODFlags.const_):
84 case X(MODFlags.immutable_, MODFlags.wildconst):
85 return true;
86 default:
87 return false;
91 /***************************
92 * Return MATCH.exact or MATCH.constant if a method of type '() modfrom' can call a method of type '() modto'.
94 MATCH MODmethodConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
96 if (modfrom == modto)
97 return MATCH.exact;
98 if (MODimplicitConv(modfrom, modto))
99 return MATCH.constant;
101 auto X(T, U)(T m, U n)
103 return ((m << 4) | n);
106 switch (X(modfrom, modto))
108 case X(0, MODFlags.wild):
109 case X(MODFlags.immutable_, MODFlags.wild):
110 case X(MODFlags.const_, MODFlags.wild):
111 case X(MODFlags.wildconst, MODFlags.wild):
112 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild):
113 case X(MODFlags.shared_ | MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild):
114 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
115 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
116 return MATCH.constant;
118 default:
119 return MATCH.nomatch;
123 /***************************
124 * Merge mod bits to form common mod.
126 MOD MODmerge(MOD mod1, MOD mod2) pure nothrow @nogc @safe
128 if (mod1 == mod2)
129 return mod1;
131 //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2);
132 MOD result = 0;
133 if ((mod1 | mod2) & MODFlags.shared_)
135 // If either type is shared, the result will be shared
136 result |= MODFlags.shared_;
137 mod1 &= ~MODFlags.shared_;
138 mod2 &= ~MODFlags.shared_;
140 if (mod1 == 0 || mod1 == MODFlags.mutable || mod1 == MODFlags.const_ || mod2 == 0 || mod2 == MODFlags.mutable || mod2 == MODFlags.const_)
142 // If either type is mutable or const, the result will be const.
143 result |= MODFlags.const_;
145 else
147 // MODFlags.immutable_ vs MODFlags.wild
148 // MODFlags.immutable_ vs MODFlags.wildconst
149 // MODFlags.wild vs MODFlags.wildconst
150 assert(mod1 & MODFlags.wild || mod2 & MODFlags.wild);
151 result |= MODFlags.wildconst;
153 return result;
156 /*********************************
157 * Store modifier name into buf.
159 void MODtoBuffer(ref OutBuffer buf, MOD mod) nothrow @safe
161 buf.writestring(MODtoString(mod));
164 /*********************************
165 * Returns:
166 * a human readable representation of `mod`,
167 * which is the token `mod` corresponds to
169 const(char)* MODtoChars(MOD mod) nothrow pure
171 /// Works because we return a literal
172 return MODtoString(mod).ptr;
175 /// Ditto
176 string MODtoString(MOD mod) nothrow pure @safe
178 final switch (mod)
180 case 0:
181 return "";
183 case MODFlags.immutable_:
184 return "immutable";
186 case MODFlags.shared_:
187 return "shared";
189 case MODFlags.shared_ | MODFlags.const_:
190 return "shared const";
192 case MODFlags.const_:
193 return "const";
195 case MODFlags.shared_ | MODFlags.wild:
196 return "shared inout";
198 case MODFlags.wild:
199 return "inout";
201 case MODFlags.shared_ | MODFlags.wildconst:
202 return "shared inout const";
204 case MODFlags.wildconst:
205 return "inout const";
209 /*************************************************
210 * Pick off one of the trust flags from trust,
211 * and return a string representation of it.
213 string trustToString(TRUST trust) pure nothrow @nogc @safe
215 final switch (trust)
217 case TRUST.default_:
218 return null;
219 case TRUST.system:
220 return "@system";
221 case TRUST.trusted:
222 return "@trusted";
223 case TRUST.safe:
224 return "@safe";
228 unittest
230 assert(trustToString(TRUST.default_) == "");
231 assert(trustToString(TRUST.system) == "@system");
232 assert(trustToString(TRUST.trusted) == "@trusted");
233 assert(trustToString(TRUST.safe) == "@safe");
236 /************************************
237 * Convert MODxxxx to STCxxx
239 StorageClass ModToStc(uint mod) pure nothrow @nogc @safe
241 StorageClass stc = 0;
242 if (mod & MODFlags.immutable_)
243 stc |= STC.immutable_;
244 if (mod & MODFlags.const_)
245 stc |= STC.const_;
246 if (mod & MODFlags.wild)
247 stc |= STC.wild;
248 if (mod & MODFlags.shared_)
249 stc |= STC.shared_;
250 return stc;
253 ///Returns true if ty is char, wchar, or dchar
254 bool isSomeChar(TY ty) pure nothrow @nogc @safe
256 return ty == Tchar || ty == Twchar || ty == Tdchar;
259 /************************************
260 * Determine mutability of indirections in (ref) t.
262 * Returns: When the type has any mutable indirections, returns 0.
263 * When all indirections are immutable, returns 2.
264 * Otherwise, when the type has const/inout indirections, returns 1.
266 * Params:
267 * isref = if true, check `ref t`; otherwise, check just `t`
268 * t = the type that is being checked
270 int mutabilityOfType(bool isref, Type t)
272 if (isref)
274 if (t.mod & MODFlags.immutable_)
275 return 2;
276 if (t.mod & (MODFlags.const_ | MODFlags.wild))
277 return 1;
278 return 0;
281 t = t.baseElemOf();
283 if (!t.hasPointers() || t.mod & MODFlags.immutable_)
284 return 2;
286 /* Accept immutable(T)[] and immutable(T)* as being strongly pure
288 if (t.ty == Tarray || t.ty == Tpointer)
290 Type tn = t.nextOf().toBasetype();
291 if (tn.mod & MODFlags.immutable_)
292 return 2;
293 if (tn.mod & (MODFlags.const_ | MODFlags.wild))
294 return 1;
297 /* The rest of this is too strict; fix later.
298 * For example, the only pointer members of a struct may be immutable,
299 * which would maintain strong purity.
300 * (Just like for dynamic arrays and pointers above.)
302 if (t.mod & (MODFlags.const_ | MODFlags.wild))
303 return 1;
305 /* Should catch delegates and function pointers, and fold in their purity
307 return 0;
310 /****************
311 * dotExp() bit flags
313 enum DotExpFlag
315 none = 0,
316 gag = 1, // don't report "not a property" error and just return null
317 noDeref = 2, // the use of the expression will not attempt a dereference
318 noAliasThis = 4, // don't do 'alias this' resolution
321 /// Result of a check whether two types are covariant
322 enum Covariant
324 distinct = 0, /// types are distinct
325 yes = 1, /// types are covariant
326 no = 2, /// arguments match as far as overloading goes, but types are not covariant
327 fwdref = 3, /// cannot determine covariance because of forward references
330 /***********************************************************
332 extern (C++) abstract class Type : ASTNode
334 TY ty;
335 MOD mod; // modifiers MODxxxx
336 char* deco;
338 static struct Mcache
340 /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc.
341 * They should not be referenced by anybody but mtype.d.
342 * They can be null if not lazily evaluated yet.
343 * Note that there is no "shared immutable", because that is just immutable
344 * The point of this is to reduce the size of each Type instance as
345 * we bank on the idea that usually only one of variants exist.
346 * It will also speed up code because these are rarely referenced and
347 * so need not be in the cache.
349 Type cto; // MODFlags.const_
350 Type ito; // MODFlags.immutable_
351 Type sto; // MODFlags.shared_
352 Type scto; // MODFlags.shared_ | MODFlags.const_
353 Type wto; // MODFlags.wild
354 Type wcto; // MODFlags.wildconst
355 Type swto; // MODFlags.shared_ | MODFlags.wild
356 Type swcto; // MODFlags.shared_ | MODFlags.wildconst
358 private Mcache* mcache;
360 Type pto; // merged pointer to this type
361 Type rto; // reference to this type
362 Type arrayof; // array of this type
364 TypeInfoDeclaration vtinfo; // TypeInfo object for this Type
366 type* ctype; // for back end
368 extern (C++) __gshared Type tvoid;
369 extern (C++) __gshared Type tint8;
370 extern (C++) __gshared Type tuns8;
371 extern (C++) __gshared Type tint16;
372 extern (C++) __gshared Type tuns16;
373 extern (C++) __gshared Type tint32;
374 extern (C++) __gshared Type tuns32;
375 extern (C++) __gshared Type tint64;
376 extern (C++) __gshared Type tuns64;
377 extern (C++) __gshared Type tint128;
378 extern (C++) __gshared Type tuns128;
379 extern (C++) __gshared Type tfloat32;
380 extern (C++) __gshared Type tfloat64;
381 extern (C++) __gshared Type tfloat80;
382 extern (C++) __gshared Type timaginary32;
383 extern (C++) __gshared Type timaginary64;
384 extern (C++) __gshared Type timaginary80;
385 extern (C++) __gshared Type tcomplex32;
386 extern (C++) __gshared Type tcomplex64;
387 extern (C++) __gshared Type tcomplex80;
388 extern (C++) __gshared Type tbool;
389 extern (C++) __gshared Type tchar;
390 extern (C++) __gshared Type twchar;
391 extern (C++) __gshared Type tdchar;
393 // Some special types
394 extern (C++) __gshared Type tshiftcnt;
395 extern (C++) __gshared Type tvoidptr; // void*
396 extern (C++) __gshared Type tstring; // immutable(char)[]
397 extern (C++) __gshared Type twstring; // immutable(wchar)[]
398 extern (C++) __gshared Type tdstring; // immutable(dchar)[]
399 extern (C++) __gshared Type terror; // for error recovery
400 extern (C++) __gshared Type tnull; // for null type
401 extern (C++) __gshared Type tnoreturn; // for bottom type typeof(*null)
403 extern (C++) __gshared Type tsize_t; // matches size_t alias
404 extern (C++) __gshared Type tptrdiff_t; // matches ptrdiff_t alias
405 extern (C++) __gshared Type thash_t; // matches hash_t alias
407 extern (C++) __gshared ClassDeclaration dtypeinfo;
408 extern (C++) __gshared ClassDeclaration typeinfoclass;
409 extern (C++) __gshared ClassDeclaration typeinfointerface;
410 extern (C++) __gshared ClassDeclaration typeinfostruct;
411 extern (C++) __gshared ClassDeclaration typeinfopointer;
412 extern (C++) __gshared ClassDeclaration typeinfoarray;
413 extern (C++) __gshared ClassDeclaration typeinfostaticarray;
414 extern (C++) __gshared ClassDeclaration typeinfoassociativearray;
415 extern (C++) __gshared ClassDeclaration typeinfovector;
416 extern (C++) __gshared ClassDeclaration typeinfoenum;
417 extern (C++) __gshared ClassDeclaration typeinfofunction;
418 extern (C++) __gshared ClassDeclaration typeinfodelegate;
419 extern (C++) __gshared ClassDeclaration typeinfotypelist;
420 extern (C++) __gshared ClassDeclaration typeinfoconst;
421 extern (C++) __gshared ClassDeclaration typeinfoinvariant;
422 extern (C++) __gshared ClassDeclaration typeinfoshared;
423 extern (C++) __gshared ClassDeclaration typeinfowild;
425 extern (C++) __gshared TemplateDeclaration rtinfo;
427 extern (C++) __gshared Type[TMAX] basic;
429 extern (D) __gshared StringTable!Type stringtable;
430 extern (D) private static immutable ubyte[TMAX] sizeTy = ()
432 ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic);
433 sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray);
434 sizeTy[Tarray] = __traits(classInstanceSize, TypeDArray);
435 sizeTy[Taarray] = __traits(classInstanceSize, TypeAArray);
436 sizeTy[Tpointer] = __traits(classInstanceSize, TypePointer);
437 sizeTy[Treference] = __traits(classInstanceSize, TypeReference);
438 sizeTy[Tfunction] = __traits(classInstanceSize, TypeFunction);
439 sizeTy[Tdelegate] = __traits(classInstanceSize, TypeDelegate);
440 sizeTy[Tident] = __traits(classInstanceSize, TypeIdentifier);
441 sizeTy[Tinstance] = __traits(classInstanceSize, TypeInstance);
442 sizeTy[Ttypeof] = __traits(classInstanceSize, TypeTypeof);
443 sizeTy[Tenum] = __traits(classInstanceSize, TypeEnum);
444 sizeTy[Tstruct] = __traits(classInstanceSize, TypeStruct);
445 sizeTy[Tclass] = __traits(classInstanceSize, TypeClass);
446 sizeTy[Ttuple] = __traits(classInstanceSize, TypeTuple);
447 sizeTy[Tslice] = __traits(classInstanceSize, TypeSlice);
448 sizeTy[Treturn] = __traits(classInstanceSize, TypeReturn);
449 sizeTy[Terror] = __traits(classInstanceSize, TypeError);
450 sizeTy[Tnull] = __traits(classInstanceSize, TypeNull);
451 sizeTy[Tvector] = __traits(classInstanceSize, TypeVector);
452 sizeTy[Ttraits] = __traits(classInstanceSize, TypeTraits);
453 sizeTy[Tmixin] = __traits(classInstanceSize, TypeMixin);
454 sizeTy[Tnoreturn] = __traits(classInstanceSize, TypeNoreturn);
455 sizeTy[Ttag] = __traits(classInstanceSize, TypeTag);
456 return sizeTy;
457 }();
459 final extern (D) this(TY ty) scope @safe
461 this.ty = ty;
464 const(char)* kind() const nothrow pure @nogc @safe
466 assert(false); // should be overridden
469 final Type copy() nothrow const
471 Type t = cast(Type)mem.xmalloc(sizeTy[ty]);
472 memcpy(cast(void*)t, cast(void*)this, sizeTy[ty]);
473 return t;
476 Type syntaxCopy()
478 fprintf(stderr, "this = %s, ty = %d\n", toChars(), ty);
479 assert(0);
482 override bool equals(const RootObject o) const
484 Type t = cast(Type)o;
485 //printf("Type::equals(%s, %s)\n", toChars(), t.toChars());
486 // deco strings are unique
487 // and semantic() has been run
488 if (this == o || ((t && deco == t.deco) && deco !is null))
490 //printf("deco = '%s', t.deco = '%s'\n", deco, t.deco);
491 return true;
493 //if (deco && t && t.deco) printf("deco = '%s', t.deco = '%s'\n", deco, t.deco);
494 return false;
497 final bool equivalent(Type t)
499 return immutableOf().equals(t.immutableOf());
502 // kludge for template.isType()
503 override final DYNCAST dyncast() const
505 return DYNCAST.type;
508 /// Returns a non-zero unique ID for this Type, or returns 0 if the Type does not (yet) have a unique ID.
509 /// If `semantic()` has not been run, 0 is returned.
510 final size_t getUniqueID() const
512 return cast(size_t) deco;
515 extern (D)
516 final Mcache* getMcache()
518 if (!mcache)
519 mcache = cast(Mcache*) mem.xcalloc(Mcache.sizeof, 1);
520 return mcache;
523 /********************************
524 * For pretty-printing a type.
526 final override const(char)* toChars() const
528 OutBuffer buf;
529 buf.reserve(16);
530 HdrGenState hgs;
531 hgs.fullQual = (ty == Tclass && !mod);
533 toCBuffer(this, buf, null, hgs);
534 return buf.extractChars();
537 /// ditto
538 final char* toPrettyChars(bool QualifyTypes = false)
540 OutBuffer buf;
541 buf.reserve(16);
542 HdrGenState hgs;
543 hgs.fullQual = QualifyTypes;
545 toCBuffer(this, buf, null, hgs);
546 return buf.extractChars();
549 static void _init()
551 stringtable._init(14_000);
553 // Set basic types
554 __gshared TY* basetab =
556 Tvoid,
557 Tint8,
558 Tuns8,
559 Tint16,
560 Tuns16,
561 Tint32,
562 Tuns32,
563 Tint64,
564 Tuns64,
565 Tint128,
566 Tuns128,
567 Tfloat32,
568 Tfloat64,
569 Tfloat80,
570 Timaginary32,
571 Timaginary64,
572 Timaginary80,
573 Tcomplex32,
574 Tcomplex64,
575 Tcomplex80,
576 Tbool,
577 Tchar,
578 Twchar,
579 Tdchar,
580 Terror
583 for (size_t i = 0; basetab[i] != Terror; i++)
585 Type t = new TypeBasic(basetab[i]);
586 t = t.merge();
587 basic[basetab[i]] = t;
589 basic[Terror] = new TypeError();
591 tnoreturn = new TypeNoreturn();
592 tnoreturn.deco = tnoreturn.merge().deco;
593 basic[Tnoreturn] = tnoreturn;
595 tvoid = basic[Tvoid];
596 tint8 = basic[Tint8];
597 tuns8 = basic[Tuns8];
598 tint16 = basic[Tint16];
599 tuns16 = basic[Tuns16];
600 tint32 = basic[Tint32];
601 tuns32 = basic[Tuns32];
602 tint64 = basic[Tint64];
603 tuns64 = basic[Tuns64];
604 tint128 = basic[Tint128];
605 tuns128 = basic[Tuns128];
606 tfloat32 = basic[Tfloat32];
607 tfloat64 = basic[Tfloat64];
608 tfloat80 = basic[Tfloat80];
610 timaginary32 = basic[Timaginary32];
611 timaginary64 = basic[Timaginary64];
612 timaginary80 = basic[Timaginary80];
614 tcomplex32 = basic[Tcomplex32];
615 tcomplex64 = basic[Tcomplex64];
616 tcomplex80 = basic[Tcomplex80];
618 tbool = basic[Tbool];
619 tchar = basic[Tchar];
620 twchar = basic[Twchar];
621 tdchar = basic[Tdchar];
623 tshiftcnt = tint32;
624 terror = basic[Terror];
625 tnoreturn = basic[Tnoreturn];
626 tnull = new TypeNull();
627 tnull.deco = tnull.merge().deco;
629 tvoidptr = tvoid.pointerTo();
630 tstring = tchar.immutableOf().arrayOf();
631 twstring = twchar.immutableOf().arrayOf();
632 tdstring = tdchar.immutableOf().arrayOf();
634 const isLP64 = target.isLP64;
636 tsize_t = basic[isLP64 ? Tuns64 : Tuns32];
637 tptrdiff_t = basic[isLP64 ? Tint64 : Tint32];
638 thash_t = tsize_t;
642 * Deinitializes the global state of the compiler.
644 * This can be used to restore the state set by `_init` to its original
645 * state.
647 static void deinitialize()
649 stringtable = stringtable.init;
652 final uinteger_t size()
654 return size(Loc.initial);
657 uinteger_t size(const ref Loc loc)
659 error(loc, "no size for type `%s`", toChars());
660 return SIZE_INVALID;
663 uint alignsize()
665 return cast(uint)size(Loc.initial);
668 final Type trySemantic(const ref Loc loc, Scope* sc)
670 //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
672 // Needed to display any deprecations that were gagged
673 auto tcopy = this.syntaxCopy();
675 const errors = global.startGagging();
676 Type t = typeSemantic(this, loc, sc);
677 if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
679 t = null;
681 else
683 // If `typeSemantic` succeeded, there may have been deprecations that
684 // were gagged due the `startGagging` above. Run again to display
685 // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
686 if (global.gaggedWarnings > 0)
687 typeSemantic(tcopy, loc, sc);
689 //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
690 return t;
693 /*************************************
694 * This version does a merge even if the deco is already computed.
695 * Necessary for types that have a deco, but are not merged.
697 final Type merge2()
699 //printf("merge2(%s)\n", toChars());
700 Type t = this;
701 assert(t);
702 if (!t.deco)
703 return t.merge();
705 auto sv = stringtable.lookup(t.deco, strlen(t.deco));
706 if (sv && sv.value)
708 t = sv.value;
709 assert(t.deco);
711 else
712 assert(0);
713 return t;
716 /*********************************
717 * Store this type's modifier name into buf.
719 final void modToBuffer(ref OutBuffer buf) nothrow const
721 if (mod)
723 buf.writeByte(' ');
724 MODtoBuffer(buf, mod);
728 /*********************************
729 * Return this type's modifier name.
731 final char* modToChars() nothrow const
733 OutBuffer buf;
734 buf.reserve(16);
735 modToBuffer(buf);
736 return buf.extractChars();
739 bool isintegral()
741 return false;
744 // real, imaginary, or complex
745 bool isfloating()
747 return false;
750 bool isreal()
752 return false;
755 bool isimaginary()
757 return false;
760 bool iscomplex()
762 return false;
765 bool isscalar()
767 return false;
770 bool isunsigned()
772 return false;
775 bool isscope()
777 return false;
780 bool isString()
782 return false;
785 /**************************
786 * When T is mutable,
787 * Given:
788 * T a, b;
789 * Can we bitwise assign:
790 * a = b;
793 bool isAssignable()
795 return true;
798 /**************************
799 * Returns true if T can be converted to boolean value.
801 bool isBoolean()
803 return isscalar();
806 final bool isConst() const nothrow pure @nogc @safe
808 return (mod & MODFlags.const_) != 0;
811 final bool isImmutable() const nothrow pure @nogc @safe
813 return (mod & MODFlags.immutable_) != 0;
816 final bool isMutable() const nothrow pure @nogc @safe
818 return (mod & (MODFlags.const_ | MODFlags.immutable_ | MODFlags.wild)) == 0;
821 final bool isShared() const nothrow pure @nogc @safe
823 return (mod & MODFlags.shared_) != 0;
826 final bool isSharedConst() const nothrow pure @nogc @safe
828 return (mod & (MODFlags.shared_ | MODFlags.const_)) == (MODFlags.shared_ | MODFlags.const_);
831 final bool isWild() const nothrow pure @nogc @safe
833 return (mod & MODFlags.wild) != 0;
836 final bool isWildConst() const nothrow pure @nogc @safe
838 return (mod & MODFlags.wildconst) == MODFlags.wildconst;
841 final bool isSharedWild() const nothrow pure @nogc @safe
843 return (mod & (MODFlags.shared_ | MODFlags.wild)) == (MODFlags.shared_ | MODFlags.wild);
846 final bool isNaked() const nothrow pure @nogc @safe
848 return mod == 0;
851 /********************************
852 * Return a copy of this type with all attributes null-initialized.
853 * Useful for creating a type with different modifiers.
855 final Type nullAttributes() nothrow const
857 uint sz = sizeTy[ty];
858 Type t = cast(Type)mem.xmalloc(sz);
859 memcpy(cast(void*)t, cast(void*)this, sz);
860 // t.mod = NULL; // leave mod unchanged
861 t.deco = null;
862 t.arrayof = null;
863 t.pto = null;
864 t.rto = null;
865 t.vtinfo = null;
866 t.ctype = null;
867 t.mcache = null;
868 if (t.ty == Tstruct)
869 (cast(TypeStruct)t).att = AliasThisRec.fwdref;
870 if (t.ty == Tclass)
871 (cast(TypeClass)t).att = AliasThisRec.fwdref;
872 return t;
875 /********************************
876 * Convert to 'const'.
878 final Type constOf()
880 //printf("Type::constOf() %p %s\n", this, toChars());
881 if (mod == MODFlags.const_)
882 return this;
883 if (mcache && mcache.cto)
885 assert(mcache.cto.mod == MODFlags.const_);
886 return mcache.cto;
888 Type t = makeConst();
889 t = t.merge();
890 t.fixTo(this);
891 //printf("-Type::constOf() %p %s\n", t, t.toChars());
892 return t;
895 /********************************
896 * Convert to 'immutable'.
898 final Type immutableOf()
900 //printf("Type::immutableOf() %p %s\n", this, toChars());
901 if (isImmutable())
902 return this;
903 if (mcache && mcache.ito)
905 assert(mcache.ito.isImmutable());
906 return mcache.ito;
908 Type t = makeImmutable();
909 t = t.merge();
910 t.fixTo(this);
911 //printf("\t%p\n", t);
912 return t;
915 /********************************
916 * Make type mutable.
918 final Type mutableOf()
920 //printf("Type::mutableOf() %p, %s\n", this, toChars());
921 Type t = this;
922 if (isImmutable())
924 getMcache();
925 t = mcache.ito; // immutable => naked
926 assert(!t || (t.isMutable() && !t.isShared()));
928 else if (isConst())
930 getMcache();
931 if (isShared())
933 if (isWild())
934 t = mcache.swcto; // shared wild const -> shared
935 else
936 t = mcache.sto; // shared const => shared
938 else
940 if (isWild())
941 t = mcache.wcto; // wild const -> naked
942 else
943 t = mcache.cto; // const => naked
945 assert(!t || t.isMutable());
947 else if (isWild())
949 getMcache();
950 if (isShared())
951 t = mcache.sto; // shared wild => shared
952 else
953 t = mcache.wto; // wild => naked
954 assert(!t || t.isMutable());
956 if (!t)
958 t = makeMutable();
959 t = t.merge();
960 t.fixTo(this);
962 else
963 t = t.merge();
964 assert(t.isMutable());
965 return t;
968 final Type sharedOf()
970 //printf("Type::sharedOf() %p, %s\n", this, toChars());
971 if (mod == MODFlags.shared_)
972 return this;
973 if (mcache && mcache.sto)
975 assert(mcache.sto.mod == MODFlags.shared_);
976 return mcache.sto;
978 Type t = makeShared();
979 t = t.merge();
980 t.fixTo(this);
981 //printf("\t%p\n", t);
982 return t;
985 final Type sharedConstOf()
987 //printf("Type::sharedConstOf() %p, %s\n", this, toChars());
988 if (mod == (MODFlags.shared_ | MODFlags.const_))
989 return this;
990 if (mcache && mcache.scto)
992 assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_));
993 return mcache.scto;
995 Type t = makeSharedConst();
996 t = t.merge();
997 t.fixTo(this);
998 //printf("\t%p\n", t);
999 return t;
1002 /********************************
1003 * Make type unshared.
1004 * 0 => 0
1005 * const => const
1006 * immutable => immutable
1007 * shared => 0
1008 * shared const => const
1009 * wild => wild
1010 * wild const => wild const
1011 * shared wild => wild
1012 * shared wild const => wild const
1014 final Type unSharedOf()
1016 //printf("Type::unSharedOf() %p, %s\n", this, toChars());
1017 Type t = this;
1019 if (isShared())
1021 getMcache();
1022 if (isWild())
1024 if (isConst())
1025 t = mcache.wcto; // shared wild const => wild const
1026 else
1027 t = mcache.wto; // shared wild => wild
1029 else
1031 if (isConst())
1032 t = mcache.cto; // shared const => const
1033 else
1034 t = mcache.sto; // shared => naked
1036 assert(!t || !t.isShared());
1039 if (!t)
1041 t = this.nullAttributes();
1042 t.mod = mod & ~MODFlags.shared_;
1043 t.ctype = ctype;
1044 t = t.merge();
1045 t.fixTo(this);
1047 else
1048 t = t.merge();
1049 assert(!t.isShared());
1050 return t;
1053 /********************************
1054 * Convert to 'wild'.
1056 final Type wildOf()
1058 //printf("Type::wildOf() %p %s\n", this, toChars());
1059 if (mod == MODFlags.wild)
1060 return this;
1061 if (mcache && mcache.wto)
1063 assert(mcache.wto.mod == MODFlags.wild);
1064 return mcache.wto;
1066 Type t = makeWild();
1067 t = t.merge();
1068 t.fixTo(this);
1069 //printf("\t%p %s\n", t, t.toChars());
1070 return t;
1073 final Type wildConstOf()
1075 //printf("Type::wildConstOf() %p %s\n", this, toChars());
1076 if (mod == MODFlags.wildconst)
1077 return this;
1078 if (mcache && mcache.wcto)
1080 assert(mcache.wcto.mod == MODFlags.wildconst);
1081 return mcache.wcto;
1083 Type t = makeWildConst();
1084 t = t.merge();
1085 t.fixTo(this);
1086 //printf("\t%p %s\n", t, t.toChars());
1087 return t;
1090 final Type sharedWildOf()
1092 //printf("Type::sharedWildOf() %p, %s\n", this, toChars());
1093 if (mod == (MODFlags.shared_ | MODFlags.wild))
1094 return this;
1095 if (mcache && mcache.swto)
1097 assert(mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild));
1098 return mcache.swto;
1100 Type t = makeSharedWild();
1101 t = t.merge();
1102 t.fixTo(this);
1103 //printf("\t%p %s\n", t, t.toChars());
1104 return t;
1107 final Type sharedWildConstOf()
1109 //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars());
1110 if (mod == (MODFlags.shared_ | MODFlags.wildconst))
1111 return this;
1112 if (mcache && mcache.swcto)
1114 assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1115 return mcache.swcto;
1117 Type t = makeSharedWildConst();
1118 t = t.merge();
1119 t.fixTo(this);
1120 //printf("\t%p %s\n", t, t.toChars());
1121 return t;
1124 /**********************************
1125 * For our new type 'this', which is type-constructed from t,
1126 * fill in the cto, ito, sto, scto, wto shortcuts.
1128 extern (D) final void fixTo(Type t)
1130 // If fixing this: immutable(T*) by t: immutable(T)*,
1131 // cache t to this.xto won't break transitivity.
1132 Type mto = null;
1133 Type tn = nextOf();
1134 if (!tn || ty != Tsarray && tn.mod == t.nextOf().mod)
1136 switch (t.mod)
1138 case 0:
1139 mto = t;
1140 break;
1142 case MODFlags.const_:
1143 getMcache();
1144 mcache.cto = t;
1145 break;
1147 case MODFlags.wild:
1148 getMcache();
1149 mcache.wto = t;
1150 break;
1152 case MODFlags.wildconst:
1153 getMcache();
1154 mcache.wcto = t;
1155 break;
1157 case MODFlags.shared_:
1158 getMcache();
1159 mcache.sto = t;
1160 break;
1162 case MODFlags.shared_ | MODFlags.const_:
1163 getMcache();
1164 mcache.scto = t;
1165 break;
1167 case MODFlags.shared_ | MODFlags.wild:
1168 getMcache();
1169 mcache.swto = t;
1170 break;
1172 case MODFlags.shared_ | MODFlags.wildconst:
1173 getMcache();
1174 mcache.swcto = t;
1175 break;
1177 case MODFlags.immutable_:
1178 getMcache();
1179 mcache.ito = t;
1180 break;
1182 default:
1183 break;
1186 assert(mod != t.mod);
1188 if (mod)
1190 getMcache();
1191 t.getMcache();
1193 switch (mod)
1195 case 0:
1196 break;
1198 case MODFlags.const_:
1199 mcache.cto = mto;
1200 t.mcache.cto = this;
1201 break;
1203 case MODFlags.wild:
1204 mcache.wto = mto;
1205 t.mcache.wto = this;
1206 break;
1208 case MODFlags.wildconst:
1209 mcache.wcto = mto;
1210 t.mcache.wcto = this;
1211 break;
1213 case MODFlags.shared_:
1214 mcache.sto = mto;
1215 t.mcache.sto = this;
1216 break;
1218 case MODFlags.shared_ | MODFlags.const_:
1219 mcache.scto = mto;
1220 t.mcache.scto = this;
1221 break;
1223 case MODFlags.shared_ | MODFlags.wild:
1224 mcache.swto = mto;
1225 t.mcache.swto = this;
1226 break;
1228 case MODFlags.shared_ | MODFlags.wildconst:
1229 mcache.swcto = mto;
1230 t.mcache.swcto = this;
1231 break;
1233 case MODFlags.immutable_:
1234 t.mcache.ito = this;
1235 if (t.mcache.cto)
1236 t.mcache.cto.getMcache().ito = this;
1237 if (t.mcache.sto)
1238 t.mcache.sto.getMcache().ito = this;
1239 if (t.mcache.scto)
1240 t.mcache.scto.getMcache().ito = this;
1241 if (t.mcache.wto)
1242 t.mcache.wto.getMcache().ito = this;
1243 if (t.mcache.wcto)
1244 t.mcache.wcto.getMcache().ito = this;
1245 if (t.mcache.swto)
1246 t.mcache.swto.getMcache().ito = this;
1247 if (t.mcache.swcto)
1248 t.mcache.swcto.getMcache().ito = this;
1249 break;
1251 default:
1252 assert(0);
1255 check();
1256 t.check();
1257 //printf("fixTo: %s, %s\n", toChars(), t.toChars());
1260 /***************************
1261 * Look for bugs in constructing types.
1263 extern (D) final void check()
1265 if (mcache)
1266 with (mcache)
1267 switch (mod)
1269 case 0:
1270 if (cto)
1271 assert(cto.mod == MODFlags.const_);
1272 if (ito)
1273 assert(ito.mod == MODFlags.immutable_);
1274 if (sto)
1275 assert(sto.mod == MODFlags.shared_);
1276 if (scto)
1277 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
1278 if (wto)
1279 assert(wto.mod == MODFlags.wild);
1280 if (wcto)
1281 assert(wcto.mod == MODFlags.wildconst);
1282 if (swto)
1283 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
1284 if (swcto)
1285 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1286 break;
1288 case MODFlags.const_:
1289 if (cto)
1290 assert(cto.mod == 0);
1291 if (ito)
1292 assert(ito.mod == MODFlags.immutable_);
1293 if (sto)
1294 assert(sto.mod == MODFlags.shared_);
1295 if (scto)
1296 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
1297 if (wto)
1298 assert(wto.mod == MODFlags.wild);
1299 if (wcto)
1300 assert(wcto.mod == MODFlags.wildconst);
1301 if (swto)
1302 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
1303 if (swcto)
1304 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1305 break;
1307 case MODFlags.wild:
1308 if (cto)
1309 assert(cto.mod == MODFlags.const_);
1310 if (ito)
1311 assert(ito.mod == MODFlags.immutable_);
1312 if (sto)
1313 assert(sto.mod == MODFlags.shared_);
1314 if (scto)
1315 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
1316 if (wto)
1317 assert(wto.mod == 0);
1318 if (wcto)
1319 assert(wcto.mod == MODFlags.wildconst);
1320 if (swto)
1321 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
1322 if (swcto)
1323 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1324 break;
1326 case MODFlags.wildconst:
1327 assert(!cto || cto.mod == MODFlags.const_);
1328 assert(!ito || ito.mod == MODFlags.immutable_);
1329 assert(!sto || sto.mod == MODFlags.shared_);
1330 assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_));
1331 assert(!wto || wto.mod == MODFlags.wild);
1332 assert(!wcto || wcto.mod == 0);
1333 assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild));
1334 assert(!swcto || swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1335 break;
1337 case MODFlags.shared_:
1338 if (cto)
1339 assert(cto.mod == MODFlags.const_);
1340 if (ito)
1341 assert(ito.mod == MODFlags.immutable_);
1342 if (sto)
1343 assert(sto.mod == 0);
1344 if (scto)
1345 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
1346 if (wto)
1347 assert(wto.mod == MODFlags.wild);
1348 if (wcto)
1349 assert(wcto.mod == MODFlags.wildconst);
1350 if (swto)
1351 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
1352 if (swcto)
1353 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1354 break;
1356 case MODFlags.shared_ | MODFlags.const_:
1357 if (cto)
1358 assert(cto.mod == MODFlags.const_);
1359 if (ito)
1360 assert(ito.mod == MODFlags.immutable_);
1361 if (sto)
1362 assert(sto.mod == MODFlags.shared_);
1363 if (scto)
1364 assert(scto.mod == 0);
1365 if (wto)
1366 assert(wto.mod == MODFlags.wild);
1367 if (wcto)
1368 assert(wcto.mod == MODFlags.wildconst);
1369 if (swto)
1370 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
1371 if (swcto)
1372 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1373 break;
1375 case MODFlags.shared_ | MODFlags.wild:
1376 if (cto)
1377 assert(cto.mod == MODFlags.const_);
1378 if (ito)
1379 assert(ito.mod == MODFlags.immutable_);
1380 if (sto)
1381 assert(sto.mod == MODFlags.shared_);
1382 if (scto)
1383 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
1384 if (wto)
1385 assert(wto.mod == MODFlags.wild);
1386 if (wcto)
1387 assert(wcto.mod == MODFlags.wildconst);
1388 if (swto)
1389 assert(swto.mod == 0);
1390 if (swcto)
1391 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1392 break;
1394 case MODFlags.shared_ | MODFlags.wildconst:
1395 assert(!cto || cto.mod == MODFlags.const_);
1396 assert(!ito || ito.mod == MODFlags.immutable_);
1397 assert(!sto || sto.mod == MODFlags.shared_);
1398 assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_));
1399 assert(!wto || wto.mod == MODFlags.wild);
1400 assert(!wcto || wcto.mod == MODFlags.wildconst);
1401 assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild));
1402 assert(!swcto || swcto.mod == 0);
1403 break;
1405 case MODFlags.immutable_:
1406 if (cto)
1407 assert(cto.mod == MODFlags.const_);
1408 if (ito)
1409 assert(ito.mod == 0);
1410 if (sto)
1411 assert(sto.mod == MODFlags.shared_);
1412 if (scto)
1413 assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
1414 if (wto)
1415 assert(wto.mod == MODFlags.wild);
1416 if (wcto)
1417 assert(wcto.mod == MODFlags.wildconst);
1418 if (swto)
1419 assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
1420 if (swcto)
1421 assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
1422 break;
1424 default:
1425 assert(0);
1428 Type tn = nextOf();
1429 if (tn && ty != Tfunction && tn.ty != Tfunction && ty != Tenum)
1431 // Verify transitivity
1432 switch (mod)
1434 case 0:
1435 case MODFlags.const_:
1436 case MODFlags.wild:
1437 case MODFlags.wildconst:
1438 case MODFlags.shared_:
1439 case MODFlags.shared_ | MODFlags.const_:
1440 case MODFlags.shared_ | MODFlags.wild:
1441 case MODFlags.shared_ | MODFlags.wildconst:
1442 case MODFlags.immutable_:
1443 assert(tn.mod == MODFlags.immutable_ || (tn.mod & mod) == mod);
1444 break;
1446 default:
1447 assert(0);
1449 tn.check();
1453 /*************************************
1454 * Apply STCxxxx bits to existing type.
1455 * Use *before* semantic analysis is run.
1457 extern (D) final Type addSTC(StorageClass stc)
1459 Type t = this;
1460 if (t.isImmutable())
1463 else if (stc & STC.immutable_)
1465 t = t.makeImmutable();
1467 else
1469 if ((stc & STC.shared_) && !t.isShared())
1471 if (t.isWild())
1473 if (t.isConst())
1474 t = t.makeSharedWildConst();
1475 else
1476 t = t.makeSharedWild();
1478 else
1480 if (t.isConst())
1481 t = t.makeSharedConst();
1482 else
1483 t = t.makeShared();
1486 if ((stc & STC.const_) && !t.isConst())
1488 if (t.isShared())
1490 if (t.isWild())
1491 t = t.makeSharedWildConst();
1492 else
1493 t = t.makeSharedConst();
1495 else
1497 if (t.isWild())
1498 t = t.makeWildConst();
1499 else
1500 t = t.makeConst();
1503 if ((stc & STC.wild) && !t.isWild())
1505 if (t.isShared())
1507 if (t.isConst())
1508 t = t.makeSharedWildConst();
1509 else
1510 t = t.makeSharedWild();
1512 else
1514 if (t.isConst())
1515 t = t.makeWildConst();
1516 else
1517 t = t.makeWild();
1521 return t;
1524 /************************************
1525 * Apply MODxxxx bits to existing type.
1527 final Type castMod(MOD mod)
1529 Type t;
1530 switch (mod)
1532 case 0:
1533 t = unSharedOf().mutableOf();
1534 break;
1536 case MODFlags.const_:
1537 t = unSharedOf().constOf();
1538 break;
1540 case MODFlags.wild:
1541 t = unSharedOf().wildOf();
1542 break;
1544 case MODFlags.wildconst:
1545 t = unSharedOf().wildConstOf();
1546 break;
1548 case MODFlags.shared_:
1549 t = mutableOf().sharedOf();
1550 break;
1552 case MODFlags.shared_ | MODFlags.const_:
1553 t = sharedConstOf();
1554 break;
1556 case MODFlags.shared_ | MODFlags.wild:
1557 t = sharedWildOf();
1558 break;
1560 case MODFlags.shared_ | MODFlags.wildconst:
1561 t = sharedWildConstOf();
1562 break;
1564 case MODFlags.immutable_:
1565 t = immutableOf();
1566 break;
1568 default:
1569 assert(0);
1571 return t;
1574 /************************************
1575 * Add MODxxxx bits to existing type.
1576 * We're adding, not replacing, so adding const to
1577 * a shared type => "shared const"
1579 final Type addMod(MOD mod)
1581 /* Add anything to immutable, and it remains immutable
1583 Type t = this;
1584 if (!t.isImmutable())
1586 //printf("addMod(%x) %s\n", mod, toChars());
1587 switch (mod)
1589 case 0:
1590 break;
1592 case MODFlags.const_:
1593 if (isShared())
1595 if (isWild())
1596 t = sharedWildConstOf();
1597 else
1598 t = sharedConstOf();
1600 else
1602 if (isWild())
1603 t = wildConstOf();
1604 else
1605 t = constOf();
1607 break;
1609 case MODFlags.wild:
1610 if (isShared())
1612 if (isConst())
1613 t = sharedWildConstOf();
1614 else
1615 t = sharedWildOf();
1617 else
1619 if (isConst())
1620 t = wildConstOf();
1621 else
1622 t = wildOf();
1624 break;
1626 case MODFlags.wildconst:
1627 if (isShared())
1628 t = sharedWildConstOf();
1629 else
1630 t = wildConstOf();
1631 break;
1633 case MODFlags.shared_:
1634 if (isWild())
1636 if (isConst())
1637 t = sharedWildConstOf();
1638 else
1639 t = sharedWildOf();
1641 else
1643 if (isConst())
1644 t = sharedConstOf();
1645 else
1646 t = sharedOf();
1648 break;
1650 case MODFlags.shared_ | MODFlags.const_:
1651 if (isWild())
1652 t = sharedWildConstOf();
1653 else
1654 t = sharedConstOf();
1655 break;
1657 case MODFlags.shared_ | MODFlags.wild:
1658 if (isConst())
1659 t = sharedWildConstOf();
1660 else
1661 t = sharedWildOf();
1662 break;
1664 case MODFlags.shared_ | MODFlags.wildconst:
1665 t = sharedWildConstOf();
1666 break;
1668 case MODFlags.immutable_:
1669 t = immutableOf();
1670 break;
1672 default:
1673 assert(0);
1676 return t;
1679 /************************************
1680 * Add storage class modifiers to type.
1682 Type addStorageClass(StorageClass stc)
1684 /* Just translate to MOD bits and let addMod() do the work
1686 MOD mod = 0;
1687 if (stc & STC.immutable_)
1688 mod = MODFlags.immutable_;
1689 else
1691 if (stc & (STC.const_ | STC.in_))
1692 mod |= MODFlags.const_;
1693 if (stc & STC.wild)
1694 mod |= MODFlags.wild;
1695 if (stc & STC.shared_)
1696 mod |= MODFlags.shared_;
1698 return addMod(mod);
1701 final Type pointerTo()
1703 if (ty == Terror)
1704 return this;
1705 if (!pto)
1707 Type t = new TypePointer(this);
1708 if (ty == Tfunction)
1710 t.deco = t.merge().deco;
1711 pto = t;
1713 else
1714 pto = t.merge();
1716 return pto;
1719 final Type referenceTo()
1721 if (ty == Terror)
1722 return this;
1723 if (!rto)
1725 Type t = new TypeReference(this);
1726 rto = t.merge();
1728 return rto;
1731 final Type arrayOf()
1733 if (ty == Terror)
1734 return this;
1735 if (!arrayof)
1737 Type t = new TypeDArray(this);
1738 arrayof = t.merge();
1740 return arrayof;
1743 // Make corresponding static array type without semantic
1744 final Type sarrayOf(dinteger_t dim)
1746 assert(deco);
1747 Type t = new TypeSArray(this, new IntegerExp(Loc.initial, dim, Type.tsize_t));
1748 // according to TypeSArray::semantic()
1749 t = t.addMod(mod);
1750 t = t.merge();
1751 return t;
1754 final bool hasDeprecatedAliasThis()
1756 auto ad = isAggregate(this);
1757 return ad && ad.aliasthis && (ad.aliasthis.isDeprecated || ad.aliasthis.sym.isDeprecated);
1760 final Type aliasthisOf()
1762 auto ad = isAggregate(this);
1763 if (!ad || !ad.aliasthis)
1764 return null;
1766 auto s = ad.aliasthis.sym;
1767 if (s.isAliasDeclaration())
1768 s = s.toAlias();
1770 if (s.isTupleDeclaration())
1771 return null;
1773 if (auto vd = s.isVarDeclaration())
1775 auto t = vd.type;
1776 if (vd.needThis())
1777 t = t.addMod(this.mod);
1778 return t;
1780 Dsymbol callable = s.isFuncDeclaration();
1781 callable = callable ? callable : s.isTemplateDeclaration();
1782 if (callable)
1784 auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet);
1785 if (!fd || fd.errors || !fd.functionSemantic())
1786 return Type.terror;
1788 auto t = fd.type.nextOf();
1789 if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185
1790 return Type.terror;
1791 t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod);
1792 return t;
1794 if (auto d = s.isDeclaration())
1796 assert(d.type);
1797 return d.type;
1799 if (auto ed = s.isEnumDeclaration())
1801 return ed.type;
1804 //printf("%s\n", s.kind());
1805 return null;
1809 * Check whether this type has endless `alias this` recursion.
1810 * Returns:
1811 * `true` if this type has an `alias this` that can be implicitly
1812 * converted back to this type itself.
1814 extern (D) final bool checkAliasThisRec()
1816 Type tb = toBasetype();
1817 AliasThisRec* pflag;
1818 if (tb.ty == Tstruct)
1819 pflag = &(cast(TypeStruct)tb).att;
1820 else if (tb.ty == Tclass)
1821 pflag = &(cast(TypeClass)tb).att;
1822 else
1823 return false;
1825 AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask);
1826 if (flag == AliasThisRec.fwdref)
1828 Type att = aliasthisOf();
1829 flag = att && att.implicitConvTo(this) ? AliasThisRec.yes : AliasThisRec.no;
1831 *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask));
1832 return flag == AliasThisRec.yes;
1835 Type makeConst()
1837 //printf("Type::makeConst() %p, %s\n", this, toChars());
1838 if (mcache && mcache.cto)
1839 return mcache.cto;
1840 Type t = this.nullAttributes();
1841 t.mod = MODFlags.const_;
1842 //printf("-Type::makeConst() %p, %s\n", t, toChars());
1843 return t;
1846 Type makeImmutable()
1848 if (mcache && mcache.ito)
1849 return mcache.ito;
1850 Type t = this.nullAttributes();
1851 t.mod = MODFlags.immutable_;
1852 return t;
1855 Type makeShared()
1857 if (mcache && mcache.sto)
1858 return mcache.sto;
1859 Type t = this.nullAttributes();
1860 t.mod = MODFlags.shared_;
1861 return t;
1864 Type makeSharedConst()
1866 if (mcache && mcache.scto)
1867 return mcache.scto;
1868 Type t = this.nullAttributes();
1869 t.mod = MODFlags.shared_ | MODFlags.const_;
1870 return t;
1873 Type makeWild()
1875 if (mcache && mcache.wto)
1876 return mcache.wto;
1877 Type t = this.nullAttributes();
1878 t.mod = MODFlags.wild;
1879 return t;
1882 Type makeWildConst()
1884 if (mcache && mcache.wcto)
1885 return mcache.wcto;
1886 Type t = this.nullAttributes();
1887 t.mod = MODFlags.wildconst;
1888 return t;
1891 Type makeSharedWild()
1893 if (mcache && mcache.swto)
1894 return mcache.swto;
1895 Type t = this.nullAttributes();
1896 t.mod = MODFlags.shared_ | MODFlags.wild;
1897 return t;
1900 Type makeSharedWildConst()
1902 if (mcache && mcache.swcto)
1903 return mcache.swcto;
1904 Type t = this.nullAttributes();
1905 t.mod = MODFlags.shared_ | MODFlags.wildconst;
1906 return t;
1909 Type makeMutable()
1911 Type t = this.nullAttributes();
1912 t.mod = mod & MODFlags.shared_;
1913 return t;
1916 Dsymbol toDsymbol(Scope* sc)
1918 return null;
1921 /*******************************
1922 * If this is a shell around another type,
1923 * get that other type.
1925 final Type toBasetype()
1927 /* This function is used heavily.
1928 * De-virtualize it so it can be easily inlined.
1930 TypeEnum te;
1931 return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
1934 bool isBaseOf(Type t, int* poffset)
1936 return 0; // assume not
1939 /********************************
1940 * Determine if 'this' can be implicitly converted
1941 * to type 'to'.
1942 * Returns:
1943 * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
1945 MATCH implicitConvTo(Type to)
1947 //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
1948 //printf("from: %s\n", toChars());
1949 //printf("to : %s\n", to.toChars());
1950 if (this.equals(to))
1951 return MATCH.exact;
1952 return MATCH.nomatch;
1955 /*******************************
1956 * Determine if converting 'this' to 'to' is an identity operation,
1957 * a conversion to const operation, or the types aren't the same.
1958 * Returns:
1959 * MATCH.exact 'this' == 'to'
1960 * MATCH.constant 'to' is const
1961 * MATCH.nomatch conversion to mutable or invariant
1963 MATCH constConv(Type to)
1965 //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars());
1966 if (equals(to))
1967 return MATCH.exact;
1968 if (ty == to.ty && MODimplicitConv(mod, to.mod))
1969 return MATCH.constant;
1970 return MATCH.nomatch;
1973 /***************************************
1974 * Compute MOD bits matching `this` argument type to wild parameter type.
1975 * Params:
1976 * t = corresponding parameter type
1977 * isRef = parameter is `ref` or `out`
1978 * Returns:
1979 * MOD bits
1981 MOD deduceWild(Type t, bool isRef)
1983 //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm.toChars());
1984 if (t.isWild())
1986 if (isImmutable())
1987 return MODFlags.immutable_;
1988 else if (isWildConst())
1990 if (t.isWildConst())
1991 return MODFlags.wild;
1992 else
1993 return MODFlags.wildconst;
1995 else if (isWild())
1996 return MODFlags.wild;
1997 else if (isConst())
1998 return MODFlags.const_;
1999 else if (isMutable())
2000 return MODFlags.mutable;
2001 else
2002 assert(0);
2004 return 0;
2007 Type substWildTo(uint mod)
2009 //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
2010 Type t;
2012 if (Type tn = nextOf())
2014 // substitution has no effect on function pointer type.
2015 if (ty == Tpointer && tn.ty == Tfunction)
2017 t = this;
2018 goto L1;
2021 t = tn.substWildTo(mod);
2022 if (t == tn)
2023 t = this;
2024 else
2026 if (ty == Tpointer)
2027 t = t.pointerTo();
2028 else if (ty == Tarray)
2029 t = t.arrayOf();
2030 else if (ty == Tsarray)
2031 t = new TypeSArray(t, (cast(TypeSArray)this).dim.syntaxCopy());
2032 else if (ty == Taarray)
2034 t = new TypeAArray(t, (cast(TypeAArray)this).index.syntaxCopy());
2036 else if (ty == Tdelegate)
2038 t = new TypeDelegate(t.isTypeFunction());
2040 else
2041 assert(0);
2043 t = t.merge();
2046 else
2047 t = this;
2050 if (isWild())
2052 if (mod == MODFlags.immutable_)
2054 t = t.immutableOf();
2056 else if (mod == MODFlags.wildconst)
2058 t = t.wildConstOf();
2060 else if (mod == MODFlags.wild)
2062 if (isWildConst())
2063 t = t.wildConstOf();
2064 else
2065 t = t.wildOf();
2067 else if (mod == MODFlags.const_)
2069 t = t.constOf();
2071 else
2073 if (isWildConst())
2074 t = t.constOf();
2075 else
2076 t = t.mutableOf();
2079 if (isConst())
2080 t = t.addMod(MODFlags.const_);
2081 if (isShared())
2082 t = t.addMod(MODFlags.shared_);
2084 //printf("-Type::substWildTo t = %s\n", t.toChars());
2085 return t;
2088 final Type unqualify(uint m)
2090 Type t = mutableOf().unSharedOf();
2092 Type tn = ty == Tenum ? null : nextOf();
2093 if (tn && tn.ty != Tfunction)
2095 Type utn = tn.unqualify(m);
2096 if (utn != tn)
2098 if (ty == Tpointer)
2099 t = utn.pointerTo();
2100 else if (ty == Tarray)
2101 t = utn.arrayOf();
2102 else if (ty == Tsarray)
2103 t = new TypeSArray(utn, (cast(TypeSArray)this).dim);
2104 else if (ty == Taarray)
2106 t = new TypeAArray(utn, (cast(TypeAArray)this).index);
2108 else
2109 assert(0);
2111 t = t.merge();
2114 t = t.addMod(mod & ~m);
2115 return t;
2118 /**************************
2119 * Return type with the top level of it being mutable.
2121 inout(Type) toHeadMutable() inout
2123 if (!mod)
2124 return this;
2125 Type unqualThis = cast(Type) this;
2126 // `mutableOf` needs a mutable `this` only for caching
2127 return cast(inout(Type)) unqualThis.mutableOf();
2130 inout(ClassDeclaration) isClassHandle() inout
2132 return null;
2135 /************************************
2136 * Return alignment to use for this type.
2138 structalign_t alignment()
2140 structalign_t s;
2141 s.setDefault();
2142 return s;
2145 /***************************************
2146 * Use when we prefer the default initializer to be a literal,
2147 * rather than a global immutable variable.
2149 Expression defaultInitLiteral(const ref Loc loc)
2151 static if (LOGDEFAULTINIT)
2153 printf("Type::defaultInitLiteral() '%s'\n", toChars());
2155 return defaultInit(this, loc);
2158 // if initializer is 0
2159 bool isZeroInit(const ref Loc loc)
2161 return false; // assume not
2164 final Identifier getTypeInfoIdent()
2166 // _init_10TypeInfo_%s
2167 OutBuffer buf;
2168 buf.reserve(32);
2169 mangleToBuffer(this, buf);
2171 const slice = buf[];
2173 // Allocate buffer on stack, fail over to using malloc()
2174 char[128] namebuf;
2175 const namelen = 19 + size_t.sizeof * 3 + slice.length + 1;
2176 auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen));
2178 const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ",
2179 cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr);
2180 //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
2181 assert(0 < length && length < namelen); // don't overflow the buffer
2183 auto id = Identifier.idPool(name[0 .. length]);
2185 if (name != namebuf.ptr)
2186 free(name);
2187 return id;
2190 /***************************************
2191 * Return !=0 if the type or any of its subtypes is wild.
2193 int hasWild() const
2195 return mod & MODFlags.wild;
2198 /***************************************
2199 * Return !=0 if type has pointers that need to
2200 * be scanned by the GC during a collection cycle.
2202 bool hasPointers()
2204 //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
2205 return false;
2208 /*************************************
2209 * Detect if type has pointer fields that are initialized to void.
2210 * Local stack variables with such void fields can remain uninitialized,
2211 * leading to pointer bugs.
2212 * Returns:
2213 * true if so
2215 bool hasVoidInitPointers()
2217 return false;
2220 /*************************************
2221 * Detect if this is an unsafe type because of the presence of `@system` members
2222 * Returns:
2223 * true if so
2225 bool hasSystemFields()
2227 return false;
2230 /***************************************
2231 * Returns: true if type has any invariants
2233 bool hasInvariant()
2235 //printf("Type::hasInvariant() %s, %d\n", toChars(), ty);
2236 return false;
2239 /*************************************
2240 * If this is a type of something, return that something.
2242 Type nextOf()
2244 return null;
2247 /*************************************
2248 * If this is a type of static array, return its base element type.
2250 final Type baseElemOf()
2252 Type t = toBasetype();
2253 TypeSArray tsa;
2254 while ((tsa = t.isTypeSArray()) !is null)
2255 t = tsa.next.toBasetype();
2256 return t;
2259 /*******************************************
2260 * Compute number of elements for a (possibly multidimensional) static array,
2261 * or 1 for other types.
2262 * Params:
2263 * loc = for error message
2264 * Returns:
2265 * number of elements, uint.max on overflow
2267 final uint numberOfElems(const ref Loc loc)
2269 //printf("Type::numberOfElems()\n");
2270 uinteger_t n = 1;
2271 Type tb = this;
2272 while ((tb = tb.toBasetype()).ty == Tsarray)
2274 bool overflow = false;
2275 n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow);
2276 if (overflow || n >= uint.max)
2278 error(loc, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n);
2279 return uint.max;
2281 tb = (cast(TypeSArray)tb).next;
2283 return cast(uint)n;
2286 /****************************************
2287 * Return the mask that an integral type will
2288 * fit into.
2290 extern (D) final uinteger_t sizemask()
2292 uinteger_t m;
2293 switch (toBasetype().ty)
2295 case Tbool:
2296 m = 1;
2297 break;
2298 case Tchar:
2299 case Tint8:
2300 case Tuns8:
2301 m = 0xFF;
2302 break;
2303 case Twchar:
2304 case Tint16:
2305 case Tuns16:
2306 m = 0xFFFFU;
2307 break;
2308 case Tdchar:
2309 case Tint32:
2310 case Tuns32:
2311 m = 0xFFFFFFFFU;
2312 break;
2313 case Tint64:
2314 case Tuns64:
2315 m = 0xFFFFFFFFFFFFFFFFUL;
2316 break;
2317 default:
2318 assert(0);
2320 return m;
2323 /********************************
2324 * true if when type goes out of scope, it needs a destructor applied.
2325 * Only applies to value types, not ref types.
2327 bool needsDestruction()
2329 return false;
2332 /********************************
2333 * true if when type is copied, it needs a copy constructor or postblit
2334 * applied. Only applies to value types, not ref types.
2336 bool needsCopyOrPostblit()
2338 return false;
2341 /*********************************
2344 bool needsNested()
2346 return false;
2349 /*************************************
2350 * https://issues.dlang.org/show_bug.cgi?id=14488
2351 * Check if the inner most base type is complex or imaginary.
2352 * Should only give alerts when set to emit transitional messages.
2353 * Params:
2354 * loc = The source location.
2355 * sc = scope of the type
2357 extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc)
2359 if (sc.isDeprecated())
2360 return false;
2361 // Don't complain if we're inside a template constraint
2362 // https://issues.dlang.org/show_bug.cgi?id=21831
2363 if (sc.flags & SCOPE.constraint)
2364 return false;
2366 Type t = baseElemOf();
2367 while (t.ty == Tpointer || t.ty == Tarray)
2368 t = t.nextOf().baseElemOf();
2370 // Basetype is an opaque enum, nothing to check.
2371 if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
2372 return false;
2374 if (t.isimaginary() || t.iscomplex())
2376 if (sc.flags & SCOPE.Cfile)
2377 return true; // complex/imaginary not deprecated in C code
2378 Type rt;
2379 switch (t.ty)
2381 case Tcomplex32:
2382 case Timaginary32:
2383 rt = Type.tfloat32;
2384 break;
2386 case Tcomplex64:
2387 case Timaginary64:
2388 rt = Type.tfloat64;
2389 break;
2391 case Tcomplex80:
2392 case Timaginary80:
2393 rt = Type.tfloat80;
2394 break;
2396 default:
2397 assert(0);
2399 // @@@DEPRECATED_2.117@@@
2400 // Deprecated in 2.097 - Can be made an error from 2.117.
2401 // The deprecation period is longer than usual as `cfloat`,
2402 // `cdouble`, and `creal` were quite widely used.
2403 if (t.iscomplex())
2405 deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
2406 toChars(), rt.toChars());
2407 return true;
2409 else
2411 deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
2412 toChars(), rt.toChars());
2413 return true;
2416 return false;
2419 // For eliminating dynamic_cast
2420 TypeBasic isTypeBasic()
2422 return null;
2425 final pure inout nothrow @nogc
2427 /****************
2428 * Is this type a pointer to a function?
2429 * Returns:
2430 * the function type if it is
2432 inout(TypeFunction) isPtrToFunction()
2434 return (ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction)
2435 ? cast(typeof(return))(cast(TypePointer)this).next
2436 : null;
2439 /*****************
2440 * Is this type a function, delegate, or pointer to a function?
2441 * Returns:
2442 * the function type if it is
2444 inout(TypeFunction) isFunction_Delegate_PtrToFunction()
2446 return ty == Tfunction ? cast(typeof(return))this :
2448 ty == Tdelegate ? cast(typeof(return))(cast(TypePointer)this).next :
2450 ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction ?
2451 cast(typeof(return))(cast(TypePointer)this).next :
2453 null;
2457 final pure inout nothrow @nogc @safe
2459 inout(TypeError) isTypeError() { return ty == Terror ? cast(typeof(return))this : null; }
2460 inout(TypeVector) isTypeVector() { return ty == Tvector ? cast(typeof(return))this : null; }
2461 inout(TypeSArray) isTypeSArray() { return ty == Tsarray ? cast(typeof(return))this : null; }
2462 inout(TypeDArray) isTypeDArray() { return ty == Tarray ? cast(typeof(return))this : null; }
2463 inout(TypeAArray) isTypeAArray() { return ty == Taarray ? cast(typeof(return))this : null; }
2464 inout(TypePointer) isTypePointer() { return ty == Tpointer ? cast(typeof(return))this : null; }
2465 inout(TypeReference) isTypeReference() { return ty == Treference ? cast(typeof(return))this : null; }
2466 inout(TypeFunction) isTypeFunction() { return ty == Tfunction ? cast(typeof(return))this : null; }
2467 inout(TypeDelegate) isTypeDelegate() { return ty == Tdelegate ? cast(typeof(return))this : null; }
2468 inout(TypeIdentifier) isTypeIdentifier() { return ty == Tident ? cast(typeof(return))this : null; }
2469 inout(TypeInstance) isTypeInstance() { return ty == Tinstance ? cast(typeof(return))this : null; }
2470 inout(TypeTypeof) isTypeTypeof() { return ty == Ttypeof ? cast(typeof(return))this : null; }
2471 inout(TypeReturn) isTypeReturn() { return ty == Treturn ? cast(typeof(return))this : null; }
2472 inout(TypeStruct) isTypeStruct() { return ty == Tstruct ? cast(typeof(return))this : null; }
2473 inout(TypeEnum) isTypeEnum() { return ty == Tenum ? cast(typeof(return))this : null; }
2474 inout(TypeClass) isTypeClass() { return ty == Tclass ? cast(typeof(return))this : null; }
2475 inout(TypeTuple) isTypeTuple() { return ty == Ttuple ? cast(typeof(return))this : null; }
2476 inout(TypeSlice) isTypeSlice() { return ty == Tslice ? cast(typeof(return))this : null; }
2477 inout(TypeNull) isTypeNull() { return ty == Tnull ? cast(typeof(return))this : null; }
2478 inout(TypeMixin) isTypeMixin() { return ty == Tmixin ? cast(typeof(return))this : null; }
2479 inout(TypeTraits) isTypeTraits() { return ty == Ttraits ? cast(typeof(return))this : null; }
2480 inout(TypeNoreturn) isTypeNoreturn() { return ty == Tnoreturn ? cast(typeof(return))this : null; }
2481 inout(TypeTag) isTypeTag() { return ty == Ttag ? cast(typeof(return))this : null; }
2484 override void accept(Visitor v)
2486 v.visit(this);
2489 final TypeFunction toTypeFunction()
2491 if (ty != Tfunction)
2492 assert(0);
2493 return cast(TypeFunction)this;
2496 extern (D) static Types* arraySyntaxCopy(Types* types)
2498 Types* a = null;
2499 if (types)
2501 a = new Types(types.length);
2502 foreach (i, t; *types)
2504 (*a)[i] = t ? t.syntaxCopy() : null;
2507 return a;
2511 /***********************************************************
2513 extern (C++) final class TypeError : Type
2515 extern (D) this() @safe
2517 super(Terror);
2520 override const(char)* kind() const
2522 return "error";
2525 override TypeError syntaxCopy()
2527 // No semantic analysis done, no need to copy
2528 return this;
2531 override uinteger_t size(const ref Loc loc)
2533 return SIZE_INVALID;
2536 override Expression defaultInitLiteral(const ref Loc loc)
2538 return ErrorExp.get();
2541 override void accept(Visitor v)
2543 v.visit(this);
2547 /***********************************************************
2549 extern (C++) abstract class TypeNext : Type
2551 Type next;
2553 final extern (D) this(TY ty, Type next) @safe
2555 super(ty);
2556 this.next = next;
2559 override final int hasWild() const
2561 if (ty == Tfunction)
2562 return 0;
2563 if (ty == Tdelegate)
2564 return Type.hasWild();
2565 return mod & MODFlags.wild || (next && next.hasWild());
2568 /*******************************
2569 * For TypeFunction, nextOf() can return NULL if the function return
2570 * type is meant to be inferred, and semantic() hasn't yet ben run
2571 * on the function. After semantic(), it must no longer be NULL.
2573 override final Type nextOf()
2575 return next;
2578 override final Type makeConst()
2580 //printf("TypeNext::makeConst() %p, %s\n", this, toChars());
2581 if (mcache && mcache.cto)
2583 assert(mcache.cto.mod == MODFlags.const_);
2584 return mcache.cto;
2586 TypeNext t = cast(TypeNext)Type.makeConst();
2587 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2589 if (next.isShared())
2591 if (next.isWild())
2592 t.next = next.sharedWildConstOf();
2593 else
2594 t.next = next.sharedConstOf();
2596 else
2598 if (next.isWild())
2599 t.next = next.wildConstOf();
2600 else
2601 t.next = next.constOf();
2604 //printf("TypeNext::makeConst() returns %p, %s\n", t, t.toChars());
2605 return t;
2608 override final Type makeImmutable()
2610 //printf("TypeNext::makeImmutable() %s\n", toChars());
2611 if (mcache && mcache.ito)
2613 assert(mcache.ito.isImmutable());
2614 return mcache.ito;
2616 TypeNext t = cast(TypeNext)Type.makeImmutable();
2617 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2619 t.next = next.immutableOf();
2621 return t;
2624 override final Type makeShared()
2626 //printf("TypeNext::makeShared() %s\n", toChars());
2627 if (mcache && mcache.sto)
2629 assert(mcache.sto.mod == MODFlags.shared_);
2630 return mcache.sto;
2632 TypeNext t = cast(TypeNext)Type.makeShared();
2633 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2635 if (next.isWild())
2637 if (next.isConst())
2638 t.next = next.sharedWildConstOf();
2639 else
2640 t.next = next.sharedWildOf();
2642 else
2644 if (next.isConst())
2645 t.next = next.sharedConstOf();
2646 else
2647 t.next = next.sharedOf();
2650 //printf("TypeNext::makeShared() returns %p, %s\n", t, t.toChars());
2651 return t;
2654 override final Type makeSharedConst()
2656 //printf("TypeNext::makeSharedConst() %s\n", toChars());
2657 if (mcache && mcache.scto)
2659 assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_));
2660 return mcache.scto;
2662 TypeNext t = cast(TypeNext)Type.makeSharedConst();
2663 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2665 if (next.isWild())
2666 t.next = next.sharedWildConstOf();
2667 else
2668 t.next = next.sharedConstOf();
2670 //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t.toChars());
2671 return t;
2674 override final Type makeWild()
2676 //printf("TypeNext::makeWild() %s\n", toChars());
2677 if (mcache && mcache.wto)
2679 assert(mcache.wto.mod == MODFlags.wild);
2680 return mcache.wto;
2682 TypeNext t = cast(TypeNext)Type.makeWild();
2683 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2685 if (next.isShared())
2687 if (next.isConst())
2688 t.next = next.sharedWildConstOf();
2689 else
2690 t.next = next.sharedWildOf();
2692 else
2694 if (next.isConst())
2695 t.next = next.wildConstOf();
2696 else
2697 t.next = next.wildOf();
2700 //printf("TypeNext::makeWild() returns %p, %s\n", t, t.toChars());
2701 return t;
2704 override final Type makeWildConst()
2706 //printf("TypeNext::makeWildConst() %s\n", toChars());
2707 if (mcache && mcache.wcto)
2709 assert(mcache.wcto.mod == MODFlags.wildconst);
2710 return mcache.wcto;
2712 TypeNext t = cast(TypeNext)Type.makeWildConst();
2713 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2715 if (next.isShared())
2716 t.next = next.sharedWildConstOf();
2717 else
2718 t.next = next.wildConstOf();
2720 //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t.toChars());
2721 return t;
2724 override final Type makeSharedWild()
2726 //printf("TypeNext::makeSharedWild() %s\n", toChars());
2727 if (mcache && mcache.swto)
2729 assert(mcache.swto.isSharedWild());
2730 return mcache.swto;
2732 TypeNext t = cast(TypeNext)Type.makeSharedWild();
2733 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2735 if (next.isConst())
2736 t.next = next.sharedWildConstOf();
2737 else
2738 t.next = next.sharedWildOf();
2740 //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t.toChars());
2741 return t;
2744 override final Type makeSharedWildConst()
2746 //printf("TypeNext::makeSharedWildConst() %s\n", toChars());
2747 if (mcache && mcache.swcto)
2749 assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
2750 return mcache.swcto;
2752 TypeNext t = cast(TypeNext)Type.makeSharedWildConst();
2753 if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
2755 t.next = next.sharedWildConstOf();
2757 //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t.toChars());
2758 return t;
2761 override final Type makeMutable()
2763 //printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
2764 TypeNext t = cast(TypeNext)Type.makeMutable();
2765 if (ty == Tsarray)
2767 t.next = next.mutableOf();
2769 //printf("TypeNext::makeMutable() returns %p, %s\n", t, t.toChars());
2770 return t;
2773 override MATCH constConv(Type to)
2775 //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars());
2776 if (equals(to))
2777 return MATCH.exact;
2779 if (!(ty == to.ty && MODimplicitConv(mod, to.mod)))
2780 return MATCH.nomatch;
2782 Type tn = to.nextOf();
2783 if (!(tn && next.ty == tn.ty))
2784 return MATCH.nomatch;
2786 MATCH m;
2787 if (to.isConst()) // whole tail const conversion
2789 // Recursive shared level check
2790 m = next.constConv(tn);
2791 if (m == MATCH.exact)
2792 m = MATCH.constant;
2794 else
2796 //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars());
2797 m = next.equals(tn) ? MATCH.constant : MATCH.nomatch;
2799 return m;
2802 override final MOD deduceWild(Type t, bool isRef)
2804 if (ty == Tfunction)
2805 return 0;
2807 ubyte wm;
2809 Type tn = t.nextOf();
2810 if (!isRef && (ty == Tarray || ty == Tpointer) && tn)
2812 wm = next.deduceWild(tn, true);
2813 if (!wm)
2814 wm = Type.deduceWild(t, true);
2816 else
2818 wm = Type.deduceWild(t, isRef);
2819 if (!wm && tn)
2820 wm = next.deduceWild(tn, true);
2823 return wm;
2826 final void transitive()
2828 /* Invoke transitivity of type attributes
2830 next = next.addMod(mod);
2833 override void accept(Visitor v)
2835 v.visit(this);
2839 /***********************************************************
2841 extern (C++) final class TypeBasic : Type
2843 const(char)* dstring;
2844 uint flags;
2846 extern (D) this(TY ty) scope
2848 super(ty);
2849 const(char)* d;
2850 uint flags = 0;
2851 switch (ty)
2853 case Tvoid:
2854 d = Token.toChars(TOK.void_);
2855 break;
2857 case Tint8:
2858 d = Token.toChars(TOK.int8);
2859 flags |= TFlags.integral;
2860 break;
2862 case Tuns8:
2863 d = Token.toChars(TOK.uns8);
2864 flags |= TFlags.integral | TFlags.unsigned;
2865 break;
2867 case Tint16:
2868 d = Token.toChars(TOK.int16);
2869 flags |= TFlags.integral;
2870 break;
2872 case Tuns16:
2873 d = Token.toChars(TOK.uns16);
2874 flags |= TFlags.integral | TFlags.unsigned;
2875 break;
2877 case Tint32:
2878 d = Token.toChars(TOK.int32);
2879 flags |= TFlags.integral;
2880 break;
2882 case Tuns32:
2883 d = Token.toChars(TOK.uns32);
2884 flags |= TFlags.integral | TFlags.unsigned;
2885 break;
2887 case Tfloat32:
2888 d = Token.toChars(TOK.float32);
2889 flags |= TFlags.floating | TFlags.real_;
2890 break;
2892 case Tint64:
2893 d = Token.toChars(TOK.int64);
2894 flags |= TFlags.integral;
2895 break;
2897 case Tuns64:
2898 d = Token.toChars(TOK.uns64);
2899 flags |= TFlags.integral | TFlags.unsigned;
2900 break;
2902 case Tint128:
2903 d = Token.toChars(TOK.int128);
2904 flags |= TFlags.integral;
2905 break;
2907 case Tuns128:
2908 d = Token.toChars(TOK.uns128);
2909 flags |= TFlags.integral | TFlags.unsigned;
2910 break;
2912 case Tfloat64:
2913 d = Token.toChars(TOK.float64);
2914 flags |= TFlags.floating | TFlags.real_;
2915 break;
2917 case Tfloat80:
2918 d = Token.toChars(TOK.float80);
2919 flags |= TFlags.floating | TFlags.real_;
2920 break;
2922 case Timaginary32:
2923 d = Token.toChars(TOK.imaginary32);
2924 flags |= TFlags.floating | TFlags.imaginary;
2925 break;
2927 case Timaginary64:
2928 d = Token.toChars(TOK.imaginary64);
2929 flags |= TFlags.floating | TFlags.imaginary;
2930 break;
2932 case Timaginary80:
2933 d = Token.toChars(TOK.imaginary80);
2934 flags |= TFlags.floating | TFlags.imaginary;
2935 break;
2937 case Tcomplex32:
2938 d = Token.toChars(TOK.complex32);
2939 flags |= TFlags.floating | TFlags.complex;
2940 break;
2942 case Tcomplex64:
2943 d = Token.toChars(TOK.complex64);
2944 flags |= TFlags.floating | TFlags.complex;
2945 break;
2947 case Tcomplex80:
2948 d = Token.toChars(TOK.complex80);
2949 flags |= TFlags.floating | TFlags.complex;
2950 break;
2952 case Tbool:
2953 d = "bool";
2954 flags |= TFlags.integral | TFlags.unsigned;
2955 break;
2957 case Tchar:
2958 d = Token.toChars(TOK.char_);
2959 flags |= TFlags.integral | TFlags.unsigned;
2960 break;
2962 case Twchar:
2963 d = Token.toChars(TOK.wchar_);
2964 flags |= TFlags.integral | TFlags.unsigned;
2965 break;
2967 case Tdchar:
2968 d = Token.toChars(TOK.dchar_);
2969 flags |= TFlags.integral | TFlags.unsigned;
2970 break;
2972 default:
2973 assert(0);
2975 this.dstring = d;
2976 this.flags = flags;
2977 merge(this);
2980 override const(char)* kind() const
2982 return dstring;
2985 override TypeBasic syntaxCopy()
2987 // No semantic analysis done on basic types, no need to copy
2988 return this;
2991 override uinteger_t size(const ref Loc loc)
2993 uint size;
2994 //printf("TypeBasic::size()\n");
2995 switch (ty)
2997 case Tint8:
2998 case Tuns8:
2999 size = 1;
3000 break;
3002 case Tint16:
3003 case Tuns16:
3004 size = 2;
3005 break;
3007 case Tint32:
3008 case Tuns32:
3009 case Tfloat32:
3010 case Timaginary32:
3011 size = 4;
3012 break;
3014 case Tint64:
3015 case Tuns64:
3016 case Tfloat64:
3017 case Timaginary64:
3018 size = 8;
3019 break;
3021 case Tfloat80:
3022 case Timaginary80:
3023 size = target.realsize;
3024 break;
3026 case Tcomplex32:
3027 size = 8;
3028 break;
3030 case Tcomplex64:
3031 case Tint128:
3032 case Tuns128:
3033 size = 16;
3034 break;
3036 case Tcomplex80:
3037 size = target.realsize * 2;
3038 break;
3040 case Tvoid:
3041 //size = Type::size(); // error message
3042 size = 1;
3043 break;
3045 case Tbool:
3046 size = 1;
3047 break;
3049 case Tchar:
3050 size = 1;
3051 break;
3053 case Twchar:
3054 size = 2;
3055 break;
3057 case Tdchar:
3058 size = 4;
3059 break;
3061 default:
3062 assert(0);
3064 //printf("TypeBasic::size() = %d\n", size);
3065 return size;
3068 override uint alignsize()
3070 return target.alignsize(this);
3073 override bool isintegral()
3075 //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
3076 return (flags & TFlags.integral) != 0;
3079 override bool isfloating()
3081 return (flags & TFlags.floating) != 0;
3084 override bool isreal()
3086 return (flags & TFlags.real_) != 0;
3089 override bool isimaginary()
3091 return (flags & TFlags.imaginary) != 0;
3094 override bool iscomplex()
3096 return (flags & TFlags.complex) != 0;
3099 override bool isscalar()
3101 return (flags & (TFlags.integral | TFlags.floating)) != 0;
3104 override bool isunsigned()
3106 return (flags & TFlags.unsigned) != 0;
3109 override MATCH implicitConvTo(Type to)
3111 //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
3112 if (this == to)
3113 return MATCH.exact;
3115 if (ty == to.ty)
3117 if (mod == to.mod)
3118 return MATCH.exact;
3119 else if (MODimplicitConv(mod, to.mod))
3120 return MATCH.constant;
3121 else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching
3122 return MATCH.constant;
3123 else
3124 return MATCH.convert;
3127 if (ty == Tvoid || to.ty == Tvoid)
3128 return MATCH.nomatch;
3129 if (to.ty == Tbool)
3130 return MATCH.nomatch;
3132 TypeBasic tob;
3133 if (to.ty == Tvector && to.deco)
3135 TypeVector tv = cast(TypeVector)to;
3136 tob = tv.elementType();
3138 else if (auto te = to.isTypeEnum())
3140 EnumDeclaration ed = te.sym;
3141 if (ed.isSpecial())
3143 /* Special enums that allow implicit conversions to them
3144 * with a MATCH.convert
3146 tob = to.toBasetype().isTypeBasic();
3148 else
3149 return MATCH.nomatch;
3151 else
3152 tob = to.isTypeBasic();
3153 if (!tob)
3154 return MATCH.nomatch;
3156 if (flags & TFlags.integral)
3158 // Disallow implicit conversion of integers to imaginary or complex
3159 if (tob.flags & (TFlags.imaginary | TFlags.complex))
3160 return MATCH.nomatch;
3162 // If converting from integral to integral
3163 if (tob.flags & TFlags.integral)
3165 const sz = size(Loc.initial);
3166 const tosz = tob.size(Loc.initial);
3168 /* Can't convert to smaller size
3170 if (sz > tosz)
3171 return MATCH.nomatch;
3172 /* Can't change sign if same size
3174 //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
3175 // return MATCH.nomatch;
3178 else if (flags & TFlags.floating)
3180 // Disallow implicit conversion of floating point to integer
3181 if (tob.flags & TFlags.integral)
3182 return MATCH.nomatch;
3184 assert(tob.flags & TFlags.floating || to.ty == Tvector);
3186 // Disallow implicit conversion from complex to non-complex
3187 if (flags & TFlags.complex && !(tob.flags & TFlags.complex))
3188 return MATCH.nomatch;
3190 // Disallow implicit conversion of real or imaginary to complex
3191 if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
3192 return MATCH.nomatch;
3194 // Disallow implicit conversion to-from real and imaginary
3195 if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
3196 return MATCH.nomatch;
3198 return MATCH.convert;
3201 override bool isZeroInit(const ref Loc loc)
3203 switch (ty)
3205 case Tchar:
3206 case Twchar:
3207 case Tdchar:
3208 case Timaginary32:
3209 case Timaginary64:
3210 case Timaginary80:
3211 case Tfloat32:
3212 case Tfloat64:
3213 case Tfloat80:
3214 case Tcomplex32:
3215 case Tcomplex64:
3216 case Tcomplex80:
3217 return false; // no
3218 default:
3219 return true; // yes
3223 // For eliminating dynamic_cast
3224 override TypeBasic isTypeBasic()
3226 return this;
3229 override void accept(Visitor v)
3231 v.visit(this);
3235 /***********************************************************
3236 * The basetype must be one of:
3237 * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
3238 * For AVX:
3239 * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4]
3241 extern (C++) final class TypeVector : Type
3243 Type basetype;
3245 extern (D) this(Type basetype) @safe
3247 super(Tvector);
3248 this.basetype = basetype;
3251 static TypeVector create(Type basetype) @safe
3253 return new TypeVector(basetype);
3256 override const(char)* kind() const
3258 return "vector";
3261 override TypeVector syntaxCopy()
3263 return new TypeVector(basetype.syntaxCopy());
3266 override uinteger_t size(const ref Loc loc)
3268 return basetype.size();
3271 override uint alignsize()
3273 return cast(uint)basetype.size();
3276 override bool isintegral()
3278 //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
3279 return basetype.nextOf().isintegral();
3282 override bool isfloating()
3284 return basetype.nextOf().isfloating();
3287 override bool isscalar()
3289 return basetype.nextOf().isscalar();
3292 override bool isunsigned()
3294 return basetype.nextOf().isunsigned();
3297 override bool isBoolean()
3299 return false;
3302 override MATCH implicitConvTo(Type to)
3304 //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
3305 if (this == to)
3306 return MATCH.exact;
3307 if (to.ty != Tvector)
3308 return MATCH.nomatch;
3310 TypeVector tv = cast(TypeVector)to;
3311 assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
3313 // Can't convert to a vector which has different size.
3314 if (basetype.size() != tv.basetype.size())
3315 return MATCH.nomatch;
3317 // Allow conversion to void[]
3318 if (tv.basetype.nextOf().ty == Tvoid)
3319 return MATCH.convert;
3321 // Otherwise implicitly convertible only if basetypes are.
3322 return basetype.implicitConvTo(tv.basetype);
3325 override Expression defaultInitLiteral(const ref Loc loc)
3327 //printf("TypeVector::defaultInitLiteral()\n");
3328 assert(basetype.ty == Tsarray);
3329 Expression e = basetype.defaultInitLiteral(loc);
3330 auto ve = new VectorExp(loc, e, this);
3331 ve.type = this;
3332 ve.dim = cast(int)(basetype.size(loc) / elementType().size(loc));
3333 return ve;
3336 TypeBasic elementType()
3338 assert(basetype.ty == Tsarray);
3339 TypeSArray t = cast(TypeSArray)basetype;
3340 TypeBasic tb = t.nextOf().isTypeBasic();
3341 assert(tb);
3342 return tb;
3345 override bool isZeroInit(const ref Loc loc)
3347 return basetype.isZeroInit(loc);
3350 override void accept(Visitor v)
3352 v.visit(this);
3356 /***********************************************************
3358 extern (C++) abstract class TypeArray : TypeNext
3360 final extern (D) this(TY ty, Type next) @safe
3362 super(ty, next);
3365 override void accept(Visitor v)
3367 v.visit(this);
3371 /***********************************************************
3372 * Static array, one with a fixed dimension
3374 extern (C++) final class TypeSArray : TypeArray
3376 Expression dim;
3378 extern (D) this(Type t, Expression dim) @safe
3380 super(Tsarray, t);
3381 //printf("TypeSArray(%s)\n", dim.toChars());
3382 this.dim = dim;
3385 extern (D) this(Type t) // for incomplete type
3387 super(Tsarray, t);
3388 //printf("TypeSArray()\n");
3389 this.dim = new IntegerExp(0);
3392 override const(char)* kind() const
3394 return "sarray";
3397 override TypeSArray syntaxCopy()
3399 Type t = next.syntaxCopy();
3400 Expression e = dim.syntaxCopy();
3401 auto result = new TypeSArray(t, e);
3402 result.mod = mod;
3403 return result;
3406 /***
3407 * C11 6.7.6.2-4 incomplete array type
3408 * Returns: true if incomplete type
3410 bool isIncomplete()
3412 return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0;
3415 override uinteger_t size(const ref Loc loc)
3417 //printf("TypeSArray::size()\n");
3418 const n = numberOfElems(loc);
3419 const elemsize = baseElemOf().size(loc);
3420 bool overflow = false;
3421 const sz = mulu(n, elemsize, overflow);
3422 if (overflow || sz >= uint.max)
3424 if (elemsize != SIZE_INVALID && n != uint.max)
3425 error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz);
3426 return SIZE_INVALID;
3428 return sz;
3431 override uint alignsize()
3433 return next.alignsize();
3436 override bool isString()
3438 TY nty = next.toBasetype().ty;
3439 return nty.isSomeChar;
3442 override bool isZeroInit(const ref Loc loc)
3444 return next.isZeroInit(loc);
3447 override structalign_t alignment()
3449 return next.alignment();
3452 override MATCH constConv(Type to)
3454 if (auto tsa = to.isTypeSArray())
3456 if (!dim.equals(tsa.dim))
3457 return MATCH.nomatch;
3459 return TypeNext.constConv(to);
3462 override MATCH implicitConvTo(Type to)
3464 //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
3465 if (auto ta = to.isTypeDArray())
3467 if (!MODimplicitConv(next.mod, ta.next.mod))
3468 return MATCH.nomatch;
3470 /* Allow conversion to void[]
3472 if (ta.next.ty == Tvoid)
3474 return MATCH.convert;
3477 MATCH m = next.constConv(ta.next);
3478 if (m > MATCH.nomatch)
3480 return MATCH.convert;
3482 return MATCH.nomatch;
3484 if (auto tsa = to.isTypeSArray())
3486 if (this == to)
3487 return MATCH.exact;
3489 if (dim.equals(tsa.dim))
3491 MATCH m = next.implicitConvTo(tsa.next);
3493 /* Allow conversion to non-interface base class.
3495 if (m == MATCH.convert &&
3496 next.ty == Tclass)
3498 if (auto toc = tsa.next.isTypeClass)
3500 if (!toc.sym.isInterfaceDeclaration)
3501 return MATCH.convert;
3505 /* Since static arrays are value types, allow
3506 * conversions from const elements to non-const
3507 * ones, just like we allow conversion from const int
3508 * to int.
3510 if (m >= MATCH.constant)
3512 if (mod != to.mod)
3513 m = MATCH.constant;
3514 return m;
3518 return MATCH.nomatch;
3521 override Expression defaultInitLiteral(const ref Loc loc)
3523 static if (LOGDEFAULTINIT)
3525 printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars());
3527 size_t d = cast(size_t)dim.toInteger();
3528 Expression elementinit;
3529 if (next.ty == Tvoid)
3530 elementinit = tuns8.defaultInitLiteral(loc);
3531 else
3532 elementinit = next.defaultInitLiteral(loc);
3533 auto elements = new Expressions(d);
3534 foreach (ref e; *elements)
3535 e = null;
3536 auto ae = new ArrayLiteralExp(Loc.initial, this, elementinit, elements);
3537 return ae;
3540 override bool hasPointers()
3542 /* Don't want to do this, because:
3543 * struct S { T* array[0]; }
3544 * may be a variable length struct.
3546 //if (dim.toInteger() == 0)
3547 // return false;
3549 if (next.ty == Tvoid)
3551 // Arrays of void contain arbitrary data, which may include pointers
3552 return true;
3554 else
3555 return next.hasPointers();
3558 override bool hasSystemFields()
3560 return next.hasSystemFields();
3563 override bool hasVoidInitPointers()
3565 return next.hasVoidInitPointers();
3568 override bool hasInvariant()
3570 return next.hasInvariant();
3573 override bool needsDestruction()
3575 return next.needsDestruction();
3578 override bool needsCopyOrPostblit()
3580 return next.needsCopyOrPostblit();
3583 /*********************************
3586 override bool needsNested()
3588 return next.needsNested();
3591 override void accept(Visitor v)
3593 v.visit(this);
3597 /***********************************************************
3598 * Dynamic array, no dimension
3600 extern (C++) final class TypeDArray : TypeArray
3602 extern (D) this(Type t) @safe
3604 super(Tarray, t);
3605 //printf("TypeDArray(t = %p)\n", t);
3608 override const(char)* kind() const
3610 return "darray";
3613 override TypeDArray syntaxCopy()
3615 Type t = next.syntaxCopy();
3616 if (t == next)
3617 return this;
3619 auto result = new TypeDArray(t);
3620 result.mod = mod;
3621 return result;
3624 override uinteger_t size(const ref Loc loc)
3626 //printf("TypeDArray::size()\n");
3627 return target.ptrsize * 2;
3630 override uint alignsize()
3632 // A DArray consists of two ptr-sized values, so align it on pointer size
3633 // boundary
3634 return target.ptrsize;
3637 override bool isString()
3639 TY nty = next.toBasetype().ty;
3640 return nty.isSomeChar;
3643 override bool isZeroInit(const ref Loc loc)
3645 return true;
3648 override bool isBoolean()
3650 return true;
3653 override MATCH implicitConvTo(Type to)
3655 //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
3656 if (equals(to))
3657 return MATCH.exact;
3659 if (auto ta = to.isTypeDArray())
3661 if (!MODimplicitConv(next.mod, ta.next.mod))
3662 return MATCH.nomatch; // not const-compatible
3664 /* Allow conversion to void[]
3666 if (next.ty != Tvoid && ta.next.ty == Tvoid)
3668 return MATCH.convert;
3671 MATCH m = next.constConv(ta.next);
3672 if (m > MATCH.nomatch)
3674 if (m == MATCH.exact && mod != to.mod)
3675 m = MATCH.constant;
3676 return m;
3679 return Type.implicitConvTo(to);
3682 override bool hasPointers()
3684 return true;
3687 override void accept(Visitor v)
3689 v.visit(this);
3693 /***********************************************************
3695 extern (C++) final class TypeAArray : TypeArray
3697 Type index; // key type
3698 Loc loc;
3700 extern (D) this(Type t, Type index) @safe
3702 super(Taarray, t);
3703 this.index = index;
3706 static TypeAArray create(Type t, Type index) @safe
3708 return new TypeAArray(t, index);
3711 override const(char)* kind() const
3713 return "aarray";
3716 override TypeAArray syntaxCopy()
3718 Type t = next.syntaxCopy();
3719 Type ti = index.syntaxCopy();
3720 if (t == next && ti == index)
3721 return this;
3723 auto result = new TypeAArray(t, ti);
3724 result.mod = mod;
3725 return result;
3728 override uinteger_t size(const ref Loc loc)
3730 return target.ptrsize;
3733 override bool isZeroInit(const ref Loc loc)
3735 return true;
3738 override bool isBoolean()
3740 return true;
3743 override bool hasPointers()
3745 return true;
3748 override MATCH implicitConvTo(Type to)
3750 //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
3751 if (equals(to))
3752 return MATCH.exact;
3754 if (auto ta = to.isTypeAArray())
3756 if (!MODimplicitConv(next.mod, ta.next.mod))
3757 return MATCH.nomatch; // not const-compatible
3759 if (!MODimplicitConv(index.mod, ta.index.mod))
3760 return MATCH.nomatch; // not const-compatible
3762 MATCH m = next.constConv(ta.next);
3763 MATCH mi = index.constConv(ta.index);
3764 if (m > MATCH.nomatch && mi > MATCH.nomatch)
3766 return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch;
3769 return Type.implicitConvTo(to);
3772 override MATCH constConv(Type to)
3774 if (auto taa = to.isTypeAArray())
3776 MATCH mindex = index.constConv(taa.index);
3777 MATCH mkey = next.constConv(taa.next);
3778 // Pick the worst match
3779 return mkey < mindex ? mkey : mindex;
3781 return Type.constConv(to);
3784 override void accept(Visitor v)
3786 v.visit(this);
3790 /***********************************************************
3792 extern (C++) final class TypePointer : TypeNext
3794 extern (D) this(Type t) @safe
3796 super(Tpointer, t);
3799 static TypePointer create(Type t) @safe
3801 return new TypePointer(t);
3804 override const(char)* kind() const
3806 return "pointer";
3809 override TypePointer syntaxCopy()
3811 Type t = next.syntaxCopy();
3812 if (t == next)
3813 return this;
3815 auto result = new TypePointer(t);
3816 result.mod = mod;
3817 return result;
3820 override uinteger_t size(const ref Loc loc)
3822 return target.ptrsize;
3825 override MATCH implicitConvTo(Type to)
3827 //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars());
3828 if (equals(to))
3829 return MATCH.exact;
3831 // Only convert between pointers
3832 auto tp = to.isTypePointer();
3833 if (!tp)
3834 return MATCH.nomatch;
3836 assert(this.next);
3837 assert(tp.next);
3839 // Conversion to void*
3840 if (tp.next.ty == Tvoid)
3842 // Function pointer conversion doesn't check constness?
3843 if (this.next.ty == Tfunction)
3844 return MATCH.convert;
3846 if (!MODimplicitConv(next.mod, tp.next.mod))
3847 return MATCH.nomatch; // not const-compatible
3849 return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
3852 // Conversion between function pointers
3853 if (auto thisTf = this.next.isTypeFunction())
3854 return thisTf.implicitPointerConv(tp.next);
3856 // Default, no implicit conversion between the pointer targets
3857 MATCH m = next.constConv(tp.next);
3859 if (m == MATCH.exact && mod != to.mod)
3860 m = MATCH.constant;
3861 return m;
3864 override MATCH constConv(Type to)
3866 if (next.ty == Tfunction)
3868 if (to.nextOf() && next.equals((cast(TypeNext)to).next))
3869 return Type.constConv(to);
3870 else
3871 return MATCH.nomatch;
3873 return TypeNext.constConv(to);
3876 override bool isscalar()
3878 return true;
3881 override bool isZeroInit(const ref Loc loc)
3883 return true;
3886 override bool hasPointers()
3888 return true;
3891 override void accept(Visitor v)
3893 v.visit(this);
3897 /***********************************************************
3899 extern (C++) final class TypeReference : TypeNext
3901 extern (D) this(Type t) @safe
3903 super(Treference, t);
3904 // BUG: what about references to static arrays?
3907 override const(char)* kind() const
3909 return "reference";
3912 override TypeReference syntaxCopy()
3914 Type t = next.syntaxCopy();
3915 if (t == next)
3916 return this;
3918 auto result = new TypeReference(t);
3919 result.mod = mod;
3920 return result;
3923 override uinteger_t size(const ref Loc loc)
3925 return target.ptrsize;
3928 override bool isZeroInit(const ref Loc loc)
3930 return true;
3933 override void accept(Visitor v)
3935 v.visit(this);
3939 enum RET : int
3941 regs = 1, // returned in registers
3942 stack = 2, // returned on stack
3945 enum TRUSTformat : int
3947 TRUSTformatDefault, // do not emit @system when trust == TRUST.default_
3948 TRUSTformatSystem, // emit @system when trust == TRUST.default_
3951 alias TRUSTformatDefault = TRUSTformat.TRUSTformatDefault;
3952 alias TRUSTformatSystem = TRUSTformat.TRUSTformatSystem;
3954 /***********************************************************
3956 extern (C++) final class TypeFunction : TypeNext
3958 // .next is the return type
3960 ParameterList parameterList; // function parameters
3962 // These flags can be accessed like `bool` properties,
3963 // getters and setters are generated for them
3964 private extern (D) static struct BitFields
3966 bool isnothrow; /// nothrow
3967 bool isnogc; /// is @nogc
3968 bool isproperty; /// can be called without parentheses
3969 bool isref; /// returns a reference
3970 bool isreturn; /// 'this' is returned by ref
3971 bool isScopeQual; /// 'this' is scope
3972 bool isreturninferred; /// 'this' is return from inference
3973 bool isscopeinferred; /// 'this' is scope from inference
3974 bool islive; /// is @live
3975 bool incomplete; /// return type or default arguments removed
3976 bool isInOutParam; /// inout on the parameters
3977 bool isInOutQual; /// inout on the qualifier
3978 bool isctor; /// the function is a constructor
3979 bool isreturnscope; /// `this` is returned by value
3982 import dmd.common.bitfields : generateBitFields;
3983 mixin(generateBitFields!(BitFields, ushort));
3985 LINK linkage; // calling convention
3986 TRUST trust; // level of trust
3987 PURE purity = PURE.impure;
3988 byte inuse;
3989 Expressions* fargs; // function arguments
3991 extern (D) this(ParameterList pl, Type treturn, LINK linkage, StorageClass stc = 0) @safe
3993 super(Tfunction, treturn);
3994 //if (!treturn) *(char*)0=0;
3995 // assert(treturn);
3996 assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.max);
3997 this.parameterList = pl;
3998 this.linkage = linkage;
4000 if (stc & STC.pure_)
4001 this.purity = PURE.fwdref;
4002 if (stc & STC.nothrow_)
4003 this.isnothrow = true;
4004 if (stc & STC.nogc)
4005 this.isnogc = true;
4006 if (stc & STC.property)
4007 this.isproperty = true;
4008 if (stc & STC.live)
4009 this.islive = true;
4011 if (stc & STC.ref_)
4012 this.isref = true;
4013 if (stc & STC.return_)
4014 this.isreturn = true;
4015 if (stc & STC.returnScope)
4016 this.isreturnscope = true;
4017 if (stc & STC.returninferred)
4018 this.isreturninferred = true;
4019 if (stc & STC.scope_)
4020 this.isScopeQual = true;
4021 if (stc & STC.scopeinferred)
4022 this.isscopeinferred = true;
4024 this.trust = TRUST.default_;
4025 if (stc & STC.safe)
4026 this.trust = TRUST.safe;
4027 else if (stc & STC.system)
4028 this.trust = TRUST.system;
4029 else if (stc & STC.trusted)
4030 this.trust = TRUST.trusted;
4033 static TypeFunction create(Parameters* parameters, Type treturn, ubyte varargs, LINK linkage, StorageClass stc = 0) @safe
4035 return new TypeFunction(ParameterList(parameters, cast(VarArg)varargs), treturn, linkage, stc);
4038 override const(char)* kind() const
4040 return "function";
4043 override TypeFunction syntaxCopy()
4045 Type treturn = next ? next.syntaxCopy() : null;
4046 auto t = new TypeFunction(parameterList.syntaxCopy(), treturn, linkage);
4047 t.mod = mod;
4048 t.isnothrow = isnothrow;
4049 t.isnogc = isnogc;
4050 t.islive = islive;
4051 t.purity = purity;
4052 t.isproperty = isproperty;
4053 t.isref = isref;
4054 t.isreturn = isreturn;
4055 t.isreturnscope = isreturnscope;
4056 t.isScopeQual = isScopeQual;
4057 t.isreturninferred = isreturninferred;
4058 t.isscopeinferred = isscopeinferred;
4059 t.isInOutParam = isInOutParam;
4060 t.isInOutQual = isInOutQual;
4061 t.trust = trust;
4062 t.fargs = fargs;
4063 t.isctor = isctor;
4064 return t;
4067 /********************************************
4068 * Set 'purity' field of 'this'.
4069 * Do this lazily, as the parameter types might be forward referenced.
4071 void purityLevel()
4073 TypeFunction tf = this;
4074 if (tf.purity != PURE.fwdref)
4075 return;
4077 purity = PURE.const_; // assume strong until something weakens it
4079 /* Evaluate what kind of purity based on the modifiers for the parameters
4081 foreach (i, fparam; tf.parameterList)
4083 Type t = fparam.type;
4084 if (!t)
4085 continue;
4087 if (fparam.storageClass & (STC.lazy_ | STC.out_))
4089 purity = PURE.weak;
4090 break;
4092 const pref = (fparam.storageClass & STC.ref_) != 0;
4093 if (mutabilityOfType(pref, t) == 0)
4094 purity = PURE.weak;
4097 tf.purity = purity;
4100 /********************************************
4101 * Return true if there are lazy parameters.
4103 bool hasLazyParameters()
4105 foreach (i, fparam; parameterList)
4107 if (fparam.isLazy())
4108 return true;
4110 return false;
4113 /*******************************
4114 * Check for `extern (D) U func(T t, ...)` variadic function type,
4115 * which has `_arguments[]` added as the first argument.
4116 * Returns:
4117 * true if D-style variadic
4119 bool isDstyleVariadic() const pure nothrow
4121 return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
4124 /************************************
4125 * Take the specified storage class for p,
4126 * and use the function signature to infer whether
4127 * STC.scope_ and STC.return_ should be OR'd in.
4128 * (This will not affect the name mangling.)
4129 * Params:
4130 * tthis = type of `this` parameter, null if none
4131 * p = parameter to this function
4132 * outerVars = context variables p could escape into, if any
4133 * indirect = is this for an indirect or virtual function call?
4134 * Returns:
4135 * storage class with STC.scope_ or STC.return_ OR'd in
4137 StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null,
4138 bool indirect = false)
4140 //printf("parameterStorageClass(p: %s)\n", p.toChars());
4141 auto stc = p.storageClass;
4143 // When the preview switch is enable, `in` parameters are `scope`
4144 if (stc & STC.in_ && global.params.previewIn)
4145 return stc | STC.scope_;
4147 if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure)
4148 return stc;
4150 /* If haven't inferred the return type yet, can't infer storage classes
4152 if (!nextOf() || !isnothrow())
4153 return stc;
4155 purityLevel();
4157 static bool mayHavePointers(Type t)
4159 if (auto ts = t.isTypeStruct())
4161 auto sym = ts.sym;
4162 if (sym.members && !sym.determineFields() && sym.type != Type.terror)
4163 // struct is forward referenced, so "may have" pointers
4164 return true;
4166 return t.hasPointers();
4169 // See if p can escape via any of the other parameters
4170 if (purity == PURE.weak)
4173 * Indirect calls may escape p through a nested context
4174 * See:
4175 * https://issues.dlang.org/show_bug.cgi?id=24212
4176 * https://issues.dlang.org/show_bug.cgi?id=24213
4178 if (indirect)
4179 return stc;
4181 // Check escaping through parameters
4182 foreach (i, fparam; parameterList)
4184 Type t = fparam.type;
4185 if (!t)
4186 continue;
4187 t = t.baseElemOf(); // punch thru static arrays
4188 if (t.isMutable() && t.hasPointers())
4190 if (fparam.isReference() && fparam != p)
4191 return stc;
4193 if (t.ty == Tdelegate)
4194 return stc; // could escape thru delegate
4196 if (t.ty == Tclass)
4197 return stc;
4199 /* if t is a pointer to mutable pointer
4201 if (auto tn = t.nextOf())
4203 if (tn.isMutable() && mayHavePointers(tn))
4204 return stc; // escape through pointers
4209 // Check escaping through `this`
4210 if (tthis && tthis.isMutable())
4212 foreach (VarDeclaration v; isAggregate(tthis).fields)
4214 if (v.hasPointers())
4215 return stc;
4219 // Check escaping through nested context
4220 if (outerVars && this.isMutable())
4222 foreach (VarDeclaration v; *outerVars)
4224 if (v.hasPointers())
4225 return stc;
4230 // Check escaping through return value
4231 Type tret = nextOf().toBasetype();
4232 if (isref || tret.hasPointers())
4234 return stc | STC.scope_ | STC.return_ | STC.returnScope;
4236 else
4237 return stc | STC.scope_;
4240 override Type addStorageClass(StorageClass stc)
4242 //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
4243 TypeFunction t = Type.addStorageClass(stc).toTypeFunction();
4244 if ((stc & STC.pure_ && !t.purity) ||
4245 (stc & STC.nothrow_ && !t.isnothrow) ||
4246 (stc & STC.nogc && !t.isnogc) ||
4247 (stc & STC.scope_ && !t.isScopeQual) ||
4248 (stc & STC.safe && t.trust < TRUST.trusted))
4250 // Klunky to change these
4251 auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0);
4252 tf.mod = t.mod;
4253 tf.fargs = fargs;
4254 tf.purity = t.purity;
4255 tf.isnothrow = t.isnothrow;
4256 tf.isnogc = t.isnogc;
4257 tf.isproperty = t.isproperty;
4258 tf.isref = t.isref;
4259 tf.isreturn = t.isreturn;
4260 tf.isreturnscope = t.isreturnscope;
4261 tf.isScopeQual = t.isScopeQual;
4262 tf.isreturninferred = t.isreturninferred;
4263 tf.isscopeinferred = t.isscopeinferred;
4264 tf.trust = t.trust;
4265 tf.isInOutParam = t.isInOutParam;
4266 tf.isInOutQual = t.isInOutQual;
4267 tf.isctor = t.isctor;
4269 if (stc & STC.pure_)
4270 tf.purity = PURE.fwdref;
4271 if (stc & STC.nothrow_)
4272 tf.isnothrow = true;
4273 if (stc & STC.nogc)
4274 tf.isnogc = true;
4275 if (stc & STC.safe)
4276 tf.trust = TRUST.safe;
4277 if (stc & STC.scope_)
4279 tf.isScopeQual = true;
4280 if (stc & STC.scopeinferred)
4281 tf.isscopeinferred = true;
4284 tf.deco = tf.merge().deco;
4285 t = tf;
4287 return t;
4290 override Type substWildTo(uint)
4292 if (!iswild && !(mod & MODFlags.wild))
4293 return this;
4295 // Substitude inout qualifier of function type to mutable or immutable
4296 // would break type system. Instead substitude inout to the most weak
4297 // qualifer - const.
4298 uint m = MODFlags.const_;
4300 assert(next);
4301 Type tret = next.substWildTo(m);
4302 Parameters* params = parameterList.parameters;
4303 if (mod & MODFlags.wild)
4304 params = parameterList.parameters.copy();
4305 for (size_t i = 0; i < params.length; i++)
4307 Parameter p = (*params)[i];
4308 Type t = p.type.substWildTo(m);
4309 if (t == p.type)
4310 continue;
4311 if (params == parameterList.parameters)
4312 params = parameterList.parameters.copy();
4313 (*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null);
4315 if (next == tret && params == parameterList.parameters)
4316 return this;
4318 // Similar to TypeFunction::syntaxCopy;
4319 auto t = new TypeFunction(ParameterList(params, parameterList.varargs), tret, linkage);
4320 t.mod = ((mod & MODFlags.wild) ? (mod & ~MODFlags.wild) | MODFlags.const_ : mod);
4321 t.isnothrow = isnothrow;
4322 t.isnogc = isnogc;
4323 t.purity = purity;
4324 t.isproperty = isproperty;
4325 t.isref = isref;
4326 t.isreturn = isreturn;
4327 t.isreturnscope = isreturnscope;
4328 t.isScopeQual = isScopeQual;
4329 t.isreturninferred = isreturninferred;
4330 t.isscopeinferred = isscopeinferred;
4331 t.isInOutParam = false;
4332 t.isInOutQual = false;
4333 t.trust = trust;
4334 t.fargs = fargs;
4335 t.isctor = isctor;
4336 return t.merge();
4339 extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args)
4341 if (global.gag && !global.params.v.showGaggedErrors)
4342 return null;
4343 OutBuffer buf;
4344 buf.printf(format, args);
4345 return buf.extractChars();
4348 /********************************
4349 * Convert an `argumentList`, which may contain named arguments, into
4350 * a list of arguments in the order of the parameter list.
4352 * Params:
4353 * argumentList = array of function arguments
4354 * pMessage = address to store error message, or `null`
4355 * Returns: re-ordered argument list, or `null` on error
4357 extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, const(char)** pMessage)
4359 Expression[] args = argumentList.arguments ? (*argumentList.arguments)[] : null;
4360 Identifier[] names = argumentList.names ? (*argumentList.names)[] : null;
4361 auto newArgs = new Expressions(parameterList.length);
4362 newArgs.zero();
4363 size_t ci = 0;
4364 bool hasNamedArgs = false;
4365 foreach (i, arg; args)
4367 if (!arg)
4369 ci++;
4370 continue;
4372 auto name = i < names.length ? names[i] : null;
4373 if (name)
4375 hasNamedArgs = true;
4376 const pi = findParameterIndex(name);
4377 if (pi == -1)
4379 if (pMessage)
4380 *pMessage = getMatchError("no parameter named `%s`", name.toChars());
4381 return null;
4383 ci = pi;
4385 if (ci >= newArgs.length)
4387 if (!parameterList.varargs)
4389 // Without named args, let the caller diagnose argument overflow
4390 if (hasNamedArgs && pMessage)
4391 *pMessage = getMatchError("argument `%s` goes past end of parameter list", arg.toChars());
4392 return null;
4394 while (ci >= newArgs.length)
4395 newArgs.push(null);
4398 if ((*newArgs)[ci])
4400 if (pMessage)
4401 *pMessage = getMatchError("parameter `%s` assigned twice", parameterList[ci].toChars());
4402 return null;
4404 (*newArgs)[ci++] = arg;
4406 foreach (i, arg; (*newArgs)[])
4408 if (arg || parameterList[i].defaultArg)
4409 continue;
4411 if (parameterList.varargs != VarArg.none && i + 1 == newArgs.length)
4412 continue;
4414 if (pMessage)
4415 *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
4416 i + 1, parameterToChars(parameterList[i], this, false));
4417 return null;
4419 // strip trailing nulls from default arguments
4420 size_t e = newArgs.length;
4421 while (e > 0 && (*newArgs)[e - 1] is null)
4423 --e;
4425 newArgs.setDim(e);
4426 return newArgs;
4430 + Checks whether this function type is convertible to ` to`
4431 + when used in a function pointer / delegate.
4433 + Params:
4434 + to = target type
4436 + Returns:
4437 + MATCH.nomatch: `to` is not a covaraint function
4438 + MATCH.convert: `to` is a covaraint function
4439 + MATCH.exact: `to` is identical to this function
4441 private MATCH implicitPointerConv(Type to)
4443 assert(to);
4445 if (this.equals(to))
4446 return MATCH.constant;
4448 if (this.covariant(to) == Covariant.yes)
4450 Type tret = this.nextOf();
4451 Type toret = to.nextOf();
4452 if (tret.ty == Tclass && toret.ty == Tclass)
4454 /* https://issues.dlang.org/show_bug.cgi?id=10219
4455 * Check covariant interface return with offset tweaking.
4456 * interface I {}
4457 * class C : Object, I {}
4458 * I function() dg = function C() {} // should be error
4460 int offset = 0;
4461 if (toret.isBaseOf(tret, &offset) && offset != 0)
4462 return MATCH.nomatch;
4464 return MATCH.convert;
4467 return MATCH.nomatch;
4470 /** Extends TypeNext.constConv by also checking for matching attributes **/
4471 override MATCH constConv(Type to)
4473 // Attributes need to match exactly, otherwise it's an implicit conversion
4474 if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to))
4475 return MATCH.nomatch;
4477 return super.constConv(to);
4480 extern (D) bool checkRetType(const ref Loc loc)
4482 Type tb = next.toBasetype();
4483 if (tb.ty == Tfunction)
4485 error(loc, "functions cannot return a function");
4486 next = Type.terror;
4488 if (tb.ty == Ttuple)
4490 error(loc, "functions cannot return a sequence (use `std.typecons.Tuple`)");
4491 next = Type.terror;
4493 if (!isref && (tb.ty == Tstruct || tb.ty == Tsarray))
4495 if (auto ts = tb.baseElemOf().isTypeStruct())
4497 if (!ts.sym.members)
4499 error(loc, "functions cannot return opaque type `%s` by value", tb.toChars());
4500 next = Type.terror;
4504 if (tb.ty == Terror)
4505 return true;
4506 return false;
4510 /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
4511 bool iswild() const pure nothrow @safe @nogc
4513 return isInOutParam || isInOutQual;
4516 /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
4517 extern (D) bool attributesEqual(const scope TypeFunction other, bool trustSystemEqualsDefault = true) const pure nothrow @safe @nogc
4519 // @@@DEPRECATED_2.112@@@
4520 // See semantic2.d Semantic2Visitor.visit(FuncDeclaration):
4521 // Two overloads that are identical except for one having an explicit `@system`
4522 // attribute is currently in deprecation, and will become an error in 2.104 for
4523 // `extern(C)`, and 2.112 for `extern(D)` code respectively. Once the deprecation
4524 // period has passed, the trustSystemEqualsDefault=true behaviour should be made
4525 // the default, then we can remove the `cannot overload extern(...) function`
4526 // errors as they will become dead code as a result.
4527 return (this.trust == other.trust ||
4528 (trustSystemEqualsDefault && this.trust <= TRUST.system && other.trust <= TRUST.system)) &&
4529 this.purity == other.purity &&
4530 this.isnothrow == other.isnothrow &&
4531 this.isnogc == other.isnogc &&
4532 this.islive == other.islive;
4535 override void accept(Visitor v)
4537 v.visit(this);
4541 * Look for the index of parameter `ident` in the parameter list
4543 * Params:
4544 * ident = identifier of parameter to search for
4545 * Returns: index of parameter with name `ident` or -1 if not found
4547 private extern(D) ptrdiff_t findParameterIndex(Identifier ident)
4549 foreach (i, p; this.parameterList)
4551 if (p.ident == ident)
4552 return i;
4554 return -1;
4558 /***********************************************************
4560 extern (C++) final class TypeDelegate : TypeNext
4562 // .next is a TypeFunction
4564 extern (D) this(TypeFunction t) @safe
4566 super(Tfunction, t);
4567 ty = Tdelegate;
4570 static TypeDelegate create(TypeFunction t) @safe
4572 return new TypeDelegate(t);
4575 override const(char)* kind() const
4577 return "delegate";
4580 override TypeDelegate syntaxCopy()
4582 auto tf = next.syntaxCopy().isTypeFunction();
4583 if (tf == next)
4584 return this;
4586 auto result = new TypeDelegate(tf);
4587 result.mod = mod;
4588 return result;
4591 override Type addStorageClass(StorageClass stc)
4593 TypeDelegate t = cast(TypeDelegate)Type.addStorageClass(stc);
4594 return t;
4597 override uinteger_t size(const ref Loc loc)
4599 return target.ptrsize * 2;
4602 override uint alignsize()
4604 return target.ptrsize;
4607 override MATCH implicitConvTo(Type to)
4609 //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
4610 //printf("from: %s\n", toChars());
4611 //printf("to : %s\n", to.toChars());
4612 if (this.equals(to))
4613 return MATCH.exact;
4615 if (auto toDg = to.isTypeDelegate())
4617 MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next);
4619 // Retain the old behaviour for this refactoring
4620 // Should probably be changed to constant to match function pointers
4621 if (m > MATCH.convert)
4622 m = MATCH.convert;
4624 return m;
4627 return MATCH.nomatch;
4630 override bool isZeroInit(const ref Loc loc)
4632 return true;
4635 override bool isBoolean()
4637 return true;
4640 override bool hasPointers()
4642 return true;
4645 override void accept(Visitor v)
4647 v.visit(this);
4652 * This is a shell containing a TraitsExp that can be
4653 * either resolved to a type or to a symbol.
4655 * The point is to allow AliasDeclarationY to use `__traits()`, see https://issues.dlang.org/show_bug.cgi?id=7804.
4657 extern (C++) final class TypeTraits : Type
4659 Loc loc;
4660 /// The expression to resolve as type or symbol.
4661 TraitsExp exp;
4662 /// Cached type/symbol after semantic analysis.
4663 RootObject obj;
4665 final extern (D) this(const ref Loc loc, TraitsExp exp) @safe
4667 super(Ttraits);
4668 this.loc = loc;
4669 this.exp = exp;
4672 override const(char)* kind() const
4674 return "traits";
4677 override TypeTraits syntaxCopy()
4679 TraitsExp te = exp.syntaxCopy();
4680 TypeTraits tt = new TypeTraits(loc, te);
4681 tt.mod = mod;
4682 return tt;
4685 override Dsymbol toDsymbol(Scope* sc)
4687 Type t;
4688 Expression e;
4689 Dsymbol s;
4690 resolve(this, loc, sc, e, t, s);
4691 if (t && t.ty != Terror)
4692 s = t.toDsymbol(sc);
4693 else if (e)
4694 s = getDsymbol(e);
4696 return s;
4699 override void accept(Visitor v)
4701 v.visit(this);
4704 override uinteger_t size(const ref Loc loc)
4706 return SIZE_INVALID;
4710 /******
4711 * Implements mixin types.
4713 * Semantic analysis will convert it to a real type.
4715 extern (C++) final class TypeMixin : Type
4717 Loc loc;
4718 Expressions* exps;
4719 RootObject obj; // cached result of semantic analysis.
4721 extern (D) this(const ref Loc loc, Expressions* exps) @safe
4723 super(Tmixin);
4724 this.loc = loc;
4725 this.exps = exps;
4728 override const(char)* kind() const
4730 return "mixin";
4733 override TypeMixin syntaxCopy()
4735 return new TypeMixin(loc, Expression.arraySyntaxCopy(exps));
4738 override Dsymbol toDsymbol(Scope* sc)
4740 Type t;
4741 Expression e;
4742 Dsymbol s;
4743 resolve(this, loc, sc, e, t, s);
4744 if (t)
4745 s = t.toDsymbol(sc);
4746 else if (e)
4747 s = getDsymbol(e);
4749 return s;
4752 override void accept(Visitor v)
4754 v.visit(this);
4758 /***********************************************************
4760 extern (C++) abstract class TypeQualified : Type
4762 Loc loc;
4764 // array of Identifier and TypeInstance,
4765 // representing ident.ident!tiargs.ident. ... etc.
4766 Objects idents;
4768 final extern (D) this(TY ty, Loc loc)
4770 super(ty);
4771 this.loc = loc;
4774 // abstract override so that using `TypeQualified.syntaxCopy` gets
4775 // us a `TypeQualified`
4776 abstract override TypeQualified syntaxCopy();
4778 extern (D) final void syntaxCopyHelper(TypeQualified t)
4780 //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t.toChars(), toChars());
4781 idents.setDim(t.idents.length);
4782 for (size_t i = 0; i < idents.length; i++)
4784 RootObject id = t.idents[i];
4785 with (DYNCAST) final switch (id.dyncast())
4787 case object:
4788 break;
4789 case expression:
4790 Expression e = cast(Expression)id;
4791 e = e.syntaxCopy();
4792 id = e;
4793 break;
4794 case dsymbol:
4795 TemplateInstance ti = cast(TemplateInstance)id;
4796 ti = ti.syntaxCopy(null);
4797 id = ti;
4798 break;
4799 case type:
4800 Type tx = cast(Type)id;
4801 tx = tx.syntaxCopy();
4802 id = tx;
4803 break;
4804 case identifier:
4805 case tuple:
4806 case parameter:
4807 case statement:
4808 case condition:
4809 case templateparameter:
4810 case initializer:
4812 idents[i] = id;
4816 extern (D) final void addIdent(Identifier ident)
4818 idents.push(ident);
4821 extern (D) final void addInst(TemplateInstance inst)
4823 idents.push(inst);
4826 extern (D) final void addIndex(RootObject e)
4828 idents.push(e);
4831 override uinteger_t size(const ref Loc loc)
4833 error(this.loc, "size of type `%s` is not known", toChars());
4834 return SIZE_INVALID;
4837 override void accept(Visitor v)
4839 v.visit(this);
4843 /***********************************************************
4845 extern (C++) final class TypeIdentifier : TypeQualified
4847 Identifier ident;
4849 // The symbol representing this identifier, before alias resolution
4850 Dsymbol originalSymbol;
4852 extern (D) this(const ref Loc loc, Identifier ident)
4854 super(Tident, loc);
4855 this.ident = ident;
4858 static TypeIdentifier create(const ref Loc loc, Identifier ident)
4860 return new TypeIdentifier(loc, ident);
4863 override const(char)* kind() const
4865 return "identifier";
4868 override TypeIdentifier syntaxCopy()
4870 auto t = new TypeIdentifier(loc, ident);
4871 t.syntaxCopyHelper(this);
4872 t.mod = mod;
4873 return t;
4876 /*****************************************
4877 * See if type resolves to a symbol, if so,
4878 * return that symbol.
4880 override Dsymbol toDsymbol(Scope* sc)
4882 //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
4883 if (!sc)
4884 return null;
4886 Type t;
4887 Expression e;
4888 Dsymbol s;
4889 resolve(this, loc, sc, e, t, s);
4890 if (t && t.ty != Tident)
4891 s = t.toDsymbol(sc);
4892 if (e)
4893 s = getDsymbol(e);
4895 return s;
4898 override void accept(Visitor v)
4900 v.visit(this);
4904 /***********************************************************
4905 * Similar to TypeIdentifier, but with a TemplateInstance as the root
4907 extern (C++) final class TypeInstance : TypeQualified
4909 TemplateInstance tempinst;
4911 extern (D) this(const ref Loc loc, TemplateInstance tempinst)
4913 super(Tinstance, loc);
4914 this.tempinst = tempinst;
4917 override const(char)* kind() const
4919 return "instance";
4922 override TypeInstance syntaxCopy()
4924 //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.length);
4925 auto t = new TypeInstance(loc, tempinst.syntaxCopy(null));
4926 t.syntaxCopyHelper(this);
4927 t.mod = mod;
4928 return t;
4931 override Dsymbol toDsymbol(Scope* sc)
4933 Type t;
4934 Expression e;
4935 Dsymbol s;
4936 //printf("TypeInstance::semantic(%s)\n", toChars());
4937 resolve(this, loc, sc, e, t, s);
4938 if (t && t.ty != Tinstance)
4939 s = t.toDsymbol(sc);
4940 return s;
4943 override void accept(Visitor v)
4945 v.visit(this);
4949 /***********************************************************
4951 extern (C++) final class TypeTypeof : TypeQualified
4953 Expression exp;
4954 int inuse;
4956 extern (D) this(const ref Loc loc, Expression exp)
4958 super(Ttypeof, loc);
4959 this.exp = exp;
4962 override const(char)* kind() const
4964 return "typeof";
4967 override TypeTypeof syntaxCopy()
4969 //printf("TypeTypeof::syntaxCopy() %s\n", toChars());
4970 auto t = new TypeTypeof(loc, exp.syntaxCopy());
4971 t.syntaxCopyHelper(this);
4972 t.mod = mod;
4973 return t;
4976 override Dsymbol toDsymbol(Scope* sc)
4978 //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
4979 Expression e;
4980 Type t;
4981 Dsymbol s;
4982 resolve(this, loc, sc, e, t, s);
4983 return s;
4986 override uinteger_t size(const ref Loc loc)
4988 if (exp.type)
4989 return exp.type.size(loc);
4990 else
4991 return TypeQualified.size(loc);
4994 override void accept(Visitor v)
4996 v.visit(this);
5000 /***********************************************************
5002 extern (C++) final class TypeReturn : TypeQualified
5004 extern (D) this(const ref Loc loc)
5006 super(Treturn, loc);
5009 override const(char)* kind() const
5011 return "return";
5014 override TypeReturn syntaxCopy()
5016 auto t = new TypeReturn(loc);
5017 t.syntaxCopyHelper(this);
5018 t.mod = mod;
5019 return t;
5022 override Dsymbol toDsymbol(Scope* sc)
5024 Expression e;
5025 Type t;
5026 Dsymbol s;
5027 resolve(this, loc, sc, e, t, s);
5028 return s;
5031 override void accept(Visitor v)
5033 v.visit(this);
5037 /***********************************************************
5039 extern (C++) final class TypeStruct : Type
5041 StructDeclaration sym;
5042 AliasThisRec att = AliasThisRec.fwdref;
5043 bool inuse = false; // struct currently subject of recursive method call
5045 extern (D) this(StructDeclaration sym) @safe
5047 super(Tstruct);
5048 this.sym = sym;
5051 static TypeStruct create(StructDeclaration sym) @safe
5053 return new TypeStruct(sym);
5056 override const(char)* kind() const
5058 return "struct";
5061 override uinteger_t size(const ref Loc loc)
5063 return sym.size(loc);
5066 override uint alignsize()
5068 sym.size(Loc.initial); // give error for forward references
5069 return sym.alignsize;
5072 override TypeStruct syntaxCopy()
5074 return this;
5077 override Dsymbol toDsymbol(Scope* sc)
5079 return sym;
5082 override structalign_t alignment()
5084 if (sym.alignment.isUnknown())
5085 sym.size(sym.loc);
5086 return sym.alignment;
5089 /***************************************
5090 * Use when we prefer the default initializer to be a literal,
5091 * rather than a global immutable variable.
5093 override Expression defaultInitLiteral(const ref Loc loc)
5095 static if (LOGDEFAULTINIT)
5097 printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars());
5099 sym.size(loc);
5100 if (sym.sizeok != Sizeok.done)
5101 return ErrorExp.get();
5103 auto structelems = new Expressions(sym.nonHiddenFields());
5104 uint offset = 0;
5105 foreach (j; 0 .. structelems.length)
5107 VarDeclaration vd = sym.fields[j];
5108 Expression e;
5109 if (vd.inuse)
5111 error(loc, "circular reference to `%s`", vd.toPrettyChars());
5112 return ErrorExp.get();
5114 if (vd.offset < offset || vd.type.size() == 0)
5115 e = null;
5116 else if (vd._init)
5118 if (vd._init.isVoidInitializer())
5119 e = null;
5120 else
5121 e = vd.getConstInitializer(false);
5123 else
5124 e = vd.type.defaultInitLiteral(loc);
5125 if (e && e.op == EXP.error)
5126 return e;
5127 if (e)
5128 offset = vd.offset + cast(uint)vd.type.size();
5129 (*structelems)[j] = e;
5131 auto structinit = new StructLiteralExp(loc, sym, structelems);
5133 /* Copy from the initializer symbol for larger symbols,
5134 * otherwise the literals expressed as code get excessively large.
5136 if (size(loc) > target.ptrsize * 4 && !needsNested())
5137 structinit.useStaticInit = true;
5139 structinit.type = this;
5140 return structinit;
5143 override bool isZeroInit(const ref Loc loc)
5145 // Determine zeroInit here, as this can be called before semantic2
5146 sym.determineSize(sym.loc);
5147 return sym.zeroInit;
5150 override bool isAssignable()
5152 bool assignable = true;
5153 uint offset = ~0; // dead-store initialize to prevent spurious warning
5155 sym.determineSize(sym.loc);
5157 /* If any of the fields are const or immutable,
5158 * then one cannot assign this struct.
5160 for (size_t i = 0; i < sym.fields.length; i++)
5162 VarDeclaration v = sym.fields[i];
5163 //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());
5164 if (i == 0)
5167 else if (v.offset == offset)
5169 /* If any fields of anonymous union are assignable,
5170 * then regard union as assignable.
5171 * This is to support unsafe things like Rebindable templates.
5173 if (assignable)
5174 continue;
5176 else
5178 if (!assignable)
5179 return false;
5181 assignable = v.type.isMutable() && v.type.isAssignable();
5182 offset = v.offset;
5183 //printf(" -> assignable = %d\n", assignable);
5186 return assignable;
5189 override bool isBoolean()
5191 return false;
5194 override bool needsDestruction()
5196 return sym.dtor !is null;
5199 override bool needsCopyOrPostblit()
5201 return sym.hasCopyCtor || sym.postblit;
5204 override bool needsNested()
5206 if (inuse) return false; // circular type, error instead of crashing
5208 inuse = true;
5209 scope(exit) inuse = false;
5211 if (sym.isNested())
5212 return true;
5214 for (size_t i = 0; i < sym.fields.length; i++)
5216 VarDeclaration v = sym.fields[i];
5217 if (!v.isDataseg() && v.type.needsNested())
5218 return true;
5220 return false;
5223 override bool hasPointers()
5225 if (sym.members && !sym.determineFields() && sym.type != Type.terror)
5226 error(sym.loc, "no size because of forward references");
5228 sym.determineTypeProperties();
5229 return sym.hasPointerField;
5232 override bool hasVoidInitPointers()
5234 sym.size(Loc.initial); // give error for forward references
5235 sym.determineTypeProperties();
5236 return sym.hasVoidInitPointers;
5239 override bool hasSystemFields()
5241 sym.size(Loc.initial); // give error for forward references
5242 sym.determineTypeProperties();
5243 return sym.hasSystemFields;
5246 override bool hasInvariant()
5248 sym.size(Loc.initial); // give error for forward references
5249 sym.determineTypeProperties();
5250 return sym.hasInvariant() || sym.hasFieldWithInvariant;
5253 extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
5255 MATCH m;
5257 if (ty == to.ty && sym == (cast(TypeStruct)to).sym)
5259 m = MATCH.exact; // exact match
5260 if (mod != to.mod)
5262 m = MATCH.constant;
5263 if (MODimplicitConv(mod, to.mod))
5266 else
5268 /* Check all the fields. If they can all be converted,
5269 * allow the conversion.
5271 uint offset = ~0; // dead-store to prevent spurious warning
5272 for (size_t i = 0; i < sym.fields.length; i++)
5274 VarDeclaration v = sym.fields[i];
5275 if (i == 0)
5278 else if (v.offset == offset)
5280 if (m > MATCH.nomatch)
5281 continue;
5283 else
5285 if (m == MATCH.nomatch)
5286 return m;
5289 // 'from' type
5290 Type tvf = v.type.addMod(mod);
5292 // 'to' type
5293 Type tv = v.type.addMod(to.mod);
5295 // field match
5296 MATCH mf = tvf.implicitConvTo(tv);
5297 //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf);
5299 if (mf == MATCH.nomatch)
5300 return mf;
5301 if (mf < m) // if field match is worse
5302 m = mf;
5303 offset = v.offset;
5308 return m;
5311 extern (D) MATCH implicitConvToThroughAliasThis(Type to)
5313 MATCH m;
5314 if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing))
5316 if (auto ato = aliasthisOf())
5318 att = cast(AliasThisRec)(att | AliasThisRec.tracing);
5319 m = ato.implicitConvTo(to);
5320 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
5322 else
5323 m = MATCH.nomatch; // no match
5325 return m;
5328 override MATCH implicitConvTo(Type to)
5330 //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars());
5331 MATCH m = implicitConvToWithoutAliasThis(to);
5332 return m ? m : implicitConvToThroughAliasThis(to);
5335 override MATCH constConv(Type to)
5337 if (equals(to))
5338 return MATCH.exact;
5339 if (ty == to.ty && sym == (cast(TypeStruct)to).sym && MODimplicitConv(mod, to.mod))
5340 return MATCH.constant;
5341 return MATCH.nomatch;
5344 override MOD deduceWild(Type t, bool isRef)
5346 if (ty == t.ty && sym == (cast(TypeStruct)t).sym)
5347 return Type.deduceWild(t, isRef);
5349 ubyte wm = 0;
5351 if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing))
5353 if (auto ato = aliasthisOf())
5355 att = cast(AliasThisRec)(att | AliasThisRec.tracing);
5356 wm = ato.deduceWild(t, isRef);
5357 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
5361 return wm;
5364 override inout(Type) toHeadMutable() inout
5366 return this;
5369 override void accept(Visitor v)
5371 v.visit(this);
5375 /***********************************************************
5377 extern (C++) final class TypeEnum : Type
5379 EnumDeclaration sym;
5381 extern (D) this(EnumDeclaration sym) @safe
5383 super(Tenum);
5384 this.sym = sym;
5387 override const(char)* kind() const
5389 return "enum";
5392 override TypeEnum syntaxCopy()
5394 return this;
5397 override uinteger_t size(const ref Loc loc)
5399 return sym.getMemtype(loc).size(loc);
5402 Type memType(const ref Loc loc = Loc.initial)
5404 return sym.getMemtype(loc);
5407 override uint alignsize()
5409 Type t = memType();
5410 if (t.ty == Terror)
5411 return 4;
5412 return t.alignsize();
5415 override Dsymbol toDsymbol(Scope* sc)
5417 return sym;
5420 override bool isintegral()
5422 return memType().isintegral();
5425 override bool isfloating()
5427 return memType().isfloating();
5430 override bool isreal()
5432 return memType().isreal();
5435 override bool isimaginary()
5437 return memType().isimaginary();
5440 override bool iscomplex()
5442 return memType().iscomplex();
5445 override bool isscalar()
5447 return memType().isscalar();
5450 override bool isunsigned()
5452 return memType().isunsigned();
5455 override bool isBoolean()
5457 return memType().isBoolean();
5460 override bool isString()
5462 return memType().isString();
5465 override bool isAssignable()
5467 return memType().isAssignable();
5470 override bool needsDestruction()
5472 return memType().needsDestruction();
5475 override bool needsCopyOrPostblit()
5477 return memType().needsCopyOrPostblit();
5480 override bool needsNested()
5482 return memType().needsNested();
5485 override MATCH implicitConvTo(Type to)
5487 MATCH m;
5488 //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars());
5489 if (ty == to.ty && sym == (cast(TypeEnum)to).sym)
5490 m = (mod == to.mod) ? MATCH.exact : MATCH.constant;
5491 else if (sym.getMemtype(Loc.initial).implicitConvTo(to))
5492 m = MATCH.convert; // match with conversions
5493 else
5494 m = MATCH.nomatch; // no match
5495 return m;
5498 override MATCH constConv(Type to)
5500 if (equals(to))
5501 return MATCH.exact;
5502 if (ty == to.ty && sym == (cast(TypeEnum)to).sym && MODimplicitConv(mod, to.mod))
5503 return MATCH.constant;
5504 return MATCH.nomatch;
5507 extern (D) Type toBasetype2()
5509 if (!sym.members && !sym.memtype)
5510 return this;
5511 auto tb = sym.getMemtype(Loc.initial).toBasetype();
5512 return tb.castMod(mod); // retain modifier bits from 'this'
5515 override bool isZeroInit(const ref Loc loc)
5517 return sym.getDefaultValue(loc).toBool().hasValue(false);
5520 override bool hasPointers()
5522 return memType().hasPointers();
5525 override bool hasVoidInitPointers()
5527 return memType().hasVoidInitPointers();
5530 override bool hasSystemFields()
5532 return memType().hasSystemFields();
5535 override bool hasInvariant()
5537 return memType().hasInvariant();
5540 override Type nextOf()
5542 return memType().nextOf();
5545 override void accept(Visitor v)
5547 v.visit(this);
5551 /***********************************************************
5553 extern (C++) final class TypeClass : Type
5555 ClassDeclaration sym;
5556 AliasThisRec att = AliasThisRec.fwdref;
5557 CPPMANGLE cppmangle = CPPMANGLE.def;
5559 extern (D) this(ClassDeclaration sym) @safe
5561 super(Tclass);
5562 this.sym = sym;
5565 override const(char)* kind() const
5567 return "class";
5570 override uinteger_t size(const ref Loc loc)
5572 return target.ptrsize;
5575 override TypeClass syntaxCopy()
5577 return this;
5580 override Dsymbol toDsymbol(Scope* sc)
5582 return sym;
5585 override inout(ClassDeclaration) isClassHandle() inout
5587 return sym;
5590 override bool isBaseOf(Type t, int* poffset)
5592 if (t && t.ty == Tclass)
5594 ClassDeclaration cd = (cast(TypeClass)t).sym;
5595 if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
5596 cd.dsymbolSemantic(null);
5597 if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
5598 sym.dsymbolSemantic(null);
5600 if (sym.isBaseOf(cd, poffset))
5601 return true;
5603 return false;
5606 extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
5608 // Run semantic before checking whether class is convertible
5609 ClassDeclaration cdto = to.isClassHandle();
5610 if (cdto)
5612 //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete());
5613 if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete())
5614 cdto.dsymbolSemantic(null);
5615 if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
5616 sym.dsymbolSemantic(null);
5618 MATCH m = constConv(to);
5619 if (m > MATCH.nomatch)
5620 return m;
5622 if (cdto && cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod))
5624 //printf("'to' is base\n");
5625 return MATCH.convert;
5627 return MATCH.nomatch;
5630 extern (D) MATCH implicitConvToThroughAliasThis(Type to)
5632 MATCH m;
5633 if (sym.aliasthis && !(att & AliasThisRec.tracing))
5635 if (auto ato = aliasthisOf())
5637 att = cast(AliasThisRec)(att | AliasThisRec.tracing);
5638 m = ato.implicitConvTo(to);
5639 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
5642 return m;
5645 override MATCH implicitConvTo(Type to)
5647 //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
5648 MATCH m = implicitConvToWithoutAliasThis(to);
5649 return m ? m : implicitConvToThroughAliasThis(to);
5652 override MATCH constConv(Type to)
5654 if (equals(to))
5655 return MATCH.exact;
5656 if (ty == to.ty && sym == (cast(TypeClass)to).sym && MODimplicitConv(mod, to.mod))
5657 return MATCH.constant;
5659 /* Conversion derived to const(base)
5661 int offset = 0;
5662 if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
5664 // Disallow:
5665 // derived to base
5666 // inout(derived) to inout(base)
5667 if (!to.isMutable() && !to.isWild())
5668 return MATCH.convert;
5671 return MATCH.nomatch;
5674 override MOD deduceWild(Type t, bool isRef)
5676 ClassDeclaration cd = t.isClassHandle();
5677 if (cd && (sym == cd || cd.isBaseOf(sym, null)))
5678 return Type.deduceWild(t, isRef);
5680 ubyte wm = 0;
5682 if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing))
5684 if (auto ato = aliasthisOf())
5686 att = cast(AliasThisRec)(att | AliasThisRec.tracing);
5687 wm = ato.deduceWild(t, isRef);
5688 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
5692 return wm;
5695 override inout(Type) toHeadMutable() inout
5697 return this;
5700 override bool isZeroInit(const ref Loc loc)
5702 return true;
5705 override bool isscope()
5707 return sym.stack;
5710 override bool isBoolean()
5712 return true;
5715 override bool hasPointers()
5717 return true;
5720 override void accept(Visitor v)
5722 v.visit(this);
5726 /***********************************************************
5728 extern (C++) final class TypeTuple : Type
5730 // 'logically immutable' cached global - don't modify!
5731 __gshared TypeTuple empty = new TypeTuple();
5733 Parameters* arguments; // types making up the tuple
5735 extern (D) this(Parameters* arguments) @safe
5737 super(Ttuple);
5738 //printf("TypeTuple(this = %p)\n", this);
5739 this.arguments = arguments;
5740 //printf("TypeTuple() %p, %s\n", this, toChars());
5741 debug
5743 if (arguments)
5745 for (size_t i = 0; i < arguments.length; i++)
5747 Parameter arg = (*arguments)[i];
5748 assert(arg && arg.type);
5754 /****************
5755 * Form TypeTuple from the types of the expressions.
5756 * Assume exps[] is already tuple expanded.
5758 extern (D) this(Expressions* exps)
5760 super(Ttuple);
5761 auto arguments = new Parameters(exps ? exps.length : 0);
5762 if (exps)
5764 for (size_t i = 0; i < exps.length; i++)
5766 Expression e = (*exps)[i];
5767 if (e.type.ty == Ttuple)
5768 error(e.loc, "cannot form sequence of sequences");
5769 auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null);
5770 (*arguments)[i] = arg;
5773 this.arguments = arguments;
5774 //printf("TypeTuple() %p, %s\n", this, toChars());
5777 static TypeTuple create(Parameters* arguments) @safe
5779 return new TypeTuple(arguments);
5782 /*******************************************
5783 * Type tuple with 0, 1 or 2 types in it.
5785 extern (D) this() @safe
5787 super(Ttuple);
5788 arguments = new Parameters();
5791 extern (D) this(Type t1)
5793 super(Ttuple);
5794 arguments = new Parameters();
5795 arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null));
5798 extern (D) this(Type t1, Type t2)
5800 super(Ttuple);
5801 arguments = new Parameters();
5802 arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null));
5803 arguments.push(new Parameter(Loc.initial, 0, t2, null, null, null));
5806 static TypeTuple create() @safe
5808 return new TypeTuple();
5811 static TypeTuple create(Type t1)
5813 return new TypeTuple(t1);
5816 static TypeTuple create(Type t1, Type t2)
5818 return new TypeTuple(t1, t2);
5821 override const(char)* kind() const
5823 return "sequence";
5826 override TypeTuple syntaxCopy()
5828 Parameters* args = Parameter.arraySyntaxCopy(arguments);
5829 auto t = new TypeTuple(args);
5830 t.mod = mod;
5831 return t;
5834 override bool equals(const RootObject o) const
5836 Type t = cast(Type)o;
5837 //printf("TypeTuple::equals(%s, %s)\n", toChars(), t.toChars());
5838 if (this == t)
5839 return true;
5840 if (auto tt = t.isTypeTuple())
5842 if (arguments.length == tt.arguments.length)
5844 for (size_t i = 0; i < tt.arguments.length; i++)
5846 const Parameter arg1 = (*arguments)[i];
5847 Parameter arg2 = (*tt.arguments)[i];
5848 if (!arg1.type.equals(arg2.type))
5849 return false;
5851 return true;
5854 return false;
5857 override MATCH implicitConvTo(Type to)
5859 if (this == to)
5860 return MATCH.exact;
5861 if (auto tt = to.isTypeTuple())
5863 if (arguments.length == tt.arguments.length)
5865 MATCH m = MATCH.exact;
5866 for (size_t i = 0; i < tt.arguments.length; i++)
5868 Parameter arg1 = (*arguments)[i];
5869 Parameter arg2 = (*tt.arguments)[i];
5870 MATCH mi = arg1.type.implicitConvTo(arg2.type);
5871 if (mi < m)
5872 m = mi;
5874 return m;
5877 return MATCH.nomatch;
5880 override void accept(Visitor v)
5882 v.visit(this);
5886 /***********************************************************
5887 * This is so we can slice a TypeTuple
5889 extern (C++) final class TypeSlice : TypeNext
5891 Expression lwr;
5892 Expression upr;
5894 extern (D) this(Type next, Expression lwr, Expression upr) @safe
5896 super(Tslice, next);
5897 //printf("TypeSlice[%s .. %s]\n", lwr.toChars(), upr.toChars());
5898 this.lwr = lwr;
5899 this.upr = upr;
5902 override const(char)* kind() const
5904 return "slice";
5907 override TypeSlice syntaxCopy()
5909 auto t = new TypeSlice(next.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy());
5910 t.mod = mod;
5911 return t;
5914 override void accept(Visitor v)
5916 v.visit(this);
5920 /***********************************************************
5922 extern (C++) final class TypeNull : Type
5924 extern (D) this() @safe
5926 //printf("TypeNull %p\n", this);
5927 super(Tnull);
5930 override const(char)* kind() const
5932 return "null";
5935 override TypeNull syntaxCopy()
5937 // No semantic analysis done, no need to copy
5938 return this;
5941 override MATCH implicitConvTo(Type to)
5943 //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
5944 //printf("from: %s\n", toChars());
5945 //printf("to : %s\n", to.toChars());
5946 MATCH m = Type.implicitConvTo(to);
5947 if (m != MATCH.nomatch)
5948 return m;
5950 // NULL implicitly converts to any pointer type or dynamic array
5951 //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
5953 Type tb = to.toBasetype();
5954 if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
5955 return MATCH.constant;
5958 return MATCH.nomatch;
5961 override bool hasPointers()
5963 /* Although null isn't dereferencable, treat it as a pointer type for
5964 * attribute inference, generic code, etc.
5966 return true;
5969 override bool isBoolean()
5971 return true;
5974 override uinteger_t size(const ref Loc loc)
5976 return tvoidptr.size(loc);
5979 override void accept(Visitor v)
5981 v.visit(this);
5985 /***********************************************************
5987 extern (C++) final class TypeNoreturn : Type
5989 extern (D) this() @safe
5991 //printf("TypeNoreturn %p\n", this);
5992 super(Tnoreturn);
5995 override const(char)* kind() const
5997 return "noreturn";
6000 override TypeNoreturn syntaxCopy()
6002 // No semantic analysis done, no need to copy
6003 return this;
6006 override MATCH implicitConvTo(Type to)
6008 //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
6009 //printf("from: %s\n", toChars());
6010 //printf("to : %s\n", to.toChars());
6011 if (this.equals(to))
6012 return MATCH.exact;
6014 // Different qualifiers?
6015 if (to.ty == Tnoreturn)
6016 return MATCH.constant;
6018 // Implicitly convertible to any type
6019 return MATCH.convert;
6022 override MATCH constConv(Type to)
6024 // Either another noreturn or conversion to any type
6025 return this.implicitConvTo(to);
6028 override bool isBoolean()
6030 return true; // bottom type can be implicitly converted to any other type
6033 override uinteger_t size(const ref Loc loc)
6035 return 0;
6038 override uint alignsize()
6040 return 0;
6043 override void accept(Visitor v)
6045 v.visit(this);
6049 /***********************************************************
6050 * Unlike D, C can declare/define struct/union/enum tag names
6051 * inside Declarators, instead of separately as in D.
6052 * The order these appear in the symbol table must be in lexical
6053 * order. There isn't enough info at the parsing stage to determine if
6054 * it's a declaration or a reference to an existing name, so this Type
6055 * collects the necessary info and defers it to semantic().
6057 extern (C++) final class TypeTag : Type
6059 Loc loc; /// location of declaration
6060 TOK tok; /// TOK.struct_, TOK.union_, TOK.enum_
6061 structalign_t packalign; /// alignment of struct/union fields
6062 Identifier id; /// tag name identifier
6063 Type base; /// base type for enums otherwise null
6064 Dsymbols* members; /// members of struct, null if none
6066 Type resolved; /// type after semantic() in case there are more others
6067 /// pointing to this instance, which can happen with
6068 /// struct S { int a; } s1, *s2;
6069 MOD mod; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment)
6071 extern (D) this(const ref Loc loc, TOK tok, Identifier id, structalign_t packalign, Type base, Dsymbols* members) @safe
6073 //printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this);
6074 super(Ttag);
6075 this.loc = loc;
6076 this.tok = tok;
6077 this.id = id;
6078 this.packalign = packalign;
6079 this.base = base;
6080 this.members = members;
6081 this.mod = 0;
6084 override const(char)* kind() const
6086 return "tag";
6089 override TypeTag syntaxCopy()
6091 //printf("TypeTag syntaxCopy()\n");
6092 // No semantic analysis done, no need to copy
6093 return this;
6096 override void accept(Visitor v)
6098 v.visit(this);
6102 /***********************************************************
6103 * Represents a function's formal parameters + variadics info.
6104 * Length, indexing and iteration are based on a depth-first tuple expansion.
6105 * https://dlang.org/spec/function.html#ParameterList
6107 extern (C++) struct ParameterList
6109 /// The raw (unexpanded) formal parameters, possibly containing tuples.
6110 Parameters* parameters;
6111 StorageClass stc; // storage class of ...
6112 VarArg varargs = VarArg.none;
6113 bool hasIdentifierList; // true if C identifier-list style
6115 this(Parameters* parameters, VarArg varargs = VarArg.none, StorageClass stc = 0) @safe
6117 this.parameters = parameters;
6118 this.varargs = varargs;
6119 this.stc = stc;
6122 /// Returns the number of expanded parameters. Complexity: O(N).
6123 size_t length()
6125 return Parameter.dim(parameters);
6128 /// Returns the expanded parameter at the given index, or null if out of
6129 /// bounds. Complexity: O(i).
6130 Parameter opIndex(size_t i)
6132 return Parameter.getNth(parameters, i);
6135 /// Iterates over the expanded parameters. Complexity: O(N).
6136 /// Prefer this to avoid the O(N + N^2/2) complexity of calculating length
6137 /// and calling N times opIndex.
6138 extern (D) int opApply(scope Parameter.ForeachDg dg)
6140 return Parameter._foreach(parameters, dg);
6143 /// Iterates over the expanded parameters, matching them with the unexpanded
6144 /// ones, for semantic processing
6145 extern (D) int opApply(scope Parameter.SemanticForeachDg dg)
6147 return Parameter._foreach(this.parameters, dg);
6150 extern (D) ParameterList syntaxCopy()
6152 return ParameterList(Parameter.arraySyntaxCopy(parameters), varargs);
6155 /// Compares this to another ParameterList (and expands tuples if necessary)
6156 extern (D) bool opEquals(scope ref ParameterList other) const
6158 if (stc != other.stc || varargs != other.varargs || (!parameters != !other.parameters))
6159 return false;
6161 if (this.parameters is other.parameters)
6162 return true;
6164 size_t idx;
6165 bool diff;
6167 // Pairwise compare each parameter
6168 // Can this avoid the O(n) indexing for the second list?
6169 foreach (_, p1; cast() this)
6171 auto p2 = other[idx++];
6172 if (!p2 || p1 != p2) {
6173 diff = true;
6174 break;
6178 // Ensure no remaining parameters in `other`
6179 return !diff && other[idx] is null;
6182 /// Returns: `true` if any parameter has a default argument
6183 extern(D) bool hasDefaultArgs()
6185 foreach (oidx, oparam, eidx, eparam; this)
6187 if (eparam.defaultArg)
6188 return true;
6190 return false;
6193 // Returns: `true` if any parameter doesn't have a default argument
6194 extern(D) bool hasArgsWithoutDefault()
6196 foreach (oidx, oparam, eidx, eparam; this)
6198 if (!eparam.defaultArg)
6199 return true;
6201 return false;
6206 /***********************************************************
6208 extern (C++) final class Parameter : ASTNode
6210 import dmd.attrib : UserAttributeDeclaration;
6212 Loc loc;
6213 StorageClass storageClass;
6214 Type type;
6215 Identifier ident;
6216 Expression defaultArg;
6217 UserAttributeDeclaration userAttribDecl; // user defined attributes
6219 extern (D) this(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe
6221 this.loc = loc;
6222 this.type = type;
6223 this.ident = ident;
6224 this.storageClass = storageClass;
6225 this.defaultArg = defaultArg;
6226 this.userAttribDecl = userAttribDecl;
6229 static Parameter create(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe
6231 return new Parameter(loc, storageClass, type, ident, defaultArg, userAttribDecl);
6234 Parameter syntaxCopy()
6236 return new Parameter(loc, storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? userAttribDecl.syntaxCopy(null) : null);
6239 /****************************************************
6240 * Determine if parameter is a lazy array of delegates.
6241 * If so, return the return type of those delegates.
6242 * If not, return NULL.
6244 * Returns T if the type is one of the following forms:
6245 * T delegate()[]
6246 * T delegate()[dim]
6248 Type isLazyArray()
6250 Type tb = type.toBasetype();
6251 if (tb.ty == Tsarray || tb.ty == Tarray)
6253 Type tel = (cast(TypeArray)tb).next.toBasetype();
6254 if (auto td = tel.isTypeDelegate())
6256 TypeFunction tf = td.next.toTypeFunction();
6257 if (tf.parameterList.varargs == VarArg.none && tf.parameterList.length == 0)
6259 return tf.next; // return type of delegate
6263 return null;
6266 /// Returns: Whether the function parameter is lazy
6267 bool isLazy() const @safe pure nothrow @nogc
6269 return (this.storageClass & (STC.lazy_)) != 0;
6272 /// Returns: Whether the function parameter is a reference (out / ref)
6273 bool isReference() const @safe pure nothrow @nogc
6275 return (this.storageClass & (STC.ref_ | STC.out_)) != 0;
6278 // kludge for template.isType()
6279 override DYNCAST dyncast() const
6281 return DYNCAST.parameter;
6284 override void accept(Visitor v)
6286 v.visit(this);
6289 extern (D) static Parameters* arraySyntaxCopy(Parameters* parameters)
6291 Parameters* params = null;
6292 if (parameters)
6294 params = new Parameters(parameters.length);
6295 for (size_t i = 0; i < params.length; i++)
6296 (*params)[i] = (*parameters)[i].syntaxCopy();
6298 return params;
6301 /***************************************
6302 * Determine number of arguments, folding in tuples.
6304 static size_t dim(Parameters* parameters)
6306 size_t nargs = 0;
6308 int dimDg(size_t n, Parameter p)
6310 ++nargs;
6311 return 0;
6314 _foreach(parameters, &dimDg);
6315 return nargs;
6319 * Get nth `Parameter`, folding in tuples.
6321 * Since `parameters` can include tuples, which would increase its
6322 * length, this function allows to get the `nth` parameter as if
6323 * all tuples transitively contained in `parameters` were flattened.
6325 * Params:
6326 * parameters = Array of `Parameter` to iterate over
6327 * nth = Index of the desired parameter.
6329 * Returns:
6330 * The parameter at index `nth` (taking tuples into account),
6331 * or `null` if out of bound.
6333 static Parameter getNth(Parameters* parameters, size_t nth)
6335 Parameter param;
6337 int getNthParamDg(size_t n, Parameter p)
6339 if (n == nth)
6341 param = p;
6342 return 1;
6344 return 0;
6347 int res = _foreach(parameters, &getNthParamDg);
6348 return res ? param : null;
6351 /// Type of delegate when iterating solely on the parameters
6352 alias ForeachDg = extern (D) int delegate(size_t paramidx, Parameter param);
6353 /// Type of delegate when iterating on both the original set of parameters,
6354 /// and the type tuple. Useful for semantic analysis.
6355 /// 'o' stands for 'original' and 'e' stands for 'expanded'.
6356 alias SemanticForeachDg = extern (D) int delegate(
6357 size_t oidx, Parameter oparam, size_t eidx, Parameter eparam);
6359 /***************************************
6360 * Expands tuples in args in depth first order. Calls
6361 * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
6362 * If dg returns !=0, stops and returns that value else returns 0.
6363 * Use this function to avoid the O(N + N^2/2) complexity of
6364 * calculating dim and calling N times getNth.
6366 extern (D) static int _foreach(Parameters* parameters, scope ForeachDg dg)
6368 assert(dg !is null);
6369 return _foreach(parameters, (_oidx, _oparam, idx, param) => dg(idx, param));
6372 /// Ditto
6373 extern (D) static int _foreach(
6374 Parameters* parameters, scope SemanticForeachDg dg)
6376 assert(dg !is null);
6377 if (parameters is null)
6378 return 0;
6380 size_t eidx;
6381 foreach (oidx; 0 .. parameters.length)
6383 Parameter oparam = (*parameters)[oidx];
6384 if (auto r = _foreachImpl(dg, oidx, oparam, eidx, /* eparam */ oparam))
6385 return r;
6387 return 0;
6390 /// Implementation of the iteration process, which recurses in itself
6391 /// and just forwards `oidx` and `oparam`.
6392 extern (D) private static int _foreachImpl(scope SemanticForeachDg dg,
6393 size_t oidx, Parameter oparam, ref size_t eidx, Parameter eparam)
6395 if (eparam is null)
6396 return 0;
6398 Type t = eparam.type.toBasetype();
6399 if (auto tu = t.isTypeTuple())
6401 // Check for empty tuples
6402 if (tu.arguments is null)
6403 return 0;
6405 foreach (nidx; 0 .. tu.arguments.length)
6407 Parameter nextep = (*tu.arguments)[nidx];
6408 if (auto r = _foreachImpl(dg, oidx, oparam, eidx, nextep))
6409 return r;
6412 else
6414 if (auto r = dg(oidx, oparam, eidx, eparam))
6415 return r;
6416 // The only place where we should increment eidx is here,
6417 // as a TypeTuple doesn't count as a parameter (for arity)
6418 // it it is empty.
6419 eidx++;
6421 return 0;
6424 override const(char)* toChars() const
6426 return ident ? ident.toChars() : "__anonymous_param";
6429 /*********************************
6430 * Compute covariance of parameters `this` and `p`
6431 * as determined by the storage classes of both.
6433 * Params:
6434 * returnByRef = true if the function returns by ref
6435 * p = Parameter to compare with
6436 * previewIn = Whether `-preview=in` is being used, and thus if
6437 * `in` means `scope [ref]`.
6439 * Returns:
6440 * true = `this` can be used in place of `p`
6441 * false = nope
6443 bool isCovariant(bool returnByRef, const Parameter p, bool previewIn = global.params.previewIn)
6444 const pure nothrow @nogc @safe
6446 ulong thisSTC = this.storageClass;
6447 ulong otherSTC = p.storageClass;
6449 if (previewIn)
6451 if (thisSTC & STC.in_)
6452 thisSTC |= STC.scope_;
6453 if (otherSTC & STC.in_)
6454 otherSTC |= STC.scope_;
6457 const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0);
6458 if ((thisSTC & mask) != (otherSTC & mask))
6459 return false;
6460 return isCovariantScope(returnByRef, thisSTC, otherSTC);
6463 extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
6465 // Workaround for failing covariance when finding a common type of delegates,
6466 // some of which have parameters with inferred scope
6467 // https://issues.dlang.org/show_bug.cgi?id=21285
6468 // The root cause is that scopeinferred is not part of the mangle, and mangle
6469 // is used for type equality checks
6470 if (to & STC.returninferred)
6471 to &= ~STC.return_;
6472 // note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope
6473 if (to & STC.scopeinferred && !(to & STC.return_))
6474 to &= ~STC.scope_;
6476 if (from == to)
6477 return true;
6479 /* result is true if the 'from' can be used as a 'to'
6482 if ((from ^ to) & STC.ref_) // differing in 'ref' means no covariance
6483 return false;
6485 /* workaround until we get STC.returnScope reliably set correctly
6487 if (returnByRef)
6489 from &= ~STC.returnScope;
6490 to &= ~STC.returnScope;
6492 else
6494 from |= STC.returnScope;
6495 to |= STC.returnScope;
6497 return covariant[buildScopeRef(from)][buildScopeRef(to)];
6500 extern (D) private static bool[ScopeRef.max + 1][ScopeRef.max + 1] covariantInit() pure nothrow @nogc @safe
6502 /* Initialize covariant[][] with this:
6504 From\To n rs s
6505 None X
6506 ReturnScope X X
6507 Scope X X X
6509 From\To r rr rs rr-s r-rs
6510 Ref X X
6511 ReturnRef X
6512 RefScope X X X X X
6513 ReturnRef-Scope X X
6514 Ref-ReturnScope X X X
6516 bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant;
6518 foreach (i; 0 .. ScopeRef.max + 1)
6520 covariant[i][i] = true;
6521 covariant[ScopeRef.RefScope][i] = true;
6523 covariant[ScopeRef.ReturnScope][ScopeRef.None] = true;
6524 covariant[ScopeRef.Scope ][ScopeRef.None] = true;
6525 covariant[ScopeRef.Scope ][ScopeRef.ReturnScope] = true;
6527 covariant[ScopeRef.Ref ][ScopeRef.ReturnRef] = true;
6528 covariant[ScopeRef.ReturnRef_Scope][ScopeRef.ReturnRef] = true;
6529 covariant[ScopeRef.Ref_ReturnScope][ScopeRef.Ref ] = true;
6530 covariant[ScopeRef.Ref_ReturnScope][ScopeRef.ReturnRef] = true;
6532 return covariant;
6535 extern (D) private static immutable bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant = covariantInit();
6537 extern (D) bool opEquals(const Parameter other) const
6539 return this.storageClass == other.storageClass
6540 && this.type == other.type;
6544 /*************************************************************
6545 * For printing two types with qualification when necessary.
6546 * Params:
6547 * t1 = The first type to receive the type name for
6548 * t2 = The second type to receive the type name for
6549 * Returns:
6550 * The fully-qualified names of both types if the two type names are not the same,
6551 * or the unqualified names of both types if the two type names are the same.
6553 const(char*)[2] toAutoQualChars(Type t1, Type t2)
6555 auto s1 = t1.toChars();
6556 auto s2 = t2.toChars();
6557 // show qualification only if it's different
6558 if (!t1.equals(t2) && strcmp(s1, s2) == 0)
6560 s1 = t1.toPrettyChars(true);
6561 s2 = t2.toPrettyChars(true);
6563 return [s1, s2];
6568 * For each active modifier (MODFlags.const_, MODFlags.immutable_, etc) call `fp` with a
6569 * void* for the work param and a string representation of the attribute.
6571 void modifiersApply(const TypeFunction tf, void delegate(string) dg)
6573 immutable ubyte[4] modsArr = [MODFlags.const_, MODFlags.immutable_, MODFlags.wild, MODFlags.shared_];
6575 foreach (modsarr; modsArr)
6577 if (tf.mod & modsarr)
6579 dg(MODtoString(modsarr));
6585 * For each active attribute (ref/const/nogc/etc) call `fp` with a void* for the
6586 * work param and a string representation of the attribute.
6588 void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTformat trustFormat = TRUSTformatDefault)
6590 if (tf.purity)
6591 dg("pure");
6592 if (tf.isnothrow)
6593 dg("nothrow");
6594 if (tf.isnogc)
6595 dg("@nogc");
6596 if (tf.isproperty)
6597 dg("@property");
6598 if (tf.isref)
6599 dg("ref");
6600 if (tf.isreturn && !tf.isreturninferred)
6601 dg("return");
6602 if (tf.isScopeQual && !tf.isscopeinferred)
6603 dg("scope");
6604 if (tf.islive)
6605 dg("@live");
6607 TRUST trustAttrib = tf.trust;
6609 if (trustAttrib == TRUST.default_)
6611 if (trustFormat != TRUSTformatSystem)
6612 return;
6613 trustAttrib = TRUST.system; // avoid calling with an empty string
6616 dg(trustToString(trustAttrib));
6620 * If the type is a class or struct, returns the symbol for it,
6621 * else null.
6623 extern (C++) AggregateDeclaration isAggregate(Type t)
6625 t = t.toBasetype();
6626 if (t.ty == Tclass)
6627 return (cast(TypeClass)t).sym;
6628 if (t.ty == Tstruct)
6629 return (cast(TypeStruct)t).sym;
6630 return null;
6633 /***************************************************
6634 * Determine if type t can be indexed or sliced given that it is not an
6635 * aggregate with operator overloads.
6636 * Params:
6637 * t = type to check
6638 * Returns:
6639 * true if an expression of type t can be e1 in an array expression
6641 bool isIndexableNonAggregate(Type t)
6643 t = t.toBasetype();
6644 return (t.ty == Tpointer || t.ty == Tsarray || t.ty == Tarray || t.ty == Taarray ||
6645 t.ty == Ttuple || t.ty == Tvector);
6648 /***************************************************
6649 * Determine if type t is copyable.
6650 * Params:
6651 * t = type to check
6652 * Returns:
6653 * true if we can copy it
6655 bool isCopyable(Type t)
6657 //printf("isCopyable() %s\n", t.toChars());
6658 if (auto ts = t.isTypeStruct())
6660 if (ts.sym.postblit &&
6661 ts.sym.postblit.storage_class & STC.disable)
6662 return false;
6663 if (ts.sym.hasCopyCtor)
6665 // check if there is a matching overload of the copy constructor and whether it is disabled or not
6666 // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
6667 Dsymbol ctor = search_function(ts.sym, Id.ctor);
6668 assert(ctor);
6669 scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
6670 el.type = cast() ts;
6671 Expressions* args = new Expressions();
6672 args.push(el);
6673 FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet);
6674 if (!f || f.storage_class & STC.disable)
6675 return false;
6678 return true;
6681 /***************************************
6682 * Computes how a parameter may be returned.
6683 * Shrinking the representation is necessary because StorageClass is so wide
6684 * Params:
6685 * stc = storage class of parameter
6686 * Returns:
6687 * value from enum ScopeRef
6689 ScopeRef buildScopeRef(StorageClass stc) pure nothrow @nogc @safe
6691 if (stc & STC.out_)
6692 stc |= STC.ref_; // treat `out` and `ref` the same
6694 ScopeRef result;
6695 final switch (stc & (STC.ref_ | STC.scope_ | STC.return_))
6697 case 0: result = ScopeRef.None; break;
6699 /* can occur in case test/compilable/testsctreturn.d
6700 * related to https://issues.dlang.org/show_bug.cgi?id=20149
6701 * where inout adds `return` without `scope` or `ref`
6703 case STC.return_: result = ScopeRef.Return; break;
6705 case STC.ref_: result = ScopeRef.Ref; break;
6706 case STC.scope_: result = ScopeRef.Scope; break;
6707 case STC.return_ | STC.ref_: result = ScopeRef.ReturnRef; break;
6708 case STC.return_ | STC.scope_: result = ScopeRef.ReturnScope; break;
6709 case STC.ref_ | STC.scope_: result = ScopeRef.RefScope; break;
6711 case STC.return_ | STC.ref_ | STC.scope_:
6712 result = stc & STC.returnScope ? ScopeRef.Ref_ReturnScope
6713 : ScopeRef.ReturnRef_Scope;
6714 break;
6716 return result;
6720 * Classification of 'scope-return-ref' possibilities
6722 enum ScopeRef
6724 None,
6725 Scope,
6726 ReturnScope,
6727 Ref,
6728 ReturnRef,
6729 RefScope,
6730 ReturnRef_Scope,
6731 Ref_ReturnScope,
6732 Return,
6735 /*********************************
6736 * Give us a nice string for debugging purposes.
6737 * Params:
6738 * sr = value
6739 * Returns:
6740 * corresponding string
6742 const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe
6744 with (ScopeRef)
6746 static immutable char*[ScopeRef.max + 1] names =
6748 None: "None",
6749 Scope: "Scope",
6750 ReturnScope: "ReturnScope",
6751 Ref: "Ref",
6752 ReturnRef: "ReturnRef",
6753 RefScope: "RefScope",
6754 ReturnRef_Scope: "ReturnRef_Scope",
6755 Ref_ReturnScope: "Ref_ReturnScope",
6756 Return: "Return",
6758 return names[sr];
6763 * Creates an appropriate vector type for `tv` that will hold one boolean
6764 * result for each element of the vector type. The result of vector comparisons
6765 * is a single or doubleword mask of all 1s (comparison true) or all 0s
6766 * (comparison false). This SIMD mask type does not have an equivalent D type,
6767 * however its closest equivalent would be an integer vector of the same unit
6768 * size and length.
6770 * Params:
6771 * tv = The `TypeVector` to build a vector from.
6772 * Returns:
6773 * A vector type suitable for the result of a vector comparison operation.
6775 TypeVector toBooleanVector(TypeVector tv)
6777 Type telem = tv.elementType();
6778 switch (telem.ty)
6780 case Tvoid:
6781 case Tint8:
6782 case Tuns8:
6783 case Tint16:
6784 case Tuns16:
6785 case Tint32:
6786 case Tuns32:
6787 case Tint64:
6788 case Tuns64:
6789 // No need to build an equivalent mask type.
6790 return tv;
6792 case Tfloat32:
6793 telem = Type.tuns32;
6794 break;
6796 case Tfloat64:
6797 telem = Type.tuns64;
6798 break;
6800 default:
6801 assert(0);
6804 TypeSArray tsa = tv.basetype.isTypeSArray();
6805 assert(tsa !is null);
6807 return new TypeVector(new TypeSArray(telem, tsa.dim));
6810 /*************************************************
6811 * Dispatch to function based on static type of Type.
6813 mixin template VisitType(Result)
6815 Result VisitType(Type t)
6817 final switch (t.ty)
6819 case TY.Tvoid:
6820 case TY.Tint8:
6821 case TY.Tuns8:
6822 case TY.Tint16:
6823 case TY.Tuns16:
6824 case TY.Tint32:
6825 case TY.Tuns32:
6826 case TY.Tint64:
6827 case TY.Tuns64:
6828 case TY.Tfloat32:
6829 case TY.Tfloat64:
6830 case TY.Tfloat80:
6831 case TY.Timaginary32:
6832 case TY.Timaginary64:
6833 case TY.Timaginary80:
6834 case TY.Tcomplex32:
6835 case TY.Tcomplex64:
6836 case TY.Tcomplex80:
6837 case TY.Tbool:
6838 case TY.Tchar:
6839 case TY.Twchar:
6840 case TY.Tdchar:
6841 case TY.Tint128:
6842 case TY.Tuns128: mixin(visitTYCase("Basic"));
6843 case TY.Tarray: mixin(visitTYCase("DArray"));
6844 case TY.Tsarray: mixin(visitTYCase("SArray"));
6845 case TY.Taarray: mixin(visitTYCase("AArray"));
6846 case TY.Tpointer: mixin(visitTYCase("Pointer"));
6847 case TY.Treference: mixin(visitTYCase("Reference"));
6848 case TY.Tfunction: mixin(visitTYCase("Function"));
6849 case TY.Tident: mixin(visitTYCase("Identifier"));
6850 case TY.Tclass: mixin(visitTYCase("Class"));
6851 case TY.Tstruct: mixin(visitTYCase("Struct"));
6852 case TY.Tenum: mixin(visitTYCase("Enum"));
6853 case TY.Tdelegate: mixin(visitTYCase("Delegate"));
6854 case TY.Terror: mixin(visitTYCase("Error"));
6855 case TY.Tinstance: mixin(visitTYCase("Instance"));
6856 case TY.Ttypeof: mixin(visitTYCase("Typeof"));
6857 case TY.Ttuple: mixin(visitTYCase("Tuple"));
6858 case TY.Tslice: mixin(visitTYCase("Slice"));
6859 case TY.Treturn: mixin(visitTYCase("Return"));
6860 case TY.Tnull: mixin(visitTYCase("Null"));
6861 case TY.Tvector: mixin(visitTYCase("Vector"));
6862 case TY.Ttraits: mixin(visitTYCase("Traits"));
6863 case TY.Tmixin: mixin(visitTYCase("Mixin"));
6864 case TY.Tnoreturn: mixin(visitTYCase("Noreturn"));
6865 case TY.Ttag: mixin(visitTYCase("Tag"));
6866 case TY.Tnone: assert(0);
6871 /****************************************
6872 * CTFE-only helper function for VisitInitializer.
6873 * Params:
6874 * handler = string for the name of the visit handler
6875 * Returns: boilerplate code for a case
6877 pure string visitTYCase(string handler) @safe
6879 if (__ctfe)
6881 return
6883 enum isVoid = is(Result == void);
6884 auto tx = t.isType"~handler~"();
6885 static if (__traits(compiles, visit"~handler~"(tx)))
6887 static if (isVoid)
6889 visit"~handler~"(tx);
6890 return;
6892 else
6894 if (Result r = visit"~handler~"(tx))
6895 return r;
6896 return Result.init;
6899 else static if (__traits(compiles, visitDefaultCase(t)))
6901 static if (isVoid)
6903 visitDefaultCase(tx);
6904 return;
6906 else
6908 if (Result r = visitDefaultCase(t))
6909 return r;
6910 return Result.init;
6913 else
6914 static assert(0, "~handler~");
6917 assert(0);
6922 * Returns:
6923 * `TypeIdentifier` corresponding to `object.Throwable`
6925 TypeIdentifier getThrowable()
6927 auto tid = new TypeIdentifier(Loc.initial, Id.empty);
6928 tid.addIdent(Id.object);
6929 tid.addIdent(Id.Throwable);
6930 return tid;
6934 * Returns:
6935 * TypeIdentifier corresponding to `object.Exception`
6937 TypeIdentifier getException()
6939 auto tid = new TypeIdentifier(Loc.initial, Id.empty);
6940 tid.addIdent(Id.object);
6941 tid.addIdent(Id.Exception);
6942 return tid;
6945 /**************************************
6946 * Check and set 'att' if 't' is a recursive 'alias this' type
6948 * The goal is to prevent endless loops when there is a cycle in the alias this chain.
6949 * Since there is no multiple `alias this`, the chain either ends in a leaf,
6950 * or it loops back on itself as some point.
6952 * Example: S0 -> (S1 -> S2 -> S3 -> S1)
6954 * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
6955 * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
6956 * this still returns `false`, but `att1` is set to `S1`.
6957 * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
6958 * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
6960 * Params:
6961 * att = type reference used to detect recursion. Should be initialized to `null`.
6962 * t = type of 'alias this' rewrite to attempt
6964 * Returns:
6965 * `false` if the rewrite is safe, `true` if it would loop back around
6967 bool isRecursiveAliasThis(ref Type att, Type t)
6969 //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
6970 auto tb = t.toBasetype();
6971 if (att && tb.equivalent(att))
6972 return true;
6973 else if (!att && tb.checkAliasThisRec())
6974 att = tb;
6975 return false;