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