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