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