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