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