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