4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d)
8 * Documentation: https://dlang.org/phobos/dmd_mtype.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mtype.d
14 import core
.checkedint
;
15 import core
.stdc
.stdarg
;
16 import core
.stdc
.stdio
;
17 import core
.stdc
.stdlib
;
18 import core
.stdc
.string
;
21 import dmd
.arraytypes
;
27 import dmd
.declaration
;
33 import dmd
.dsymbolsem
;
36 import dmd
.expression
;
41 import dmd
.identifier
;
45 import dmd
.root
.ctfloat
;
46 import dmd
.common
.outbuffer
;
48 import dmd
.rootobject
;
49 import dmd
.root
.stringtable
;
55 enum LOGDOTEXP
= 0; // log ::dotExp()
56 enum LOGDEFAULTINIT
= 0; // log ::defaultInit()
58 enum SIZE_INVALID
= (~cast(uinteger_t
)0); // error return from size() functions
61 /***************************
62 * Return !=0 if modfrom can be implicitly converted to modto
64 bool MODimplicitConv(MOD modfrom
, MOD modto
) pure nothrow @nogc @safe
69 //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
70 auto X(T
, U
)(T m
, U n
)
72 return ((m
<< 4) | n
);
75 switch (X(modfrom
& ~MODFlags
.shared_
, modto
& ~MODFlags
.shared_
))
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_
);
83 case X(MODFlags
.immutable_
, MODFlags
.const_
):
84 case X(MODFlags
.immutable_
, MODFlags
.wildconst
):
91 /***************************
92 * Return MATCH.exact or MATCH.constant if a method of type '() modfrom' can call a method of type '() modto'.
94 MATCH
MODmethodConv(MOD modfrom
, MOD modto
) pure nothrow @nogc @safe
98 if (MODimplicitConv(modfrom
, modto
))
99 return MATCH
.constant
;
101 auto X(T
, U
)(T m
, U n
)
103 return ((m
<< 4) | n
);
106 switch (X(modfrom
, modto
))
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
;
119 return MATCH
.nomatch
;
123 /***************************
124 * Merge mod bits to form common mod.
126 MOD
MODmerge(MOD mod1
, MOD mod2
) pure nothrow @nogc @safe
131 //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2);
133 if ((mod1 | mod2
) & MODFlags
.shared_
)
135 // If either type is shared, the result will be shared
136 result |
= MODFlags
.shared_
;
137 mod1
&= ~MODFlags
.shared_
;
138 mod2
&= ~MODFlags
.shared_
;
140 if (mod1
== 0 || mod1
== MODFlags
.mutable || mod1
== MODFlags
.const_ || mod2
== 0 || mod2
== MODFlags
.mutable || mod2
== MODFlags
.const_
)
142 // If either type is mutable or const, the result will be const.
143 result |
= MODFlags
.const_
;
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
;
156 /*********************************
157 * Store modifier name into buf.
159 void MODtoBuffer(ref OutBuffer buf
, MOD mod
) nothrow @safe
161 buf
.writestring(MODtoString(mod
));
164 /*********************************
166 * a human readable representation of `mod`,
167 * which is the token `mod` corresponds to
169 const(char)* MODtoChars(MOD mod
) nothrow pure
171 /// Works because we return a literal
172 return MODtoString(mod
).ptr
;
176 string
MODtoString(MOD mod
) nothrow pure @safe
183 case MODFlags
.immutable_
:
186 case MODFlags
.shared_
:
189 case MODFlags
.shared_ | MODFlags
.const_
:
190 return "shared const";
192 case MODFlags
.const_
:
195 case MODFlags
.shared_ | MODFlags
.wild
:
196 return "shared inout";
201 case MODFlags
.shared_ | MODFlags
.wildconst
:
202 return "shared inout const";
204 case MODFlags
.wildconst
:
205 return "inout const";
209 /*************************************************
210 * Pick off one of the trust flags from trust,
211 * and return a string representation of it.
213 string
trustToString(TRUST trust
) pure nothrow @nogc @safe
230 assert(trustToString(TRUST
.default_
) == "");
231 assert(trustToString(TRUST
.system
) == "@system");
232 assert(trustToString(TRUST
.trusted
) == "@trusted");
233 assert(trustToString(TRUST
.safe
) == "@safe");
236 /************************************
237 * Convert MODxxxx to STCxxx
239 StorageClass
ModToStc(uint mod
) pure nothrow @nogc @safe
241 StorageClass
stc = 0;
242 if (mod
& MODFlags
.immutable_
)
243 stc |
= STC
.immutable_
;
244 if (mod
& MODFlags
.const_
)
246 if (mod
& MODFlags
.wild
)
248 if (mod
& MODFlags
.shared_
)
253 ///Returns true if ty is char, wchar, or dchar
254 bool isSomeChar(TY ty
) pure nothrow @nogc @safe
256 return ty
== Tchar || ty
== Twchar || ty
== Tdchar
;
259 /************************************
260 * Determine mutability of indirections in (ref) t.
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.
267 * isref = if true, check `ref t`; otherwise, check just `t`
268 * t = the type that is being checked
270 int mutabilityOfType(bool isref
, Type t
)
274 if (t
.mod
& MODFlags
.immutable_
)
276 if (t
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
283 if (!t
.hasPointers() || t
.mod
& MODFlags
.immutable_
)
286 /* Accept immutable(T)[] and immutable(T)* as being strongly pure
288 if (t
.ty
== Tarray || t
.ty
== Tpointer
)
290 Type tn
= t
.nextOf().toBasetype();
291 if (tn
.mod
& MODFlags
.immutable_
)
293 if (tn
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
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.)
302 if (t
.mod
& (MODFlags
.const_ | MODFlags
.wild
))
305 /* Should catch delegates and function pointers, and fold in their purity
316 gag
= 1, // don't report "not a property" error and just return null
317 noDeref
= 2, // the use of the expression will not attempt a dereference
318 noAliasThis
= 4, // don't do 'alias this' resolution
321 /// Result of a check whether two types are covariant
324 distinct
= 0, /// types are distinct
325 yes
= 1, /// types are covariant
326 no
= 2, /// arguments match as far as overloading goes, but types are not covariant
327 fwdref
= 3, /// cannot determine covariance because of forward references
330 /***********************************************************
332 extern (C
++) abstract class Type
: ASTNode
335 MOD mod
; // modifiers MODxxxx
340 /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc.
341 * They should not be referenced by anybody but mtype.d.
342 * They can be null if not lazily evaluated yet.
343 * Note that there is no "shared immutable", because that is just immutable
344 * The point of this is to reduce the size of each Type instance as
345 * we bank on the idea that usually only one of variants exist.
346 * It will also speed up code because these are rarely referenced and
347 * so need not be in the cache.
349 Type cto
; // MODFlags.const_
350 Type ito
; // MODFlags.immutable_
351 Type sto
; // MODFlags.shared_
352 Type scto
; // MODFlags.shared_ | MODFlags.const_
353 Type wto
; // MODFlags.wild
354 Type wcto
; // MODFlags.wildconst
355 Type swto
; // MODFlags.shared_ | MODFlags.wild
356 Type swcto
; // MODFlags.shared_ | MODFlags.wildconst
358 private Mcache
* mcache
;
360 Type pto
; // merged pointer to this type
361 Type rto
; // reference to this type
362 Type arrayof
; // array of this type
364 TypeInfoDeclaration vtinfo
; // TypeInfo object for this Type
366 type
* ctype
; // for back end
368 extern (C
++) __gshared Type tvoid
;
369 extern (C
++) __gshared Type tint8
;
370 extern (C
++) __gshared Type tuns8
;
371 extern (C
++) __gshared Type tint16
;
372 extern (C
++) __gshared Type tuns16
;
373 extern (C
++) __gshared Type tint32
;
374 extern (C
++) __gshared Type tuns32
;
375 extern (C
++) __gshared Type tint64
;
376 extern (C
++) __gshared Type tuns64
;
377 extern (C
++) __gshared Type tint128
;
378 extern (C
++) __gshared Type tuns128
;
379 extern (C
++) __gshared Type tfloat32
;
380 extern (C
++) __gshared Type tfloat64
;
381 extern (C
++) __gshared Type tfloat80
;
382 extern (C
++) __gshared Type timaginary32
;
383 extern (C
++) __gshared Type timaginary64
;
384 extern (C
++) __gshared Type timaginary80
;
385 extern (C
++) __gshared Type tcomplex32
;
386 extern (C
++) __gshared Type tcomplex64
;
387 extern (C
++) __gshared Type tcomplex80
;
388 extern (C
++) __gshared Type tbool
;
389 extern (C
++) __gshared Type tchar
;
390 extern (C
++) __gshared Type twchar
;
391 extern (C
++) __gshared Type tdchar
;
393 // Some special types
394 extern (C
++) __gshared Type tshiftcnt
;
395 extern (C
++) __gshared Type tvoidptr
; // void*
396 extern (C
++) __gshared Type tstring
; // immutable(char)[]
397 extern (C
++) __gshared Type twstring
; // immutable(wchar)[]
398 extern (C
++) __gshared Type tdstring
; // immutable(dchar)[]
399 extern (C
++) __gshared Type terror
; // for error recovery
400 extern (C
++) __gshared Type tnull
; // for null type
401 extern (C
++) __gshared Type tnoreturn
; // for bottom type typeof(*null)
403 extern (C
++) __gshared Type tsize_t
; // matches size_t alias
404 extern (C
++) __gshared Type tptrdiff_t
; // matches ptrdiff_t alias
405 extern (C
++) __gshared Type thash_t
; // matches hash_t alias
407 extern (C
++) __gshared ClassDeclaration dtypeinfo
;
408 extern (C
++) __gshared ClassDeclaration typeinfoclass
;
409 extern (C
++) __gshared ClassDeclaration typeinfointerface
;
410 extern (C
++) __gshared ClassDeclaration typeinfostruct
;
411 extern (C
++) __gshared ClassDeclaration typeinfopointer
;
412 extern (C
++) __gshared ClassDeclaration typeinfoarray
;
413 extern (C
++) __gshared ClassDeclaration typeinfostaticarray
;
414 extern (C
++) __gshared ClassDeclaration typeinfoassociativearray
;
415 extern (C
++) __gshared ClassDeclaration typeinfovector
;
416 extern (C
++) __gshared ClassDeclaration typeinfoenum
;
417 extern (C
++) __gshared ClassDeclaration typeinfofunction
;
418 extern (C
++) __gshared ClassDeclaration typeinfodelegate
;
419 extern (C
++) __gshared ClassDeclaration typeinfotypelist
;
420 extern (C
++) __gshared ClassDeclaration typeinfoconst
;
421 extern (C
++) __gshared ClassDeclaration typeinfoinvariant
;
422 extern (C
++) __gshared ClassDeclaration typeinfoshared
;
423 extern (C
++) __gshared ClassDeclaration typeinfowild
;
425 extern (C
++) __gshared TemplateDeclaration rtinfo
;
427 extern (C
++) __gshared Type
[TMAX
] basic
;
429 extern (D
) __gshared StringTable
!Type stringtable
;
430 extern (D
) private static immutable ubyte[TMAX
] sizeTy
= ()
432 ubyte[TMAX
] sizeTy
= __traits(classInstanceSize
, TypeBasic
);
433 sizeTy
[Tsarray
] = __traits(classInstanceSize
, TypeSArray
);
434 sizeTy
[Tarray
] = __traits(classInstanceSize
, TypeDArray
);
435 sizeTy
[Taarray
] = __traits(classInstanceSize
, TypeAArray
);
436 sizeTy
[Tpointer
] = __traits(classInstanceSize
, TypePointer
);
437 sizeTy
[Treference
] = __traits(classInstanceSize
, TypeReference
);
438 sizeTy
[Tfunction
] = __traits(classInstanceSize
, TypeFunction
);
439 sizeTy
[Tdelegate
] = __traits(classInstanceSize
, TypeDelegate
);
440 sizeTy
[Tident
] = __traits(classInstanceSize
, TypeIdentifier
);
441 sizeTy
[Tinstance
] = __traits(classInstanceSize
, TypeInstance
);
442 sizeTy
[Ttypeof
] = __traits(classInstanceSize
, TypeTypeof
);
443 sizeTy
[Tenum
] = __traits(classInstanceSize
, TypeEnum
);
444 sizeTy
[Tstruct
] = __traits(classInstanceSize
, TypeStruct
);
445 sizeTy
[Tclass
] = __traits(classInstanceSize
, TypeClass
);
446 sizeTy
[Ttuple
] = __traits(classInstanceSize
, TypeTuple
);
447 sizeTy
[Tslice
] = __traits(classInstanceSize
, TypeSlice
);
448 sizeTy
[Treturn
] = __traits(classInstanceSize
, TypeReturn
);
449 sizeTy
[Terror
] = __traits(classInstanceSize
, TypeError
);
450 sizeTy
[Tnull
] = __traits(classInstanceSize
, TypeNull
);
451 sizeTy
[Tvector
] = __traits(classInstanceSize
, TypeVector
);
452 sizeTy
[Ttraits
] = __traits(classInstanceSize
, TypeTraits
);
453 sizeTy
[Tmixin
] = __traits(classInstanceSize
, TypeMixin
);
454 sizeTy
[Tnoreturn
] = __traits(classInstanceSize
, TypeNoreturn
);
455 sizeTy
[Ttag
] = __traits(classInstanceSize
, TypeTag
);
459 final extern (D
) this(TY ty
) scope @safe
464 const(char)* kind() const nothrow pure @nogc @safe
466 assert(false); // should be overridden
469 final Type
copy() nothrow const
471 Type t
= cast(Type
)mem
.xmalloc(sizeTy
[ty
]);
472 memcpy(cast(void*)t
, cast(void*)this, sizeTy
[ty
]);
478 fprintf(stderr
, "this = %s, ty = %d\n", toChars(), ty
);
482 override bool equals(const RootObject o
) const
484 Type t
= cast(Type
)o
;
485 //printf("Type::equals(%s, %s)\n", toChars(), t.toChars());
486 // deco strings are unique
487 // and semantic() has been run
488 if (this == o ||
((t
&& deco
== t
.deco
) && deco
!is null))
490 //printf("deco = '%s', t.deco = '%s'\n", deco, t.deco);
493 //if (deco && t && t.deco) printf("deco = '%s', t.deco = '%s'\n", deco, t.deco);
497 final bool equivalent(Type t
)
499 return immutableOf().equals(t
.immutableOf());
502 // kludge for template.isType()
503 override final DYNCAST
dyncast() const
508 /// Returns a non-zero unique ID for this Type, or returns 0 if the Type does not (yet) have a unique ID.
509 /// If `semantic()` has not been run, 0 is returned.
510 final size_t
getUniqueID() const
512 return cast(size_t
) deco
;
516 final Mcache
* getMcache()
519 mcache
= cast(Mcache
*) mem
.xcalloc(Mcache
.sizeof
, 1);
523 /********************************
524 * For pretty-printing a type.
526 final override const(char)* toChars() const
531 hgs
.fullQual
= (ty
== Tclass
&& !mod
);
533 toCBuffer(this, buf
, null, hgs
);
534 return buf
.extractChars();
538 final char* toPrettyChars(bool QualifyTypes
= false)
543 hgs
.fullQual
= QualifyTypes
;
545 toCBuffer(this, buf
, null, hgs
);
546 return buf
.extractChars();
551 stringtable
._init(14_000);
554 __gshared TY
* basetab
=
583 for (size_t i
= 0; basetab
[i
] != Terror
; i
++)
585 Type t
= new TypeBasic(basetab
[i
]);
587 basic
[basetab
[i
]] = t
;
589 basic
[Terror
] = new TypeError();
591 tnoreturn
= new TypeNoreturn();
592 tnoreturn
.deco
= tnoreturn
.merge().deco
;
593 basic
[Tnoreturn
] = tnoreturn
;
595 tvoid
= basic
[Tvoid
];
596 tint8
= basic
[Tint8
];
597 tuns8
= basic
[Tuns8
];
598 tint16
= basic
[Tint16
];
599 tuns16
= basic
[Tuns16
];
600 tint32
= basic
[Tint32
];
601 tuns32
= basic
[Tuns32
];
602 tint64
= basic
[Tint64
];
603 tuns64
= basic
[Tuns64
];
604 tint128
= basic
[Tint128
];
605 tuns128
= basic
[Tuns128
];
606 tfloat32
= basic
[Tfloat32
];
607 tfloat64
= basic
[Tfloat64
];
608 tfloat80
= basic
[Tfloat80
];
610 timaginary32
= basic
[Timaginary32
];
611 timaginary64
= basic
[Timaginary64
];
612 timaginary80
= basic
[Timaginary80
];
614 tcomplex32
= basic
[Tcomplex32
];
615 tcomplex64
= basic
[Tcomplex64
];
616 tcomplex80
= basic
[Tcomplex80
];
618 tbool
= basic
[Tbool
];
619 tchar
= basic
[Tchar
];
620 twchar
= basic
[Twchar
];
621 tdchar
= basic
[Tdchar
];
624 terror
= basic
[Terror
];
625 tnoreturn
= basic
[Tnoreturn
];
626 tnull
= new TypeNull();
627 tnull
.deco
= tnull
.merge().deco
;
629 tvoidptr
= tvoid
.pointerTo();
630 tstring
= tchar
.immutableOf().arrayOf();
631 twstring
= twchar
.immutableOf().arrayOf();
632 tdstring
= tdchar
.immutableOf().arrayOf();
634 const isLP64
= target
.isLP64
;
636 tsize_t
= basic
[isLP64 ? Tuns64
: Tuns32
];
637 tptrdiff_t
= basic
[isLP64 ? Tint64
: Tint32
];
642 * Deinitializes the global state of the compiler.
644 * This can be used to restore the state set by `_init` to its original
647 static void deinitialize()
649 stringtable
= stringtable
.init
;
652 final uinteger_t
size()
654 return size(Loc
.initial
);
657 uinteger_t
size(const ref Loc loc
)
659 error(loc
, "no size for type `%s`", toChars());
665 return cast(uint)size(Loc
.initial
);
668 final Type
trySemantic(const ref Loc loc
, Scope
* sc
)
670 //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
672 // Needed to display any deprecations that were gagged
673 auto tcopy
= this.syntaxCopy();
675 const errors
= global
.startGagging();
676 Type t
= typeSemantic(this, loc
, sc
);
677 if (global
.endGagging(errors
) || t
.ty
== Terror
) // if any errors happened
683 // If `typeSemantic` succeeded, there may have been deprecations that
684 // were gagged due the `startGagging` above. Run again to display
685 // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
686 if (global
.gaggedWarnings
> 0)
687 typeSemantic(tcopy
, loc
, sc
);
689 //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
693 /*************************************
694 * This version does a merge even if the deco is already computed.
695 * Necessary for types that have a deco, but are not merged.
699 //printf("merge2(%s)\n", toChars());
705 auto sv
= stringtable
.lookup(t
.deco
, strlen(t
.deco
));
716 /*********************************
717 * Store this type's modifier name into buf.
719 final void modToBuffer(ref OutBuffer buf
) nothrow const
724 MODtoBuffer(buf
, mod
);
728 /*********************************
729 * Return this type's modifier name.
731 final char* modToChars() nothrow const
736 return buf
.extractChars();
744 // real, imaginary, or complex
785 /**************************
789 * Can we bitwise assign:
798 /**************************
799 * Returns true if T can be converted to boolean value.
806 final bool isConst() const nothrow pure @nogc @safe
808 return (mod
& MODFlags
.const_
) != 0;
811 final bool isImmutable() const nothrow pure @nogc @safe
813 return (mod
& MODFlags
.immutable_
) != 0;
816 final bool isMutable() const nothrow pure @nogc @safe
818 return (mod
& (MODFlags
.const_ | MODFlags
.immutable_ | MODFlags
.wild
)) == 0;
821 final bool isShared() const nothrow pure @nogc @safe
823 return (mod
& MODFlags
.shared_
) != 0;
826 final bool isSharedConst() const nothrow pure @nogc @safe
828 return (mod
& (MODFlags
.shared_ | MODFlags
.const_
)) == (MODFlags
.shared_ | MODFlags
.const_
);
831 final bool isWild() const nothrow pure @nogc @safe
833 return (mod
& MODFlags
.wild
) != 0;
836 final bool isWildConst() const nothrow pure @nogc @safe
838 return (mod
& MODFlags
.wildconst
) == MODFlags
.wildconst
;
841 final bool isSharedWild() const nothrow pure @nogc @safe
843 return (mod
& (MODFlags
.shared_ | MODFlags
.wild
)) == (MODFlags
.shared_ | MODFlags
.wild
);
846 final bool isNaked() const nothrow pure @nogc @safe
851 /********************************
852 * Return a copy of this type with all attributes null-initialized.
853 * Useful for creating a type with different modifiers.
855 final Type
nullAttributes() nothrow const
857 uint sz
= sizeTy
[ty
];
858 Type t
= cast(Type
)mem
.xmalloc(sz
);
859 memcpy(cast(void*)t
, cast(void*)this, sz
);
860 // t.mod = NULL; // leave mod unchanged
869 (cast(TypeStruct
)t
).att
= AliasThisRec
.fwdref
;
871 (cast(TypeClass
)t
).att
= AliasThisRec
.fwdref
;
875 /********************************
876 * Convert to 'const'.
880 //printf("Type::constOf() %p %s\n", this, toChars());
881 if (mod
== MODFlags
.const_
)
883 if (mcache
&& mcache
.cto
)
885 assert(mcache
.cto
.mod
== MODFlags
.const_
);
888 Type t
= makeConst();
891 //printf("-Type::constOf() %p %s\n", t, t.toChars());
895 /********************************
896 * Convert to 'immutable'.
898 final Type
immutableOf()
900 //printf("Type::immutableOf() %p %s\n", this, toChars());
903 if (mcache
&& mcache
.ito
)
905 assert(mcache
.ito
.isImmutable());
908 Type t
= makeImmutable();
911 //printf("\t%p\n", t);
915 /********************************
918 final Type
mutableOf()
920 //printf("Type::mutableOf() %p, %s\n", this, toChars());
925 t
= mcache
.ito
; // immutable => naked
926 assert(!t ||
(t
.isMutable() && !t
.isShared()));
934 t
= mcache
.swcto
; // shared wild const -> shared
936 t
= mcache
.sto
; // shared const => shared
941 t
= mcache
.wcto
; // wild const -> naked
943 t
= mcache
.cto
; // const => naked
945 assert(!t || t
.isMutable());
951 t
= mcache
.sto
; // shared wild => shared
953 t
= mcache
.wto
; // wild => naked
954 assert(!t || t
.isMutable());
964 assert(t
.isMutable());
968 final Type
sharedOf()
970 //printf("Type::sharedOf() %p, %s\n", this, toChars());
971 if (mod
== MODFlags
.shared_
)
973 if (mcache
&& mcache
.sto
)
975 assert(mcache
.sto
.mod
== MODFlags
.shared_
);
978 Type t
= makeShared();
981 //printf("\t%p\n", t);
985 final Type
sharedConstOf()
987 //printf("Type::sharedConstOf() %p, %s\n", this, toChars());
988 if (mod
== (MODFlags
.shared_ | MODFlags
.const_
))
990 if (mcache
&& mcache
.scto
)
992 assert(mcache
.scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
995 Type t
= makeSharedConst();
998 //printf("\t%p\n", t);
1002 /********************************
1003 * Make type unshared.
1006 * immutable => immutable
1008 * shared const => const
1010 * wild const => wild const
1011 * shared wild => wild
1012 * shared wild const => wild const
1014 final Type
unSharedOf()
1016 //printf("Type::unSharedOf() %p, %s\n", this, toChars());
1025 t
= mcache
.wcto
; // shared wild const => wild const
1027 t
= mcache
.wto
; // shared wild => wild
1032 t
= mcache
.cto
; // shared const => const
1034 t
= mcache
.sto
; // shared => naked
1036 assert(!t ||
!t
.isShared());
1041 t
= this.nullAttributes();
1042 t
.mod
= mod
& ~MODFlags
.shared_
;
1049 assert(!t
.isShared());
1053 /********************************
1054 * Convert to 'wild'.
1058 //printf("Type::wildOf() %p %s\n", this, toChars());
1059 if (mod
== MODFlags
.wild
)
1061 if (mcache
&& mcache
.wto
)
1063 assert(mcache
.wto
.mod
== MODFlags
.wild
);
1066 Type t
= makeWild();
1069 //printf("\t%p %s\n", t, t.toChars());
1073 final Type
wildConstOf()
1075 //printf("Type::wildConstOf() %p %s\n", this, toChars());
1076 if (mod
== MODFlags
.wildconst
)
1078 if (mcache
&& mcache
.wcto
)
1080 assert(mcache
.wcto
.mod
== MODFlags
.wildconst
);
1083 Type t
= makeWildConst();
1086 //printf("\t%p %s\n", t, t.toChars());
1090 final Type
sharedWildOf()
1092 //printf("Type::sharedWildOf() %p, %s\n", this, toChars());
1093 if (mod
== (MODFlags
.shared_ | MODFlags
.wild
))
1095 if (mcache
&& mcache
.swto
)
1097 assert(mcache
.swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1100 Type t
= makeSharedWild();
1103 //printf("\t%p %s\n", t, t.toChars());
1107 final Type
sharedWildConstOf()
1109 //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars());
1110 if (mod
== (MODFlags
.shared_ | MODFlags
.wildconst
))
1112 if (mcache
&& mcache
.swcto
)
1114 assert(mcache
.swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1115 return mcache
.swcto
;
1117 Type t
= makeSharedWildConst();
1120 //printf("\t%p %s\n", t, t.toChars());
1124 /**********************************
1125 * For our new type 'this', which is type-constructed from t,
1126 * fill in the cto, ito, sto, scto, wto shortcuts.
1128 extern (D
) final void fixTo(Type t
)
1130 // If fixing this: immutable(T*) by t: immutable(T)*,
1131 // cache t to this.xto won't break transitivity.
1134 if (!tn || ty
!= Tsarray
&& tn
.mod
== t
.nextOf().mod
)
1142 case MODFlags
.const_
:
1152 case MODFlags
.wildconst
:
1157 case MODFlags
.shared_
:
1162 case MODFlags
.shared_ | MODFlags
.const_
:
1167 case MODFlags
.shared_ | MODFlags
.wild
:
1172 case MODFlags
.shared_ | MODFlags
.wildconst
:
1177 case MODFlags
.immutable_
:
1186 assert(mod
!= t
.mod
);
1198 case MODFlags
.const_
:
1200 t
.mcache
.cto
= this;
1205 t
.mcache
.wto
= this;
1208 case MODFlags
.wildconst
:
1210 t
.mcache
.wcto
= this;
1213 case MODFlags
.shared_
:
1215 t
.mcache
.sto
= this;
1218 case MODFlags
.shared_ | MODFlags
.const_
:
1220 t
.mcache
.scto
= this;
1223 case MODFlags
.shared_ | MODFlags
.wild
:
1225 t
.mcache
.swto
= this;
1228 case MODFlags
.shared_ | MODFlags
.wildconst
:
1230 t
.mcache
.swcto
= this;
1233 case MODFlags
.immutable_
:
1234 t
.mcache
.ito
= this;
1236 t
.mcache
.cto
.getMcache().ito
= this;
1238 t
.mcache
.sto
.getMcache().ito
= this;
1240 t
.mcache
.scto
.getMcache().ito
= this;
1242 t
.mcache
.wto
.getMcache().ito
= this;
1244 t
.mcache
.wcto
.getMcache().ito
= this;
1246 t
.mcache
.swto
.getMcache().ito
= this;
1248 t
.mcache
.swcto
.getMcache().ito
= this;
1257 //printf("fixTo: %s, %s\n", toChars(), t.toChars());
1260 /***************************
1261 * Look for bugs in constructing types.
1263 extern (D
) final void check()
1271 assert(cto
.mod
== MODFlags
.const_
);
1273 assert(ito
.mod
== MODFlags
.immutable_
);
1275 assert(sto
.mod
== MODFlags
.shared_
);
1277 assert(scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1279 assert(wto
.mod
== MODFlags
.wild
);
1281 assert(wcto
.mod
== MODFlags
.wildconst
);
1283 assert(swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1285 assert(swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1288 case MODFlags
.const_
:
1290 assert(cto
.mod
== 0);
1292 assert(ito
.mod
== MODFlags
.immutable_
);
1294 assert(sto
.mod
== MODFlags
.shared_
);
1296 assert(scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1298 assert(wto
.mod
== MODFlags
.wild
);
1300 assert(wcto
.mod
== MODFlags
.wildconst
);
1302 assert(swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1304 assert(swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1309 assert(cto
.mod
== MODFlags
.const_
);
1311 assert(ito
.mod
== MODFlags
.immutable_
);
1313 assert(sto
.mod
== MODFlags
.shared_
);
1315 assert(scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1317 assert(wto
.mod
== 0);
1319 assert(wcto
.mod
== MODFlags
.wildconst
);
1321 assert(swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1323 assert(swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1326 case MODFlags
.wildconst
:
1327 assert(!cto || cto
.mod
== MODFlags
.const_
);
1328 assert(!ito || ito
.mod
== MODFlags
.immutable_
);
1329 assert(!sto || sto
.mod
== MODFlags
.shared_
);
1330 assert(!scto || scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1331 assert(!wto || wto
.mod
== MODFlags
.wild
);
1332 assert(!wcto || wcto
.mod
== 0);
1333 assert(!swto || swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1334 assert(!swcto || swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1337 case MODFlags
.shared_
:
1339 assert(cto
.mod
== MODFlags
.const_
);
1341 assert(ito
.mod
== MODFlags
.immutable_
);
1343 assert(sto
.mod
== 0);
1345 assert(scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1347 assert(wto
.mod
== MODFlags
.wild
);
1349 assert(wcto
.mod
== MODFlags
.wildconst
);
1351 assert(swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1353 assert(swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1356 case MODFlags
.shared_ | MODFlags
.const_
:
1358 assert(cto
.mod
== MODFlags
.const_
);
1360 assert(ito
.mod
== MODFlags
.immutable_
);
1362 assert(sto
.mod
== MODFlags
.shared_
);
1364 assert(scto
.mod
== 0);
1366 assert(wto
.mod
== MODFlags
.wild
);
1368 assert(wcto
.mod
== MODFlags
.wildconst
);
1370 assert(swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1372 assert(swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1375 case MODFlags
.shared_ | MODFlags
.wild
:
1377 assert(cto
.mod
== MODFlags
.const_
);
1379 assert(ito
.mod
== MODFlags
.immutable_
);
1381 assert(sto
.mod
== MODFlags
.shared_
);
1383 assert(scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1385 assert(wto
.mod
== MODFlags
.wild
);
1387 assert(wcto
.mod
== MODFlags
.wildconst
);
1389 assert(swto
.mod
== 0);
1391 assert(swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1394 case MODFlags
.shared_ | MODFlags
.wildconst
:
1395 assert(!cto || cto
.mod
== MODFlags
.const_
);
1396 assert(!ito || ito
.mod
== MODFlags
.immutable_
);
1397 assert(!sto || sto
.mod
== MODFlags
.shared_
);
1398 assert(!scto || scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1399 assert(!wto || wto
.mod
== MODFlags
.wild
);
1400 assert(!wcto || wcto
.mod
== MODFlags
.wildconst
);
1401 assert(!swto || swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1402 assert(!swcto || swcto
.mod
== 0);
1405 case MODFlags
.immutable_
:
1407 assert(cto
.mod
== MODFlags
.const_
);
1409 assert(ito
.mod
== 0);
1411 assert(sto
.mod
== MODFlags
.shared_
);
1413 assert(scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
1415 assert(wto
.mod
== MODFlags
.wild
);
1417 assert(wcto
.mod
== MODFlags
.wildconst
);
1419 assert(swto
.mod
== (MODFlags
.shared_ | MODFlags
.wild
));
1421 assert(swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
1429 if (tn
&& ty
!= Tfunction
&& tn
.ty
!= Tfunction
&& ty
!= Tenum
)
1431 // Verify transitivity
1435 case MODFlags
.const_
:
1437 case MODFlags
.wildconst
:
1438 case MODFlags
.shared_
:
1439 case MODFlags
.shared_ | MODFlags
.const_
:
1440 case MODFlags
.shared_ | MODFlags
.wild
:
1441 case MODFlags
.shared_ | MODFlags
.wildconst
:
1442 case MODFlags
.immutable_
:
1443 assert(tn
.mod
== MODFlags
.immutable_ ||
(tn
.mod
& mod
) == mod
);
1453 /*************************************
1454 * Apply STCxxxx bits to existing type.
1455 * Use *before* semantic analysis is run.
1457 extern (D
) final Type
addSTC(StorageClass
stc)
1460 if (t
.isImmutable())
1463 else if (stc & STC
.immutable_
)
1465 t
= t
.makeImmutable();
1469 if ((stc & STC
.shared_
) && !t
.isShared())
1474 t
= t
.makeSharedWildConst();
1476 t
= t
.makeSharedWild();
1481 t
= t
.makeSharedConst();
1486 if ((stc & STC
.const_
) && !t
.isConst())
1491 t
= t
.makeSharedWildConst();
1493 t
= t
.makeSharedConst();
1498 t
= t
.makeWildConst();
1503 if ((stc & STC
.wild
) && !t
.isWild())
1508 t
= t
.makeSharedWildConst();
1510 t
= t
.makeSharedWild();
1515 t
= t
.makeWildConst();
1524 /************************************
1525 * Apply MODxxxx bits to existing type.
1527 final Type
castMod(MOD mod
)
1533 t
= unSharedOf().mutableOf();
1536 case MODFlags
.const_
:
1537 t
= unSharedOf().constOf();
1541 t
= unSharedOf().wildOf();
1544 case MODFlags
.wildconst
:
1545 t
= unSharedOf().wildConstOf();
1548 case MODFlags
.shared_
:
1549 t
= mutableOf().sharedOf();
1552 case MODFlags
.shared_ | MODFlags
.const_
:
1553 t
= sharedConstOf();
1556 case MODFlags
.shared_ | MODFlags
.wild
:
1560 case MODFlags
.shared_ | MODFlags
.wildconst
:
1561 t
= sharedWildConstOf();
1564 case MODFlags
.immutable_
:
1574 /************************************
1575 * Add MODxxxx bits to existing type.
1576 * We're adding, not replacing, so adding const to
1577 * a shared type => "shared const"
1579 final Type
addMod(MOD mod
)
1581 /* Add anything to immutable, and it remains immutable
1584 if (!t
.isImmutable())
1586 //printf("addMod(%x) %s\n", mod, toChars());
1592 case MODFlags
.const_
:
1596 t
= sharedWildConstOf();
1598 t
= sharedConstOf();
1613 t
= sharedWildConstOf();
1626 case MODFlags
.wildconst
:
1628 t
= sharedWildConstOf();
1633 case MODFlags
.shared_
:
1637 t
= sharedWildConstOf();
1644 t
= sharedConstOf();
1650 case MODFlags
.shared_ | MODFlags
.const_
:
1652 t
= sharedWildConstOf();
1654 t
= sharedConstOf();
1657 case MODFlags
.shared_ | MODFlags
.wild
:
1659 t
= sharedWildConstOf();
1664 case MODFlags
.shared_ | MODFlags
.wildconst
:
1665 t
= sharedWildConstOf();
1668 case MODFlags
.immutable_
:
1679 /************************************
1680 * Add storage class modifiers to type.
1682 Type
addStorageClass(StorageClass
stc)
1684 /* Just translate to MOD bits and let addMod() do the work
1687 if (stc & STC
.immutable_
)
1688 mod
= MODFlags
.immutable_
;
1691 if (stc & (STC
.const_ | STC
.in_
))
1692 mod |
= MODFlags
.const_
;
1694 mod |
= MODFlags
.wild
;
1695 if (stc & STC
.shared_
)
1696 mod |
= MODFlags
.shared_
;
1701 final Type
pointerTo()
1707 Type t
= new TypePointer(this);
1708 if (ty
== Tfunction
)
1710 t
.deco
= t
.merge().deco
;
1719 final Type
referenceTo()
1725 Type t
= new TypeReference(this);
1731 final Type
arrayOf()
1737 Type t
= new TypeDArray(this);
1738 arrayof
= t
.merge();
1743 // Make corresponding static array type without semantic
1744 final Type
sarrayOf(dinteger_t dim
)
1747 Type t
= new TypeSArray(this, new IntegerExp(Loc
.initial
, dim
, Type
.tsize_t
));
1748 // according to TypeSArray::semantic()
1754 final bool hasDeprecatedAliasThis()
1756 auto ad
= isAggregate(this);
1757 return ad
&& ad
.aliasthis
&& (ad
.aliasthis
.isDeprecated || ad
.aliasthis
.sym
.isDeprecated
);
1760 final Type
aliasthisOf()
1762 auto ad
= isAggregate(this);
1763 if (!ad ||
!ad
.aliasthis
)
1766 auto s
= ad
.aliasthis
.sym
;
1767 if (s
.isAliasDeclaration())
1770 if (s
.isTupleDeclaration())
1773 if (auto vd
= s
.isVarDeclaration())
1777 t
= t
.addMod(this.mod
);
1780 Dsymbol callable
= s
.isFuncDeclaration();
1781 callable
= callable ? callable
: s
.isTemplateDeclaration();
1784 auto fd
= resolveFuncCall(Loc
.initial
, null, callable
, null, this, ArgumentList(), FuncResolveFlag
.quiet
);
1785 if (!fd || fd
.errors ||
!fd
.functionSemantic())
1788 auto t
= fd
.type
.nextOf();
1789 if (!t
) // https://issues.dlang.org/show_bug.cgi?id=14185
1791 t
= t
.substWildTo(mod
== 0 ? MODFlags
.mutable
: mod
);
1794 if (auto d
= s
.isDeclaration())
1799 if (auto ed
= s
.isEnumDeclaration())
1804 //printf("%s\n", s.kind());
1809 * Check whether this type has endless `alias this` recursion.
1811 * `true` if this type has an `alias this` that can be implicitly
1812 * converted back to this type itself.
1814 extern (D
) final bool checkAliasThisRec()
1816 Type tb
= toBasetype();
1817 AliasThisRec
* pflag
;
1818 if (tb
.ty
== Tstruct
)
1819 pflag
= &(cast(TypeStruct
)tb
).att
;
1820 else if (tb
.ty
== Tclass
)
1821 pflag
= &(cast(TypeClass
)tb
).att
;
1825 AliasThisRec flag
= cast(AliasThisRec
)(*pflag
& AliasThisRec
.typeMask
);
1826 if (flag
== AliasThisRec
.fwdref
)
1828 Type att
= aliasthisOf();
1829 flag
= att
&& att
.implicitConvTo(this) ? AliasThisRec
.yes
: AliasThisRec
.no
;
1831 *pflag
= cast(AliasThisRec
)(flag |
(*pflag
& ~AliasThisRec
.typeMask
));
1832 return flag
== AliasThisRec
.yes
;
1837 //printf("Type::makeConst() %p, %s\n", this, toChars());
1838 if (mcache
&& mcache
.cto
)
1840 Type t
= this.nullAttributes();
1841 t
.mod
= MODFlags
.const_
;
1842 //printf("-Type::makeConst() %p, %s\n", t, toChars());
1846 Type
makeImmutable()
1848 if (mcache
&& mcache
.ito
)
1850 Type t
= this.nullAttributes();
1851 t
.mod
= MODFlags
.immutable_
;
1857 if (mcache
&& mcache
.sto
)
1859 Type t
= this.nullAttributes();
1860 t
.mod
= MODFlags
.shared_
;
1864 Type
makeSharedConst()
1866 if (mcache
&& mcache
.scto
)
1868 Type t
= this.nullAttributes();
1869 t
.mod
= MODFlags
.shared_ | MODFlags
.const_
;
1875 if (mcache
&& mcache
.wto
)
1877 Type t
= this.nullAttributes();
1878 t
.mod
= MODFlags
.wild
;
1882 Type
makeWildConst()
1884 if (mcache
&& mcache
.wcto
)
1886 Type t
= this.nullAttributes();
1887 t
.mod
= MODFlags
.wildconst
;
1891 Type
makeSharedWild()
1893 if (mcache
&& mcache
.swto
)
1895 Type t
= this.nullAttributes();
1896 t
.mod
= MODFlags
.shared_ | MODFlags
.wild
;
1900 Type
makeSharedWildConst()
1902 if (mcache
&& mcache
.swcto
)
1903 return mcache
.swcto
;
1904 Type t
= this.nullAttributes();
1905 t
.mod
= MODFlags
.shared_ | MODFlags
.wildconst
;
1911 Type t
= this.nullAttributes();
1912 t
.mod
= mod
& MODFlags
.shared_
;
1916 Dsymbol
toDsymbol(Scope
* sc
)
1921 /*******************************
1922 * If this is a shell around another type,
1923 * get that other type.
1925 final Type
toBasetype()
1927 /* This function is used heavily.
1928 * De-virtualize it so it can be easily inlined.
1931 return ((te
= isTypeEnum()) !is null) ? te
.toBasetype2() : this;
1934 bool isBaseOf(Type t
, int* poffset
)
1936 return 0; // assume not
1939 /********************************
1940 * Determine if 'this' can be implicitly converted
1943 * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
1945 MATCH
implicitConvTo(Type to
)
1947 //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
1948 //printf("from: %s\n", toChars());
1949 //printf("to : %s\n", to.toChars());
1950 if (this.equals(to
))
1952 return MATCH
.nomatch
;
1955 /*******************************
1956 * Determine if converting 'this' to 'to' is an identity operation,
1957 * a conversion to const operation, or the types aren't the same.
1959 * MATCH.exact 'this' == 'to'
1960 * MATCH.constant 'to' is const
1961 * MATCH.nomatch conversion to mutable or invariant
1963 MATCH
constConv(Type to
)
1965 //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars());
1968 if (ty
== to
.ty
&& MODimplicitConv(mod
, to
.mod
))
1969 return MATCH
.constant
;
1970 return MATCH
.nomatch
;
1973 /***************************************
1974 * Compute MOD bits matching `this` argument type to wild parameter type.
1976 * t = corresponding parameter type
1977 * isRef = parameter is `ref` or `out`
1981 MOD
deduceWild(Type t
, bool isRef
)
1983 //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm.toChars());
1987 return MODFlags
.immutable_
;
1988 else if (isWildConst())
1990 if (t
.isWildConst())
1991 return MODFlags
.wild
;
1993 return MODFlags
.wildconst
;
1996 return MODFlags
.wild
;
1998 return MODFlags
.const_
;
1999 else if (isMutable())
2000 return MODFlags
.mutable
;
2007 Type
substWildTo(uint mod
)
2009 //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
2012 if (Type tn
= nextOf())
2014 // substitution has no effect on function pointer type.
2015 if (ty
== Tpointer
&& tn
.ty
== Tfunction
)
2021 t
= tn
.substWildTo(mod
);
2028 else if (ty
== Tarray
)
2030 else if (ty
== Tsarray
)
2031 t
= new TypeSArray(t
, (cast(TypeSArray
)this).dim
.syntaxCopy());
2032 else if (ty
== Taarray
)
2034 t
= new TypeAArray(t
, (cast(TypeAArray
)this).index
.syntaxCopy());
2036 else if (ty
== Tdelegate
)
2038 t
= new TypeDelegate(t
.isTypeFunction());
2052 if (mod
== MODFlags
.immutable_
)
2054 t
= t
.immutableOf();
2056 else if (mod
== MODFlags
.wildconst
)
2058 t
= t
.wildConstOf();
2060 else if (mod
== MODFlags
.wild
)
2063 t
= t
.wildConstOf();
2067 else if (mod
== MODFlags
.const_
)
2080 t
= t
.addMod(MODFlags
.const_
);
2082 t
= t
.addMod(MODFlags
.shared_
);
2084 //printf("-Type::substWildTo t = %s\n", t.toChars());
2088 final Type
unqualify(uint m
)
2090 Type t
= mutableOf().unSharedOf();
2092 Type tn
= ty
== Tenum ?
null : nextOf();
2093 if (tn
&& tn
.ty
!= Tfunction
)
2095 Type utn
= tn
.unqualify(m
);
2099 t
= utn
.pointerTo();
2100 else if (ty
== Tarray
)
2102 else if (ty
== Tsarray
)
2103 t
= new TypeSArray(utn
, (cast(TypeSArray
)this).dim
);
2104 else if (ty
== Taarray
)
2106 t
= new TypeAArray(utn
, (cast(TypeAArray
)this).index
);
2114 t
= t
.addMod(mod
& ~m
);
2118 /**************************
2119 * Return type with the top level of it being mutable.
2121 inout(Type
) toHeadMutable() inout
2125 Type unqualThis
= cast(Type
) this;
2126 // `mutableOf` needs a mutable `this` only for caching
2127 return cast(inout(Type
)) unqualThis
.mutableOf();
2130 inout(ClassDeclaration
) isClassHandle() inout
2135 /************************************
2136 * Return alignment to use for this type.
2138 structalign_t
alignment()
2145 /***************************************
2146 * Use when we prefer the default initializer to be a literal,
2147 * rather than a global immutable variable.
2149 Expression
defaultInitLiteral(const ref Loc loc
)
2151 static if (LOGDEFAULTINIT
)
2153 printf("Type::defaultInitLiteral() '%s'\n", toChars());
2155 return defaultInit(this, loc
);
2158 // if initializer is 0
2159 bool isZeroInit(const ref Loc loc
)
2161 return false; // assume not
2164 final Identifier
getTypeInfoIdent()
2166 // _init_10TypeInfo_%s
2169 mangleToBuffer(this, buf
);
2171 const slice
= buf
[];
2173 // Allocate buffer on stack, fail over to using malloc()
2175 const namelen
= 19 + size_t
.sizeof
* 3 + slice
.length
+ 1;
2176 auto name
= namelen
<= namebuf
.length ? namebuf
.ptr
: cast(char*)Mem
.check(malloc(namelen
));
2178 const length
= snprintf(name
, namelen
, "_D%lluTypeInfo_%.*s6__initZ",
2179 cast(ulong)(9 + slice
.length
), cast(int)slice
.length
, slice
.ptr
);
2180 //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
2181 assert(0 < length
&& length
< namelen
); // don't overflow the buffer
2183 auto id
= Identifier
.idPool(name
[0 .. length
]);
2185 if (name
!= namebuf
.ptr
)
2190 /***************************************
2191 * Return !=0 if the type or any of its subtypes is wild.
2195 return mod
& MODFlags
.wild
;
2198 /***************************************
2199 * Return !=0 if type has pointers that need to
2200 * be scanned by the GC during a collection cycle.
2204 //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
2208 /*************************************
2209 * Detect if type has pointer fields that are initialized to void.
2210 * Local stack variables with such void fields can remain uninitialized,
2211 * leading to pointer bugs.
2215 bool hasVoidInitPointers()
2220 /*************************************
2221 * Detect if this is an unsafe type because of the presence of `@system` members
2225 bool hasSystemFields()
2230 /***************************************
2231 * Returns: true if type has any invariants
2235 //printf("Type::hasInvariant() %s, %d\n", toChars(), ty);
2239 /*************************************
2240 * If this is a type of something, return that something.
2247 /*************************************
2248 * If this is a type of static array, return its base element type.
2250 final Type
baseElemOf()
2252 Type t
= toBasetype();
2254 while ((tsa
= t
.isTypeSArray()) !is null)
2255 t
= tsa
.next
.toBasetype();
2259 /*******************************************
2260 * Compute number of elements for a (possibly multidimensional) static array,
2261 * or 1 for other types.
2263 * loc = for error message
2265 * number of elements, uint.max on overflow
2267 final uint numberOfElems(const ref Loc loc
)
2269 //printf("Type::numberOfElems()\n");
2272 while ((tb
= tb
.toBasetype()).ty
== Tsarray
)
2274 bool overflow
= false;
2275 n
= mulu(n
, (cast(TypeSArray
)tb
).dim
.toUInteger(), overflow
);
2276 if (overflow || n
>= uint.max
)
2278 error(loc
, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n
);
2281 tb
= (cast(TypeSArray
)tb
).next
;
2286 /****************************************
2287 * Return the mask that an integral type will
2290 extern (D
) final uinteger_t
sizemask()
2293 switch (toBasetype().ty
)
2315 m
= 0xFFFFFFFFFFFFFFFFUL
;
2323 /********************************
2324 * true if when type goes out of scope, it needs a destructor applied.
2325 * Only applies to value types, not ref types.
2327 bool needsDestruction()
2332 /********************************
2333 * true if when type is copied, it needs a copy constructor or postblit
2334 * applied. Only applies to value types, not ref types.
2336 bool needsCopyOrPostblit()
2341 /*********************************
2349 /*************************************
2350 * https://issues.dlang.org/show_bug.cgi?id=14488
2351 * Check if the inner most base type is complex or imaginary.
2352 * Should only give alerts when set to emit transitional messages.
2354 * loc = The source location.
2355 * sc = scope of the type
2357 extern (D
) final bool checkComplexTransition(const ref Loc loc
, Scope
* sc
)
2359 if (sc
.isDeprecated())
2361 // Don't complain if we're inside a template constraint
2362 // https://issues.dlang.org/show_bug.cgi?id=21831
2363 if (sc
.flags
& SCOPE
.constraint
)
2366 Type t
= baseElemOf();
2367 while (t
.ty
== Tpointer || t
.ty
== Tarray
)
2368 t
= t
.nextOf().baseElemOf();
2370 // Basetype is an opaque enum, nothing to check.
2371 if (t
.ty
== Tenum
&& !(cast(TypeEnum
)t
).sym
.memtype
)
2374 if (t
.isimaginary() || t
.iscomplex())
2376 if (sc
.flags
& SCOPE
.Cfile
)
2377 return true; // complex/imaginary not deprecated in C code
2399 // @@@DEPRECATED_2.117@@@
2400 // Deprecated in 2.097 - Can be made an error from 2.117.
2401 // The deprecation period is longer than usual as `cfloat`,
2402 // `cdouble`, and `creal` were quite widely used.
2405 deprecation(loc
, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
2406 toChars(), rt
.toChars());
2411 deprecation(loc
, "use of imaginary type `%s` is deprecated, use `%s` instead",
2412 toChars(), rt
.toChars());
2419 // For eliminating dynamic_cast
2420 TypeBasic
isTypeBasic()
2425 final pure inout nothrow @nogc
2428 * Is this type a pointer to a function?
2430 * the function type if it is
2432 inout(TypeFunction
) isPtrToFunction()
2434 return (ty
== Tpointer
&& (cast(TypePointer
)this).next
.ty
== Tfunction
)
2435 ?
cast(typeof(return))(cast(TypePointer
)this).next
2440 * Is this type a function, delegate, or pointer to a function?
2442 * the function type if it is
2444 inout(TypeFunction
) isFunction_Delegate_PtrToFunction()
2446 return ty
== Tfunction ?
cast(typeof(return))this :
2448 ty
== Tdelegate ?
cast(typeof(return))(cast(TypePointer
)this).next
:
2450 ty
== Tpointer
&& (cast(TypePointer
)this).next
.ty
== Tfunction ?
2451 cast(typeof(return))(cast(TypePointer
)this).next
:
2457 final pure inout nothrow @nogc @safe
2459 inout(TypeError
) isTypeError() { return ty
== Terror ?
cast(typeof(return))this : null; }
2460 inout(TypeVector
) isTypeVector() { return ty
== Tvector ?
cast(typeof(return))this : null; }
2461 inout(TypeSArray
) isTypeSArray() { return ty
== Tsarray ?
cast(typeof(return))this : null; }
2462 inout(TypeDArray
) isTypeDArray() { return ty
== Tarray ?
cast(typeof(return))this : null; }
2463 inout(TypeAArray
) isTypeAArray() { return ty
== Taarray ?
cast(typeof(return))this : null; }
2464 inout(TypePointer
) isTypePointer() { return ty
== Tpointer ?
cast(typeof(return))this : null; }
2465 inout(TypeReference
) isTypeReference() { return ty
== Treference ?
cast(typeof(return))this : null; }
2466 inout(TypeFunction
) isTypeFunction() { return ty
== Tfunction ?
cast(typeof(return))this : null; }
2467 inout(TypeDelegate
) isTypeDelegate() { return ty
== Tdelegate ?
cast(typeof(return))this : null; }
2468 inout(TypeIdentifier
) isTypeIdentifier() { return ty
== Tident ?
cast(typeof(return))this : null; }
2469 inout(TypeInstance
) isTypeInstance() { return ty
== Tinstance ?
cast(typeof(return))this : null; }
2470 inout(TypeTypeof
) isTypeTypeof() { return ty
== Ttypeof ?
cast(typeof(return))this : null; }
2471 inout(TypeReturn
) isTypeReturn() { return ty
== Treturn ?
cast(typeof(return))this : null; }
2472 inout(TypeStruct
) isTypeStruct() { return ty
== Tstruct ?
cast(typeof(return))this : null; }
2473 inout(TypeEnum
) isTypeEnum() { return ty
== Tenum ?
cast(typeof(return))this : null; }
2474 inout(TypeClass
) isTypeClass() { return ty
== Tclass ?
cast(typeof(return))this : null; }
2475 inout(TypeTuple
) isTypeTuple() { return ty
== Ttuple ?
cast(typeof(return))this : null; }
2476 inout(TypeSlice
) isTypeSlice() { return ty
== Tslice ?
cast(typeof(return))this : null; }
2477 inout(TypeNull
) isTypeNull() { return ty
== Tnull ?
cast(typeof(return))this : null; }
2478 inout(TypeMixin
) isTypeMixin() { return ty
== Tmixin ?
cast(typeof(return))this : null; }
2479 inout(TypeTraits
) isTypeTraits() { return ty
== Ttraits ?
cast(typeof(return))this : null; }
2480 inout(TypeNoreturn
) isTypeNoreturn() { return ty
== Tnoreturn ?
cast(typeof(return))this : null; }
2481 inout(TypeTag
) isTypeTag() { return ty
== Ttag ?
cast(typeof(return))this : null; }
2484 override void accept(Visitor v
)
2489 final TypeFunction
toTypeFunction()
2491 if (ty
!= Tfunction
)
2493 return cast(TypeFunction
)this;
2496 extern (D
) static Types
* arraySyntaxCopy(Types
* types
)
2501 a
= new Types(types
.length
);
2502 foreach (i
, t
; *types
)
2504 (*a
)[i
] = t ? t
.syntaxCopy() : null;
2511 /***********************************************************
2513 extern (C
++) final class TypeError
: Type
2515 extern (D
) this() @safe
2520 override const(char)* kind() const
2525 override TypeError
syntaxCopy()
2527 // No semantic analysis done, no need to copy
2531 override uinteger_t
size(const ref Loc loc
)
2533 return SIZE_INVALID
;
2536 override Expression
defaultInitLiteral(const ref Loc loc
)
2538 return ErrorExp
.get();
2541 override void accept(Visitor v
)
2547 /***********************************************************
2549 extern (C
++) abstract class TypeNext
: Type
2553 final extern (D
) this(TY ty
, Type next
) @safe
2559 override final int hasWild() const
2561 if (ty
== Tfunction
)
2563 if (ty
== Tdelegate
)
2564 return Type
.hasWild();
2565 return mod
& MODFlags
.wild ||
(next
&& next
.hasWild());
2568 /*******************************
2569 * For TypeFunction, nextOf() can return NULL if the function return
2570 * type is meant to be inferred, and semantic() hasn't yet ben run
2571 * on the function. After semantic(), it must no longer be NULL.
2573 override final Type
nextOf()
2578 override final Type
makeConst()
2580 //printf("TypeNext::makeConst() %p, %s\n", this, toChars());
2581 if (mcache
&& mcache
.cto
)
2583 assert(mcache
.cto
.mod
== MODFlags
.const_
);
2586 TypeNext t
= cast(TypeNext
)Type
.makeConst();
2587 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2589 if (next
.isShared())
2592 t
.next
= next
.sharedWildConstOf();
2594 t
.next
= next
.sharedConstOf();
2599 t
.next
= next
.wildConstOf();
2601 t
.next
= next
.constOf();
2604 //printf("TypeNext::makeConst() returns %p, %s\n", t, t.toChars());
2608 override final Type
makeImmutable()
2610 //printf("TypeNext::makeImmutable() %s\n", toChars());
2611 if (mcache
&& mcache
.ito
)
2613 assert(mcache
.ito
.isImmutable());
2616 TypeNext t
= cast(TypeNext
)Type
.makeImmutable();
2617 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2619 t
.next
= next
.immutableOf();
2624 override final Type
makeShared()
2626 //printf("TypeNext::makeShared() %s\n", toChars());
2627 if (mcache
&& mcache
.sto
)
2629 assert(mcache
.sto
.mod
== MODFlags
.shared_
);
2632 TypeNext t
= cast(TypeNext
)Type
.makeShared();
2633 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2638 t
.next
= next
.sharedWildConstOf();
2640 t
.next
= next
.sharedWildOf();
2645 t
.next
= next
.sharedConstOf();
2647 t
.next
= next
.sharedOf();
2650 //printf("TypeNext::makeShared() returns %p, %s\n", t, t.toChars());
2654 override final Type
makeSharedConst()
2656 //printf("TypeNext::makeSharedConst() %s\n", toChars());
2657 if (mcache
&& mcache
.scto
)
2659 assert(mcache
.scto
.mod
== (MODFlags
.shared_ | MODFlags
.const_
));
2662 TypeNext t
= cast(TypeNext
)Type
.makeSharedConst();
2663 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2666 t
.next
= next
.sharedWildConstOf();
2668 t
.next
= next
.sharedConstOf();
2670 //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t.toChars());
2674 override final Type
makeWild()
2676 //printf("TypeNext::makeWild() %s\n", toChars());
2677 if (mcache
&& mcache
.wto
)
2679 assert(mcache
.wto
.mod
== MODFlags
.wild
);
2682 TypeNext t
= cast(TypeNext
)Type
.makeWild();
2683 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2685 if (next
.isShared())
2688 t
.next
= next
.sharedWildConstOf();
2690 t
.next
= next
.sharedWildOf();
2695 t
.next
= next
.wildConstOf();
2697 t
.next
= next
.wildOf();
2700 //printf("TypeNext::makeWild() returns %p, %s\n", t, t.toChars());
2704 override final Type
makeWildConst()
2706 //printf("TypeNext::makeWildConst() %s\n", toChars());
2707 if (mcache
&& mcache
.wcto
)
2709 assert(mcache
.wcto
.mod
== MODFlags
.wildconst
);
2712 TypeNext t
= cast(TypeNext
)Type
.makeWildConst();
2713 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2715 if (next
.isShared())
2716 t
.next
= next
.sharedWildConstOf();
2718 t
.next
= next
.wildConstOf();
2720 //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t.toChars());
2724 override final Type
makeSharedWild()
2726 //printf("TypeNext::makeSharedWild() %s\n", toChars());
2727 if (mcache
&& mcache
.swto
)
2729 assert(mcache
.swto
.isSharedWild());
2732 TypeNext t
= cast(TypeNext
)Type
.makeSharedWild();
2733 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2736 t
.next
= next
.sharedWildConstOf();
2738 t
.next
= next
.sharedWildOf();
2740 //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t.toChars());
2744 override final Type
makeSharedWildConst()
2746 //printf("TypeNext::makeSharedWildConst() %s\n", toChars());
2747 if (mcache
&& mcache
.swcto
)
2749 assert(mcache
.swcto
.mod
== (MODFlags
.shared_ | MODFlags
.wildconst
));
2750 return mcache
.swcto
;
2752 TypeNext t
= cast(TypeNext
)Type
.makeSharedWildConst();
2753 if (ty
!= Tfunction
&& next
.ty
!= Tfunction
&& !next
.isImmutable())
2755 t
.next
= next
.sharedWildConstOf();
2757 //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t.toChars());
2761 override final Type
makeMutable()
2763 //printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
2764 TypeNext t
= cast(TypeNext
)Type
.makeMutable();
2767 t
.next
= next
.mutableOf();
2769 //printf("TypeNext::makeMutable() returns %p, %s\n", t, t.toChars());
2773 override MATCH
constConv(Type to
)
2775 //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars());
2779 if (!(ty
== to
.ty
&& MODimplicitConv(mod
, to
.mod
)))
2780 return MATCH
.nomatch
;
2782 Type tn
= to
.nextOf();
2783 if (!(tn
&& next
.ty
== tn
.ty
))
2784 return MATCH
.nomatch
;
2787 if (to
.isConst()) // whole tail const conversion
2789 // Recursive shared level check
2790 m
= next
.constConv(tn
);
2791 if (m
== MATCH
.exact
)
2796 //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars());
2797 m
= next
.equals(tn
) ? MATCH
.constant
: MATCH
.nomatch
;
2802 override final MOD
deduceWild(Type t
, bool isRef
)
2804 if (ty
== Tfunction
)
2809 Type tn
= t
.nextOf();
2810 if (!isRef
&& (ty
== Tarray || ty
== Tpointer
) && tn
)
2812 wm
= next
.deduceWild(tn
, true);
2814 wm
= Type
.deduceWild(t
, true);
2818 wm
= Type
.deduceWild(t
, isRef
);
2820 wm
= next
.deduceWild(tn
, true);
2826 final void transitive()
2828 /* Invoke transitivity of type attributes
2830 next
= next
.addMod(mod
);
2833 override void accept(Visitor v
)
2839 /***********************************************************
2841 extern (C
++) final class TypeBasic
: Type
2843 const(char)* dstring
;
2846 extern (D
) this(TY ty
) scope
2854 d
= Token
.toChars(TOK
.void_
);
2858 d
= Token
.toChars(TOK
.int8
);
2859 flags |
= TFlags
.integral
;
2863 d
= Token
.toChars(TOK
.uns8
);
2864 flags |
= TFlags
.integral | TFlags
.unsigned
;
2868 d
= Token
.toChars(TOK
.int16
);
2869 flags |
= TFlags
.integral
;
2873 d
= Token
.toChars(TOK
.uns16
);
2874 flags |
= TFlags
.integral | TFlags
.unsigned
;
2878 d
= Token
.toChars(TOK
.int32
);
2879 flags |
= TFlags
.integral
;
2883 d
= Token
.toChars(TOK
.uns32
);
2884 flags |
= TFlags
.integral | TFlags
.unsigned
;
2888 d
= Token
.toChars(TOK
.float32
);
2889 flags |
= TFlags
.floating | TFlags
.real_
;
2893 d
= Token
.toChars(TOK
.int64
);
2894 flags |
= TFlags
.integral
;
2898 d
= Token
.toChars(TOK
.uns64
);
2899 flags |
= TFlags
.integral | TFlags
.unsigned
;
2903 d
= Token
.toChars(TOK
.int128
);
2904 flags |
= TFlags
.integral
;
2908 d
= Token
.toChars(TOK
.uns128
);
2909 flags |
= TFlags
.integral | TFlags
.unsigned
;
2913 d
= Token
.toChars(TOK
.float64
);
2914 flags |
= TFlags
.floating | TFlags
.real_
;
2918 d
= Token
.toChars(TOK
.float80
);
2919 flags |
= TFlags
.floating | TFlags
.real_
;
2923 d
= Token
.toChars(TOK
.imaginary32
);
2924 flags |
= TFlags
.floating | TFlags
.imaginary
;
2928 d
= Token
.toChars(TOK
.imaginary64
);
2929 flags |
= TFlags
.floating | TFlags
.imaginary
;
2933 d
= Token
.toChars(TOK
.imaginary80
);
2934 flags |
= TFlags
.floating | TFlags
.imaginary
;
2938 d
= Token
.toChars(TOK
.complex32
);
2939 flags |
= TFlags
.floating | TFlags
.complex
;
2943 d
= Token
.toChars(TOK
.complex64
);
2944 flags |
= TFlags
.floating | TFlags
.complex
;
2948 d
= Token
.toChars(TOK
.complex80
);
2949 flags |
= TFlags
.floating | TFlags
.complex
;
2954 flags |
= TFlags
.integral | TFlags
.unsigned
;
2958 d
= Token
.toChars(TOK
.char_
);
2959 flags |
= TFlags
.integral | TFlags
.unsigned
;
2963 d
= Token
.toChars(TOK
.wchar_
);
2964 flags |
= TFlags
.integral | TFlags
.unsigned
;
2968 d
= Token
.toChars(TOK
.dchar_
);
2969 flags |
= TFlags
.integral | TFlags
.unsigned
;
2980 override const(char)* kind() const
2985 override TypeBasic
syntaxCopy()
2987 // No semantic analysis done on basic types, no need to copy
2991 override uinteger_t
size(const ref Loc loc
)
2994 //printf("TypeBasic::size()\n");
3023 size
= target
.realsize
;
3037 size
= target
.realsize
* 2;
3041 //size = Type::size(); // error message
3064 //printf("TypeBasic::size() = %d\n", size);
3068 override uint alignsize()
3070 return target
.alignsize(this);
3073 override bool isintegral()
3075 //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
3076 return (flags
& TFlags
.integral
) != 0;
3079 override bool isfloating()
3081 return (flags
& TFlags
.floating
) != 0;
3084 override bool isreal()
3086 return (flags
& TFlags
.real_
) != 0;
3089 override bool isimaginary()
3091 return (flags
& TFlags
.imaginary
) != 0;
3094 override bool iscomplex()
3096 return (flags
& TFlags
.complex
) != 0;
3099 override bool isscalar()
3101 return (flags
& (TFlags
.integral | TFlags
.floating
)) != 0;
3104 override bool isunsigned()
3106 return (flags
& TFlags
.unsigned
) != 0;
3109 override MATCH
implicitConvTo(Type to
)
3111 //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
3119 else if (MODimplicitConv(mod
, to
.mod
))
3120 return MATCH
.constant
;
3121 else if (!((mod ^ to
.mod
) & MODFlags
.shared_
)) // for wild matching
3122 return MATCH
.constant
;
3124 return MATCH
.convert
;
3127 if (ty
== Tvoid || to
.ty
== Tvoid
)
3128 return MATCH
.nomatch
;
3130 return MATCH
.nomatch
;
3133 if (to
.ty
== Tvector
&& to
.deco
)
3135 TypeVector tv
= cast(TypeVector
)to
;
3136 tob
= tv
.elementType();
3138 else if (auto te
= to
.isTypeEnum())
3140 EnumDeclaration ed
= te
.sym
;
3143 /* Special enums that allow implicit conversions to them
3144 * with a MATCH.convert
3146 tob
= to
.toBasetype().isTypeBasic();
3149 return MATCH
.nomatch
;
3152 tob
= to
.isTypeBasic();
3154 return MATCH
.nomatch
;
3156 if (flags
& TFlags
.integral
)
3158 // Disallow implicit conversion of integers to imaginary or complex
3159 if (tob
.flags
& (TFlags
.imaginary | TFlags
.complex
))
3160 return MATCH
.nomatch
;
3162 // If converting from integral to integral
3163 if (tob
.flags
& TFlags
.integral
)
3165 const sz
= size(Loc
.initial
);
3166 const tosz
= tob
.size(Loc
.initial
);
3168 /* Can't convert to smaller size
3171 return MATCH
.nomatch
;
3172 /* Can't change sign if same size
3174 //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
3175 // return MATCH.nomatch;
3178 else if (flags
& TFlags
.floating
)
3180 // Disallow implicit conversion of floating point to integer
3181 if (tob
.flags
& TFlags
.integral
)
3182 return MATCH
.nomatch
;
3184 assert(tob
.flags
& TFlags
.floating || to
.ty
== Tvector
);
3186 // Disallow implicit conversion from complex to non-complex
3187 if (flags
& TFlags
.complex
&& !(tob
.flags
& TFlags
.complex
))
3188 return MATCH
.nomatch
;
3190 // Disallow implicit conversion of real or imaginary to complex
3191 if (flags
& (TFlags
.real_ | TFlags
.imaginary
) && tob
.flags
& TFlags
.complex
)
3192 return MATCH
.nomatch
;
3194 // Disallow implicit conversion to-from real and imaginary
3195 if ((flags
& (TFlags
.real_ | TFlags
.imaginary
)) != (tob
.flags
& (TFlags
.real_ | TFlags
.imaginary
)))
3196 return MATCH
.nomatch
;
3198 return MATCH
.convert
;
3201 override bool isZeroInit(const ref Loc loc
)
3223 // For eliminating dynamic_cast
3224 override TypeBasic
isTypeBasic()
3229 override void accept(Visitor v
)
3235 /***********************************************************
3236 * The basetype must be one of:
3237 * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
3239 * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4]
3241 extern (C
++) final class TypeVector
: Type
3245 extern (D
) this(Type basetype
) @safe
3248 this.basetype
= basetype
;
3251 static TypeVector
create(Type basetype
) @safe
3253 return new TypeVector(basetype
);
3256 override const(char)* kind() const
3261 override TypeVector
syntaxCopy()
3263 return new TypeVector(basetype
.syntaxCopy());
3266 override uinteger_t
size(const ref Loc loc
)
3268 return basetype
.size();
3271 override uint alignsize()
3273 return cast(uint)basetype
.size();
3276 override bool isintegral()
3278 //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
3279 return basetype
.nextOf().isintegral();
3282 override bool isfloating()
3284 return basetype
.nextOf().isfloating();
3287 override bool isscalar()
3289 return basetype
.nextOf().isscalar();
3292 override bool isunsigned()
3294 return basetype
.nextOf().isunsigned();
3297 override bool isBoolean()
3302 override MATCH
implicitConvTo(Type to
)
3304 //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
3307 if (to
.ty
!= Tvector
)
3308 return MATCH
.nomatch
;
3310 TypeVector tv
= cast(TypeVector
)to
;
3311 assert(basetype
.ty
== Tsarray
&& tv
.basetype
.ty
== Tsarray
);
3313 // Can't convert to a vector which has different size.
3314 if (basetype
.size() != tv
.basetype
.size())
3315 return MATCH
.nomatch
;
3317 // Allow conversion to void[]
3318 if (tv
.basetype
.nextOf().ty
== Tvoid
)
3319 return MATCH
.convert
;
3321 // Otherwise implicitly convertible only if basetypes are.
3322 return basetype
.implicitConvTo(tv
.basetype
);
3325 override Expression
defaultInitLiteral(const ref Loc loc
)
3327 //printf("TypeVector::defaultInitLiteral()\n");
3328 assert(basetype
.ty
== Tsarray
);
3329 Expression e
= basetype
.defaultInitLiteral(loc
);
3330 auto ve
= new VectorExp(loc
, e
, this);
3332 ve
.dim
= cast(int)(basetype
.size(loc
) / elementType().size(loc
));
3336 TypeBasic
elementType()
3338 assert(basetype
.ty
== Tsarray
);
3339 TypeSArray t
= cast(TypeSArray
)basetype
;
3340 TypeBasic tb
= t
.nextOf().isTypeBasic();
3345 override bool isZeroInit(const ref Loc loc
)
3347 return basetype
.isZeroInit(loc
);
3350 override void accept(Visitor v
)
3356 /***********************************************************
3358 extern (C
++) abstract class TypeArray
: TypeNext
3360 final extern (D
) this(TY ty
, Type next
) @safe
3365 override void accept(Visitor v
)
3371 /***********************************************************
3372 * Static array, one with a fixed dimension
3374 extern (C
++) final class TypeSArray
: TypeArray
3378 extern (D
) this(Type t
, Expression dim
) @safe
3381 //printf("TypeSArray(%s)\n", dim.toChars());
3385 extern (D
) this(Type t
) // for incomplete type
3388 //printf("TypeSArray()\n");
3389 this.dim
= new IntegerExp(0);
3392 override const(char)* kind() const
3397 override TypeSArray
syntaxCopy()
3399 Type t
= next
.syntaxCopy();
3400 Expression e
= dim
.syntaxCopy();
3401 auto result
= new TypeSArray(t
, e
);
3407 * C11 6.7.6.2-4 incomplete array type
3408 * Returns: true if incomplete type
3412 return dim
.isIntegerExp() && dim
.isIntegerExp().getInteger() == 0;
3415 override uinteger_t
size(const ref Loc loc
)
3417 //printf("TypeSArray::size()\n");
3418 const n
= numberOfElems(loc
);
3419 const elemsize
= baseElemOf().size(loc
);
3420 bool overflow
= false;
3421 const sz
= mulu(n
, elemsize
, overflow
);
3422 if (overflow || sz
>= uint.max
)
3424 if (elemsize
!= SIZE_INVALID
&& n
!= uint.max
)
3425 error(loc
, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz
);
3426 return SIZE_INVALID
;
3431 override uint alignsize()
3433 return next
.alignsize();
3436 override bool isString()
3438 TY nty
= next
.toBasetype().ty
;
3439 return nty
.isSomeChar
;
3442 override bool isZeroInit(const ref Loc loc
)
3444 return next
.isZeroInit(loc
);
3447 override structalign_t
alignment()
3449 return next
.alignment();
3452 override MATCH
constConv(Type to
)
3454 if (auto tsa
= to
.isTypeSArray())
3456 if (!dim
.equals(tsa
.dim
))
3457 return MATCH
.nomatch
;
3459 return TypeNext
.constConv(to
);
3462 override MATCH
implicitConvTo(Type to
)
3464 //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
3465 if (auto ta
= to
.isTypeDArray())
3467 if (!MODimplicitConv(next
.mod
, ta
.next
.mod
))
3468 return MATCH
.nomatch
;
3470 /* Allow conversion to void[]
3472 if (ta
.next
.ty
== Tvoid
)
3474 return MATCH
.convert
;
3477 MATCH m
= next
.constConv(ta
.next
);
3478 if (m
> MATCH
.nomatch
)
3480 return MATCH
.convert
;
3482 return MATCH
.nomatch
;
3484 if (auto tsa
= to
.isTypeSArray())
3489 if (dim
.equals(tsa
.dim
))
3491 MATCH m
= next
.implicitConvTo(tsa
.next
);
3493 /* Allow conversion to non-interface base class.
3495 if (m
== MATCH
.convert
&&
3498 if (auto toc
= tsa
.next
.isTypeClass
)
3500 if (!toc
.sym
.isInterfaceDeclaration
)
3501 return MATCH
.convert
;
3505 /* Since static arrays are value types, allow
3506 * conversions from const elements to non-const
3507 * ones, just like we allow conversion from const int
3510 if (m
>= MATCH
.constant
)
3518 return MATCH
.nomatch
;
3521 override Expression
defaultInitLiteral(const ref Loc loc
)
3523 static if (LOGDEFAULTINIT
)
3525 printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars());
3527 size_t d
= cast(size_t
)dim
.toInteger();
3528 Expression elementinit
;
3529 if (next
.ty
== Tvoid
)
3530 elementinit
= tuns8
.defaultInitLiteral(loc
);
3532 elementinit
= next
.defaultInitLiteral(loc
);
3533 auto elements
= new Expressions(d
);
3534 foreach (ref e
; *elements
)
3536 auto ae
= new ArrayLiteralExp(Loc
.initial
, this, elementinit
, elements
);
3540 override bool hasPointers()
3542 /* Don't want to do this, because:
3543 * struct S { T* array[0]; }
3544 * may be a variable length struct.
3546 //if (dim.toInteger() == 0)
3549 if (next
.ty
== Tvoid
)
3551 // Arrays of void contain arbitrary data, which may include pointers
3555 return next
.hasPointers();
3558 override bool hasSystemFields()
3560 return next
.hasSystemFields();
3563 override bool hasVoidInitPointers()
3565 return next
.hasVoidInitPointers();
3568 override bool hasInvariant()
3570 return next
.hasInvariant();
3573 override bool needsDestruction()
3575 return next
.needsDestruction();
3578 override bool needsCopyOrPostblit()
3580 return next
.needsCopyOrPostblit();
3583 /*********************************
3586 override bool needsNested()
3588 return next
.needsNested();
3591 override void accept(Visitor v
)
3597 /***********************************************************
3598 * Dynamic array, no dimension
3600 extern (C
++) final class TypeDArray
: TypeArray
3602 extern (D
) this(Type t
) @safe
3605 //printf("TypeDArray(t = %p)\n", t);
3608 override const(char)* kind() const
3613 override TypeDArray
syntaxCopy()
3615 Type t
= next
.syntaxCopy();
3619 auto result
= new TypeDArray(t
);
3624 override uinteger_t
size(const ref Loc loc
)
3626 //printf("TypeDArray::size()\n");
3627 return target
.ptrsize
* 2;
3630 override uint alignsize()
3632 // A DArray consists of two ptr-sized values, so align it on pointer size
3634 return target
.ptrsize
;
3637 override bool isString()
3639 TY nty
= next
.toBasetype().ty
;
3640 return nty
.isSomeChar
;
3643 override bool isZeroInit(const ref Loc loc
)
3648 override bool isBoolean()
3653 override MATCH
implicitConvTo(Type to
)
3655 //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
3659 if (auto ta
= to
.isTypeDArray())
3661 if (!MODimplicitConv(next
.mod
, ta
.next
.mod
))
3662 return MATCH
.nomatch
; // not const-compatible
3664 /* Allow conversion to void[]
3666 if (next
.ty
!= Tvoid
&& ta
.next
.ty
== Tvoid
)
3668 return MATCH
.convert
;
3671 MATCH m
= next
.constConv(ta
.next
);
3672 if (m
> MATCH
.nomatch
)
3674 if (m
== MATCH
.exact
&& mod
!= to
.mod
)
3679 return Type
.implicitConvTo(to
);
3682 override bool hasPointers()
3687 override void accept(Visitor v
)
3693 /***********************************************************
3695 extern (C
++) final class TypeAArray
: TypeArray
3697 Type index
; // key type
3700 extern (D
) this(Type t
, Type index
) @safe
3706 static TypeAArray
create(Type t
, Type index
) @safe
3708 return new TypeAArray(t
, index
);
3711 override const(char)* kind() const
3716 override TypeAArray
syntaxCopy()
3718 Type t
= next
.syntaxCopy();
3719 Type ti
= index
.syntaxCopy();
3720 if (t
== next
&& ti
== index
)
3723 auto result
= new TypeAArray(t
, ti
);
3728 override uinteger_t
size(const ref Loc loc
)
3730 return target
.ptrsize
;
3733 override bool isZeroInit(const ref Loc loc
)
3738 override bool isBoolean()
3743 override bool hasPointers()
3748 override MATCH
implicitConvTo(Type to
)
3750 //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
3754 if (auto ta
= to
.isTypeAArray())
3756 if (!MODimplicitConv(next
.mod
, ta
.next
.mod
))
3757 return MATCH
.nomatch
; // not const-compatible
3759 if (!MODimplicitConv(index
.mod
, ta
.index
.mod
))
3760 return MATCH
.nomatch
; // not const-compatible
3762 MATCH m
= next
.constConv(ta
.next
);
3763 MATCH mi
= index
.constConv(ta
.index
);
3764 if (m
> MATCH
.nomatch
&& mi
> MATCH
.nomatch
)
3766 return MODimplicitConv(mod
, to
.mod
) ? MATCH
.constant
: MATCH
.nomatch
;
3769 return Type
.implicitConvTo(to
);
3772 override MATCH
constConv(Type to
)
3774 if (auto taa
= to
.isTypeAArray())
3776 MATCH mindex
= index
.constConv(taa
.index
);
3777 MATCH mkey
= next
.constConv(taa
.next
);
3778 // Pick the worst match
3779 return mkey
< mindex ? mkey
: mindex
;
3781 return Type
.constConv(to
);
3784 override void accept(Visitor v
)
3790 /***********************************************************
3792 extern (C
++) final class TypePointer
: TypeNext
3794 extern (D
) this(Type t
) @safe
3799 static TypePointer
create(Type t
) @safe
3801 return new TypePointer(t
);
3804 override const(char)* kind() const
3809 override TypePointer
syntaxCopy()
3811 Type t
= next
.syntaxCopy();
3815 auto result
= new TypePointer(t
);
3820 override uinteger_t
size(const ref Loc loc
)
3822 return target
.ptrsize
;
3825 override MATCH
implicitConvTo(Type to
)
3827 //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars());
3831 // Only convert between pointers
3832 auto tp
= to
.isTypePointer();
3834 return MATCH
.nomatch
;
3839 // Conversion to void*
3840 if (tp
.next
.ty
== Tvoid
)
3842 // Function pointer conversion doesn't check constness?
3843 if (this.next
.ty
== Tfunction
)
3844 return MATCH
.convert
;
3846 if (!MODimplicitConv(next
.mod
, tp
.next
.mod
))
3847 return MATCH
.nomatch
; // not const-compatible
3849 return this.next
.ty
== Tvoid ? MATCH
.constant
: MATCH
.convert
;
3852 // Conversion between function pointers
3853 if (auto thisTf
= this.next
.isTypeFunction())
3854 return thisTf
.implicitPointerConv(tp
.next
);
3856 // Default, no implicit conversion between the pointer targets
3857 MATCH m
= next
.constConv(tp
.next
);
3859 if (m
== MATCH
.exact
&& mod
!= to
.mod
)
3864 override MATCH
constConv(Type to
)
3866 if (next
.ty
== Tfunction
)
3868 if (to
.nextOf() && next
.equals((cast(TypeNext
)to
).next
))
3869 return Type
.constConv(to
);
3871 return MATCH
.nomatch
;
3873 return TypeNext
.constConv(to
);
3876 override bool isscalar()
3881 override bool isZeroInit(const ref Loc loc
)
3886 override bool hasPointers()
3891 override void accept(Visitor v
)
3897 /***********************************************************
3899 extern (C
++) final class TypeReference
: TypeNext
3901 extern (D
) this(Type t
) @safe
3903 super(Treference
, t
);
3904 // BUG: what about references to static arrays?
3907 override const(char)* kind() const
3912 override TypeReference
syntaxCopy()
3914 Type t
= next
.syntaxCopy();
3918 auto result
= new TypeReference(t
);
3923 override uinteger_t
size(const ref Loc loc
)
3925 return target
.ptrsize
;
3928 override bool isZeroInit(const ref Loc loc
)
3933 override void accept(Visitor v
)
3941 regs
= 1, // returned in registers
3942 stack
= 2, // returned on stack
3945 enum TRUSTformat
: int
3947 TRUSTformatDefault
, // do not emit @system when trust == TRUST.default_
3948 TRUSTformatSystem
, // emit @system when trust == TRUST.default_
3951 alias TRUSTformatDefault
= TRUSTformat
.TRUSTformatDefault
;
3952 alias TRUSTformatSystem
= TRUSTformat
.TRUSTformatSystem
;
3954 /***********************************************************
3956 extern (C
++) final class TypeFunction
: TypeNext
3958 // .next is the return type
3960 ParameterList parameterList
; // function parameters
3962 // These flags can be accessed like `bool` properties,
3963 // getters and setters are generated for them
3964 private extern (D
) static struct BitFields
3966 bool isnothrow
; /// nothrow
3967 bool isnogc
; /// is @nogc
3968 bool isproperty
; /// can be called without parentheses
3969 bool isref
; /// returns a reference
3970 bool isreturn
; /// 'this' is returned by ref
3971 bool isScopeQual
; /// 'this' is scope
3972 bool isreturninferred
; /// 'this' is return from inference
3973 bool isscopeinferred
; /// 'this' is scope from inference
3974 bool islive
; /// is @live
3975 bool incomplete
; /// return type or default arguments removed
3976 bool isInOutParam
; /// inout on the parameters
3977 bool isInOutQual
; /// inout on the qualifier
3978 bool isctor
; /// the function is a constructor
3979 bool isreturnscope
; /// `this` is returned by value
3982 import dmd
.common
.bitfields
: generateBitFields
;
3983 mixin(generateBitFields
!(BitFields
, ushort));
3985 LINK linkage
; // calling convention
3986 TRUST trust
; // level of trust
3987 PURE purity
= PURE
.impure
;
3989 Expressions
* fargs
; // function arguments
3991 extern (D
) this(ParameterList pl
, Type treturn
, LINK linkage
, StorageClass
stc = 0) @safe
3993 super(Tfunction
, treturn
);
3994 //if (!treturn) *(char*)0=0;
3996 assert(VarArg
.none
<= pl
.varargs
&& pl
.varargs
<= VarArg
.max
);
3997 this.parameterList
= pl
;
3998 this.linkage
= linkage
;
4000 if (stc & STC
.pure_
)
4001 this.purity
= PURE
.fwdref
;
4002 if (stc & STC
.nothrow_
)
4003 this.isnothrow
= true;
4006 if (stc & STC
.property
)
4007 this.isproperty
= true;
4013 if (stc & STC
.return_
)
4014 this.isreturn
= true;
4015 if (stc & STC
.returnScope
)
4016 this.isreturnscope
= true;
4017 if (stc & STC
.returninferred
)
4018 this.isreturninferred
= true;
4019 if (stc & STC
.scope_
)
4020 this.isScopeQual
= true;
4021 if (stc & STC
.scopeinferred
)
4022 this.isscopeinferred
= true;
4024 this.trust
= TRUST
.default_
;
4026 this.trust
= TRUST
.safe
;
4027 else if (stc & STC
.system
)
4028 this.trust
= TRUST
.system
;
4029 else if (stc & STC
.trusted
)
4030 this.trust
= TRUST
.trusted
;
4033 static TypeFunction
create(Parameters
* parameters
, Type treturn
, ubyte varargs
, LINK linkage
, StorageClass
stc = 0) @safe
4035 return new TypeFunction(ParameterList(parameters
, cast(VarArg
)varargs
), treturn
, linkage
, stc);
4038 override const(char)* kind() const
4043 override TypeFunction
syntaxCopy()
4045 Type treturn
= next ? next
.syntaxCopy() : null;
4046 auto t
= new TypeFunction(parameterList
.syntaxCopy(), treturn
, linkage
);
4048 t
.isnothrow
= isnothrow
;
4052 t
.isproperty
= isproperty
;
4054 t
.isreturn
= isreturn
;
4055 t
.isreturnscope
= isreturnscope
;
4056 t
.isScopeQual
= isScopeQual
;
4057 t
.isreturninferred
= isreturninferred
;
4058 t
.isscopeinferred
= isscopeinferred
;
4059 t
.isInOutParam
= isInOutParam
;
4060 t
.isInOutQual
= isInOutQual
;
4067 /********************************************
4068 * Set 'purity' field of 'this'.
4069 * Do this lazily, as the parameter types might be forward referenced.
4073 TypeFunction tf
= this;
4074 if (tf
.purity
!= PURE
.fwdref
)
4077 purity
= PURE
.const_
; // assume strong until something weakens it
4079 /* Evaluate what kind of purity based on the modifiers for the parameters
4081 foreach (i
, fparam
; tf
.parameterList
)
4083 Type t
= fparam
.type
;
4087 if (fparam
.storageClass
& (STC
.lazy_ | STC
.out_
))
4092 const pref
= (fparam
.storageClass
& STC
.ref_
) != 0;
4093 if (mutabilityOfType(pref
, t
) == 0)
4100 /********************************************
4101 * Return true if there are lazy parameters.
4103 bool hasLazyParameters()
4105 foreach (i
, fparam
; parameterList
)
4107 if (fparam
.isLazy())
4113 /*******************************
4114 * Check for `extern (D) U func(T t, ...)` variadic function type,
4115 * which has `_arguments[]` added as the first argument.
4117 * true if D-style variadic
4119 bool isDstyleVariadic() const pure nothrow
4121 return linkage
== LINK
.d
&& parameterList
.varargs
== VarArg
.variadic
;
4124 /************************************
4125 * Take the specified storage class for p,
4126 * and use the function signature to infer whether
4127 * STC.scope_ and STC.return_ should be OR'd in.
4128 * (This will not affect the name mangling.)
4130 * tthis = type of `this` parameter, null if none
4131 * p = parameter to this function
4132 * outerVars = context variables p could escape into, if any
4133 * indirect = is this for an indirect or virtual function call?
4135 * storage class with STC.scope_ or STC.return_ OR'd in
4137 StorageClass
parameterStorageClass(Type tthis
, Parameter p
, VarDeclarations
* outerVars
= null,
4138 bool indirect
= false)
4140 //printf("parameterStorageClass(p: %s)\n", p.toChars());
4141 auto stc = p
.storageClass
;
4143 // When the preview switch is enable, `in` parameters are `scope`
4144 if (stc & STC
.in_
&& global
.params
.previewIn
)
4145 return stc | STC
.scope_
;
4147 if (stc & (STC
.scope_ | STC
.return_ | STC
.lazy_
) || purity
== PURE
.impure
)
4150 /* If haven't inferred the return type yet, can't infer storage classes
4152 if (!nextOf() ||
!isnothrow())
4157 static bool mayHavePointers(Type t
)
4159 if (auto ts
= t
.isTypeStruct())
4162 if (sym
.members
&& !sym
.determineFields() && sym
.type
!= Type
.terror
)
4163 // struct is forward referenced, so "may have" pointers
4166 return t
.hasPointers();
4169 // See if p can escape via any of the other parameters
4170 if (purity
== PURE
.weak
)
4173 * Indirect calls may escape p through a nested context
4175 * https://issues.dlang.org/show_bug.cgi?id=24212
4176 * https://issues.dlang.org/show_bug.cgi?id=24213
4181 // Check escaping through parameters
4182 foreach (i
, fparam
; parameterList
)
4184 Type t
= fparam
.type
;
4187 t
= t
.baseElemOf(); // punch thru static arrays
4188 if (t
.isMutable() && t
.hasPointers())
4190 if (fparam
.isReference() && fparam
!= p
)
4193 if (t
.ty
== Tdelegate
)
4194 return stc; // could escape thru delegate
4199 /* if t is a pointer to mutable pointer
4201 if (auto tn
= t
.nextOf())
4203 if (tn
.isMutable() && mayHavePointers(tn
))
4204 return stc; // escape through pointers
4209 // Check escaping through `this`
4210 if (tthis
&& tthis
.isMutable())
4212 foreach (VarDeclaration v
; isAggregate(tthis
).fields
)
4214 if (v
.hasPointers())
4219 // Check escaping through nested context
4220 if (outerVars
&& this.isMutable())
4222 foreach (VarDeclaration v
; *outerVars
)
4224 if (v
.hasPointers())
4230 // Check escaping through return value
4231 Type tret
= nextOf().toBasetype();
4232 if (isref || tret
.hasPointers())
4234 return stc | STC
.scope_ | STC
.return_ | STC
.returnScope
;
4237 return stc | STC
.scope_
;
4240 override Type
addStorageClass(StorageClass
stc)
4242 //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
4243 TypeFunction t
= Type
.addStorageClass(stc).toTypeFunction();
4244 if ((stc & STC
.pure_
&& !t
.purity
) ||
4245 (stc & STC
.nothrow_
&& !t
.isnothrow
) ||
4246 (stc & STC
.nogc
&& !t
.isnogc
) ||
4247 (stc & STC
.scope_
&& !t
.isScopeQual
) ||
4248 (stc & STC
.safe
&& t
.trust
< TRUST
.trusted
))
4250 // Klunky to change these
4251 auto tf
= new TypeFunction(t
.parameterList
, t
.next
, t
.linkage
, 0);
4254 tf
.purity
= t
.purity
;
4255 tf
.isnothrow
= t
.isnothrow
;
4256 tf
.isnogc
= t
.isnogc
;
4257 tf
.isproperty
= t
.isproperty
;
4259 tf
.isreturn
= t
.isreturn
;
4260 tf
.isreturnscope
= t
.isreturnscope
;
4261 tf
.isScopeQual
= t
.isScopeQual
;
4262 tf
.isreturninferred
= t
.isreturninferred
;
4263 tf
.isscopeinferred
= t
.isscopeinferred
;
4265 tf
.isInOutParam
= t
.isInOutParam
;
4266 tf
.isInOutQual
= t
.isInOutQual
;
4267 tf
.isctor
= t
.isctor
;
4269 if (stc & STC
.pure_
)
4270 tf
.purity
= PURE
.fwdref
;
4271 if (stc & STC
.nothrow_
)
4272 tf
.isnothrow
= true;
4276 tf
.trust
= TRUST
.safe
;
4277 if (stc & STC
.scope_
)
4279 tf
.isScopeQual
= true;
4280 if (stc & STC
.scopeinferred
)
4281 tf
.isscopeinferred
= true;
4284 tf
.deco
= tf
.merge().deco
;
4290 override Type
substWildTo(uint)
4292 if (!iswild
&& !(mod
& MODFlags
.wild
))
4295 // Substitude inout qualifier of function type to mutable or immutable
4296 // would break type system. Instead substitude inout to the most weak
4297 // qualifer - const.
4298 uint m
= MODFlags
.const_
;
4301 Type tret
= next
.substWildTo(m
);
4302 Parameters
* params
= parameterList
.parameters
;
4303 if (mod
& MODFlags
.wild
)
4304 params
= parameterList
.parameters
.copy();
4305 for (size_t i
= 0; i
< params
.length
; i
++)
4307 Parameter p
= (*params
)[i
];
4308 Type t
= p
.type
.substWildTo(m
);
4311 if (params
== parameterList
.parameters
)
4312 params
= parameterList
.parameters
.copy();
4313 (*params
)[i
] = new Parameter(p
.loc
, p
.storageClass
, t
, null, null, null);
4315 if (next
== tret
&& params
== parameterList
.parameters
)
4318 // Similar to TypeFunction::syntaxCopy;
4319 auto t
= new TypeFunction(ParameterList(params
, parameterList
.varargs
), tret
, linkage
);
4320 t
.mod
= ((mod
& MODFlags
.wild
) ?
(mod
& ~MODFlags
.wild
) | MODFlags
.const_
: mod
);
4321 t
.isnothrow
= isnothrow
;
4324 t
.isproperty
= isproperty
;
4326 t
.isreturn
= isreturn
;
4327 t
.isreturnscope
= isreturnscope
;
4328 t
.isScopeQual
= isScopeQual
;
4329 t
.isreturninferred
= isreturninferred
;
4330 t
.isscopeinferred
= isscopeinferred
;
4331 t
.isInOutParam
= false;
4332 t
.isInOutQual
= false;
4339 extern(D
) static const(char)* getMatchError(A
...)(const(char)* format
, A args
)
4341 if (global
.gag
&& !global
.params
.v
.showGaggedErrors
)
4344 buf
.printf(format
, args
);
4345 return buf
.extractChars();
4348 /********************************
4349 * Convert an `argumentList`, which may contain named arguments, into
4350 * a list of arguments in the order of the parameter list.
4353 * argumentList = array of function arguments
4354 * pMessage = address to store error message, or `null`
4355 * Returns: re-ordered argument list, or `null` on error
4357 extern(D
) Expressions
* resolveNamedArgs(ArgumentList argumentList
, const(char)** pMessage
)
4359 Expression
[] args
= argumentList
.arguments ?
(*argumentList
.arguments
)[] : null;
4360 Identifier
[] names
= argumentList
.names ?
(*argumentList
.names
)[] : null;
4361 auto newArgs
= new Expressions(parameterList
.length
);
4364 bool hasNamedArgs
= false;
4365 foreach (i
, arg
; args
)
4372 auto name
= i
< names
.length ? names
[i
] : null;
4375 hasNamedArgs
= true;
4376 const pi
= findParameterIndex(name
);
4380 *pMessage
= getMatchError("no parameter named `%s`", name
.toChars());
4385 if (ci
>= newArgs
.length
)
4387 if (!parameterList
.varargs
)
4389 // Without named args, let the caller diagnose argument overflow
4390 if (hasNamedArgs
&& pMessage
)
4391 *pMessage
= getMatchError("argument `%s` goes past end of parameter list", arg
.toChars());
4394 while (ci
>= newArgs
.length
)
4401 *pMessage
= getMatchError("parameter `%s` assigned twice", parameterList
[ci
].toChars());
4404 (*newArgs
)[ci
++] = arg
;
4406 foreach (i
, arg
; (*newArgs
)[])
4408 if (arg || parameterList
[i
].defaultArg
)
4411 if (parameterList
.varargs
!= VarArg
.none
&& i
+ 1 == newArgs
.length
)
4415 *pMessage
= getMatchError("missing argument for parameter #%d: `%s`",
4416 i
+ 1, parameterToChars(parameterList
[i
], this, false));
4419 // strip trailing nulls from default arguments
4420 size_t e
= newArgs
.length
;
4421 while (e
> 0 && (*newArgs
)[e
- 1] is null)
4430 + Checks whether this function type is convertible to ` to`
4431 + when used in a function pointer / delegate.
4437 + MATCH.nomatch: `to` is not a covaraint function
4438 + MATCH.convert: `to` is a covaraint function
4439 + MATCH.exact: `to` is identical to this function
4441 private MATCH
implicitPointerConv(Type to
)
4445 if (this.equals(to
))
4446 return MATCH
.constant
;
4448 if (this.covariant(to
) == Covariant
.yes
)
4450 Type tret
= this.nextOf();
4451 Type toret
= to
.nextOf();
4452 if (tret
.ty
== Tclass
&& toret
.ty
== Tclass
)
4454 /* https://issues.dlang.org/show_bug.cgi?id=10219
4455 * Check covariant interface return with offset tweaking.
4457 * class C : Object, I {}
4458 * I function() dg = function C() {} // should be error
4461 if (toret
.isBaseOf(tret
, &offset
) && offset
!= 0)
4462 return MATCH
.nomatch
;
4464 return MATCH
.convert
;
4467 return MATCH
.nomatch
;
4470 /** Extends TypeNext.constConv by also checking for matching attributes **/
4471 override MATCH
constConv(Type to
)
4473 // Attributes need to match exactly, otherwise it's an implicit conversion
4474 if (this.ty
!= to
.ty ||
!this.attributesEqual(cast(TypeFunction
) to
))
4475 return MATCH
.nomatch
;
4477 return super.constConv(to
);
4480 extern (D
) bool checkRetType(const ref Loc loc
)
4482 Type tb
= next
.toBasetype();
4483 if (tb
.ty
== Tfunction
)
4485 error(loc
, "functions cannot return a function");
4488 if (tb
.ty
== Ttuple
)
4490 error(loc
, "functions cannot return a sequence (use `std.typecons.Tuple`)");
4493 if (!isref
&& (tb
.ty
== Tstruct || tb
.ty
== Tsarray
))
4495 if (auto ts
= tb
.baseElemOf().isTypeStruct())
4497 if (!ts
.sym
.members
)
4499 error(loc
, "functions cannot return opaque type `%s` by value", tb
.toChars());
4504 if (tb
.ty
== Terror
)
4510 /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
4511 bool iswild() const pure nothrow @safe @nogc
4513 return isInOutParam || isInOutQual
;
4516 /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
4517 extern (D
) bool attributesEqual(const scope TypeFunction other
, bool trustSystemEqualsDefault
= true) const pure nothrow @safe @nogc
4519 // @@@DEPRECATED_2.112@@@
4520 // See semantic2.d Semantic2Visitor.visit(FuncDeclaration):
4521 // Two overloads that are identical except for one having an explicit `@system`
4522 // attribute is currently in deprecation, and will become an error in 2.104 for
4523 // `extern(C)`, and 2.112 for `extern(D)` code respectively. Once the deprecation
4524 // period has passed, the trustSystemEqualsDefault=true behaviour should be made
4525 // the default, then we can remove the `cannot overload extern(...) function`
4526 // errors as they will become dead code as a result.
4527 return (this.trust
== other
.trust ||
4528 (trustSystemEqualsDefault
&& this.trust
<= TRUST
.system
&& other
.trust
<= TRUST
.system
)) &&
4529 this.purity
== other
.purity
&&
4530 this.isnothrow
== other
.isnothrow
&&
4531 this.isnogc
== other
.isnogc
&&
4532 this.islive
== other
.islive
;
4535 override void accept(Visitor v
)
4541 * Look for the index of parameter `ident` in the parameter list
4544 * ident = identifier of parameter to search for
4545 * Returns: index of parameter with name `ident` or -1 if not found
4547 private extern(D
) ptrdiff_t
findParameterIndex(Identifier ident
)
4549 foreach (i
, p
; this.parameterList
)
4551 if (p
.ident
== ident
)
4558 /***********************************************************
4560 extern (C
++) final class TypeDelegate
: TypeNext
4562 // .next is a TypeFunction
4564 extern (D
) this(TypeFunction t
) @safe
4566 super(Tfunction
, t
);
4570 static TypeDelegate
create(TypeFunction t
) @safe
4572 return new TypeDelegate(t
);
4575 override const(char)* kind() const
4580 override TypeDelegate
syntaxCopy()
4582 auto tf
= next
.syntaxCopy().isTypeFunction();
4586 auto result
= new TypeDelegate(tf
);
4591 override Type
addStorageClass(StorageClass
stc)
4593 TypeDelegate t
= cast(TypeDelegate
)Type
.addStorageClass(stc);
4597 override uinteger_t
size(const ref Loc loc
)
4599 return target
.ptrsize
* 2;
4602 override uint alignsize()
4604 return target
.ptrsize
;
4607 override MATCH
implicitConvTo(Type to
)
4609 //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
4610 //printf("from: %s\n", toChars());
4611 //printf("to : %s\n", to.toChars());
4612 if (this.equals(to
))
4615 if (auto toDg
= to
.isTypeDelegate())
4617 MATCH m
= this.next
.isTypeFunction().implicitPointerConv(toDg
.next
);
4619 // Retain the old behaviour for this refactoring
4620 // Should probably be changed to constant to match function pointers
4621 if (m
> MATCH
.convert
)
4627 return MATCH
.nomatch
;
4630 override bool isZeroInit(const ref Loc loc
)
4635 override bool isBoolean()
4640 override bool hasPointers()
4645 override void accept(Visitor v
)
4652 * This is a shell containing a TraitsExp that can be
4653 * either resolved to a type or to a symbol.
4655 * The point is to allow AliasDeclarationY to use `__traits()`, see https://issues.dlang.org/show_bug.cgi?id=7804.
4657 extern (C
++) final class TypeTraits
: Type
4660 /// The expression to resolve as type or symbol.
4662 /// Cached type/symbol after semantic analysis.
4665 final extern (D
) this(const ref Loc loc
, TraitsExp exp
) @safe
4672 override const(char)* kind() const
4677 override TypeTraits
syntaxCopy()
4679 TraitsExp te
= exp
.syntaxCopy();
4680 TypeTraits tt
= new TypeTraits(loc
, te
);
4685 override Dsymbol
toDsymbol(Scope
* sc
)
4690 resolve(this, loc
, sc
, e
, t
, s
);
4691 if (t
&& t
.ty
!= Terror
)
4692 s
= t
.toDsymbol(sc
);
4699 override void accept(Visitor v
)
4704 override uinteger_t
size(const ref Loc loc
)
4706 return SIZE_INVALID
;
4711 * Implements mixin types.
4713 * Semantic analysis will convert it to a real type.
4715 extern (C
++) final class TypeMixin
: Type
4719 RootObject obj
; // cached result of semantic analysis.
4721 extern (D
) this(const ref Loc loc
, Expressions
* exps
) @safe
4728 override const(char)* kind() const
4733 override TypeMixin
syntaxCopy()
4735 return new TypeMixin(loc
, Expression
.arraySyntaxCopy(exps
));
4738 override Dsymbol
toDsymbol(Scope
* sc
)
4743 resolve(this, loc
, sc
, e
, t
, s
);
4745 s
= t
.toDsymbol(sc
);
4752 override void accept(Visitor v
)
4758 /***********************************************************
4760 extern (C
++) abstract class TypeQualified
: Type
4764 // array of Identifier and TypeInstance,
4765 // representing ident.ident!tiargs.ident. ... etc.
4768 final extern (D
) this(TY ty
, Loc loc
)
4774 // abstract override so that using `TypeQualified.syntaxCopy` gets
4775 // us a `TypeQualified`
4776 abstract override TypeQualified
syntaxCopy();
4778 extern (D
) final void syntaxCopyHelper(TypeQualified t
)
4780 //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t.toChars(), toChars());
4781 idents
.setDim(t
.idents
.length
);
4782 for (size_t i
= 0; i
< idents
.length
; i
++)
4784 RootObject id
= t
.idents
[i
];
4785 with (DYNCAST
) final switch (id
.dyncast())
4790 Expression e
= cast(Expression
)id
;
4795 TemplateInstance ti
= cast(TemplateInstance
)id
;
4796 ti
= ti
.syntaxCopy(null);
4800 Type tx
= cast(Type
)id
;
4801 tx
= tx
.syntaxCopy();
4809 case templateparameter
:
4816 extern (D
) final void addIdent(Identifier ident
)
4821 extern (D
) final void addInst(TemplateInstance inst
)
4826 extern (D
) final void addIndex(RootObject e
)
4831 override uinteger_t
size(const ref Loc loc
)
4833 error(this.loc
, "size of type `%s` is not known", toChars());
4834 return SIZE_INVALID
;
4837 override void accept(Visitor v
)
4843 /***********************************************************
4845 extern (C
++) final class TypeIdentifier
: TypeQualified
4849 // The symbol representing this identifier, before alias resolution
4850 Dsymbol originalSymbol
;
4852 extern (D
) this(const ref Loc loc
, Identifier ident
)
4858 static TypeIdentifier
create(const ref Loc loc
, Identifier ident
)
4860 return new TypeIdentifier(loc
, ident
);
4863 override const(char)* kind() const
4865 return "identifier";
4868 override TypeIdentifier
syntaxCopy()
4870 auto t
= new TypeIdentifier(loc
, ident
);
4871 t
.syntaxCopyHelper(this);
4876 /*****************************************
4877 * See if type resolves to a symbol, if so,
4878 * return that symbol.
4880 override Dsymbol
toDsymbol(Scope
* sc
)
4882 //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
4889 resolve(this, loc
, sc
, e
, t
, s
);
4890 if (t
&& t
.ty
!= Tident
)
4891 s
= t
.toDsymbol(sc
);
4898 override void accept(Visitor v
)
4904 /***********************************************************
4905 * Similar to TypeIdentifier, but with a TemplateInstance as the root
4907 extern (C
++) final class TypeInstance
: TypeQualified
4909 TemplateInstance tempinst
;
4911 extern (D
) this(const ref Loc loc
, TemplateInstance tempinst
)
4913 super(Tinstance
, loc
);
4914 this.tempinst
= tempinst
;
4917 override const(char)* kind() const
4922 override TypeInstance
syntaxCopy()
4924 //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.length);
4925 auto t
= new TypeInstance(loc
, tempinst
.syntaxCopy(null));
4926 t
.syntaxCopyHelper(this);
4931 override Dsymbol
toDsymbol(Scope
* sc
)
4936 //printf("TypeInstance::semantic(%s)\n", toChars());
4937 resolve(this, loc
, sc
, e
, t
, s
);
4938 if (t
&& t
.ty
!= Tinstance
)
4939 s
= t
.toDsymbol(sc
);
4943 override void accept(Visitor v
)
4949 /***********************************************************
4951 extern (C
++) final class TypeTypeof
: TypeQualified
4956 extern (D
) this(const ref Loc loc
, Expression exp
)
4958 super(Ttypeof
, loc
);
4962 override const(char)* kind() const
4967 override TypeTypeof
syntaxCopy()
4969 //printf("TypeTypeof::syntaxCopy() %s\n", toChars());
4970 auto t
= new TypeTypeof(loc
, exp
.syntaxCopy());
4971 t
.syntaxCopyHelper(this);
4976 override Dsymbol
toDsymbol(Scope
* sc
)
4978 //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
4982 resolve(this, loc
, sc
, e
, t
, s
);
4986 override uinteger_t
size(const ref Loc loc
)
4989 return exp
.type
.size(loc
);
4991 return TypeQualified
.size(loc
);
4994 override void accept(Visitor v
)
5000 /***********************************************************
5002 extern (C
++) final class TypeReturn
: TypeQualified
5004 extern (D
) this(const ref Loc loc
)
5006 super(Treturn
, loc
);
5009 override const(char)* kind() const
5014 override TypeReturn
syntaxCopy()
5016 auto t
= new TypeReturn(loc
);
5017 t
.syntaxCopyHelper(this);
5022 override Dsymbol
toDsymbol(Scope
* sc
)
5027 resolve(this, loc
, sc
, e
, t
, s
);
5031 override void accept(Visitor v
)
5037 /***********************************************************
5039 extern (C
++) final class TypeStruct
: Type
5041 StructDeclaration sym
;
5042 AliasThisRec att
= AliasThisRec
.fwdref
;
5043 bool inuse
= false; // struct currently subject of recursive method call
5045 extern (D
) this(StructDeclaration sym
) @safe
5051 static TypeStruct
create(StructDeclaration sym
) @safe
5053 return new TypeStruct(sym
);
5056 override const(char)* kind() const
5061 override uinteger_t
size(const ref Loc loc
)
5063 return sym
.size(loc
);
5066 override uint alignsize()
5068 sym
.size(Loc
.initial
); // give error for forward references
5069 return sym
.alignsize
;
5072 override TypeStruct
syntaxCopy()
5077 override Dsymbol
toDsymbol(Scope
* sc
)
5082 override structalign_t
alignment()
5084 if (sym
.alignment
.isUnknown())
5086 return sym
.alignment
;
5089 /***************************************
5090 * Use when we prefer the default initializer to be a literal,
5091 * rather than a global immutable variable.
5093 override Expression
defaultInitLiteral(const ref Loc loc
)
5095 static if (LOGDEFAULTINIT
)
5097 printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars());
5100 if (sym
.sizeok
!= Sizeok
.done
)
5101 return ErrorExp
.get();
5103 auto structelems
= new Expressions(sym
.nonHiddenFields());
5105 foreach (j
; 0 .. structelems
.length
)
5107 VarDeclaration vd
= sym
.fields
[j
];
5111 error(loc
, "circular reference to `%s`", vd
.toPrettyChars());
5112 return ErrorExp
.get();
5114 if (vd
.offset
< offset || vd
.type
.size() == 0)
5118 if (vd
._init
.isVoidInitializer())
5121 e
= vd
.getConstInitializer(false);
5124 e
= vd
.type
.defaultInitLiteral(loc
);
5125 if (e
&& e
.op
== EXP
.error
)
5128 offset
= vd
.offset
+ cast(uint)vd
.type
.size();
5129 (*structelems
)[j
] = e
;
5131 auto structinit
= new StructLiteralExp(loc
, sym
, structelems
);
5133 /* Copy from the initializer symbol for larger symbols,
5134 * otherwise the literals expressed as code get excessively large.
5136 if (size(loc
) > target
.ptrsize
* 4 && !needsNested())
5137 structinit
.useStaticInit
= true;
5139 structinit
.type
= this;
5143 override bool isZeroInit(const ref Loc loc
)
5145 // Determine zeroInit here, as this can be called before semantic2
5146 sym
.determineSize(sym
.loc
);
5147 return sym
.zeroInit
;
5150 override bool isAssignable()
5152 bool assignable
= true;
5153 uint offset
= ~0; // dead-store initialize to prevent spurious warning
5155 sym
.determineSize(sym
.loc
);
5157 /* If any of the fields are const or immutable,
5158 * then one cannot assign this struct.
5160 for (size_t i
= 0; i
< sym
.fields
.length
; i
++)
5162 VarDeclaration v
= sym
.fields
[i
];
5163 //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());
5167 else if (v
.offset
== offset
)
5169 /* If any fields of anonymous union are assignable,
5170 * then regard union as assignable.
5171 * This is to support unsafe things like Rebindable templates.
5181 assignable
= v
.type
.isMutable() && v
.type
.isAssignable();
5183 //printf(" -> assignable = %d\n", assignable);
5189 override bool isBoolean()
5194 override bool needsDestruction()
5196 return sym
.dtor
!is null;
5199 override bool needsCopyOrPostblit()
5201 return sym
.hasCopyCtor || sym
.postblit
;
5204 override bool needsNested()
5206 if (inuse
) return false; // circular type, error instead of crashing
5209 scope(exit
) inuse
= false;
5214 for (size_t i
= 0; i
< sym
.fields
.length
; i
++)
5216 VarDeclaration v
= sym
.fields
[i
];
5217 if (!v
.isDataseg() && v
.type
.needsNested())
5223 override bool hasPointers()
5225 if (sym
.members
&& !sym
.determineFields() && sym
.type
!= Type
.terror
)
5226 error(sym
.loc
, "no size because of forward references");
5228 sym
.determineTypeProperties();
5229 return sym
.hasPointerField
;
5232 override bool hasVoidInitPointers()
5234 sym
.size(Loc
.initial
); // give error for forward references
5235 sym
.determineTypeProperties();
5236 return sym
.hasVoidInitPointers
;
5239 override bool hasSystemFields()
5241 sym
.size(Loc
.initial
); // give error for forward references
5242 sym
.determineTypeProperties();
5243 return sym
.hasSystemFields
;
5246 override bool hasInvariant()
5248 sym
.size(Loc
.initial
); // give error for forward references
5249 sym
.determineTypeProperties();
5250 return sym
.hasInvariant() || sym
.hasFieldWithInvariant
;
5253 extern (D
) MATCH
implicitConvToWithoutAliasThis(Type to
)
5257 if (ty
== to
.ty
&& sym
== (cast(TypeStruct
)to
).sym
)
5259 m
= MATCH
.exact
; // exact match
5263 if (MODimplicitConv(mod
, to
.mod
))
5268 /* Check all the fields. If they can all be converted,
5269 * allow the conversion.
5271 uint offset
= ~0; // dead-store to prevent spurious warning
5272 for (size_t i
= 0; i
< sym
.fields
.length
; i
++)
5274 VarDeclaration v
= sym
.fields
[i
];
5278 else if (v
.offset
== offset
)
5280 if (m
> MATCH
.nomatch
)
5285 if (m
== MATCH
.nomatch
)
5290 Type tvf
= v
.type
.addMod(mod
);
5293 Type tv
= v
.type
.addMod(to
.mod
);
5296 MATCH mf
= tvf
.implicitConvTo(tv
);
5297 //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf);
5299 if (mf
== MATCH
.nomatch
)
5301 if (mf
< m
) // if field match is worse
5311 extern (D
) MATCH
implicitConvToThroughAliasThis(Type to
)
5314 if (!(ty
== to
.ty
&& sym
== (cast(TypeStruct
)to
).sym
) && sym
.aliasthis
&& !(att
& AliasThisRec
.tracing
))
5316 if (auto ato
= aliasthisOf())
5318 att
= cast(AliasThisRec
)(att | AliasThisRec
.tracing
);
5319 m
= ato
.implicitConvTo(to
);
5320 att
= cast(AliasThisRec
)(att
& ~AliasThisRec
.tracing
);
5323 m
= MATCH
.nomatch
; // no match
5328 override MATCH
implicitConvTo(Type to
)
5330 //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars());
5331 MATCH m
= implicitConvToWithoutAliasThis(to
);
5332 return m ? m
: implicitConvToThroughAliasThis(to
);
5335 override MATCH
constConv(Type to
)
5339 if (ty
== to
.ty
&& sym
== (cast(TypeStruct
)to
).sym
&& MODimplicitConv(mod
, to
.mod
))
5340 return MATCH
.constant
;
5341 return MATCH
.nomatch
;
5344 override MOD
deduceWild(Type t
, bool isRef
)
5346 if (ty
== t
.ty
&& sym
== (cast(TypeStruct
)t
).sym
)
5347 return Type
.deduceWild(t
, isRef
);
5351 if (t
.hasWild() && sym
.aliasthis
&& !(att
& AliasThisRec
.tracing
))
5353 if (auto ato
= aliasthisOf())
5355 att
= cast(AliasThisRec
)(att | AliasThisRec
.tracing
);
5356 wm
= ato
.deduceWild(t
, isRef
);
5357 att
= cast(AliasThisRec
)(att
& ~AliasThisRec
.tracing
);
5364 override inout(Type
) toHeadMutable() inout
5369 override void accept(Visitor v
)
5375 /***********************************************************
5377 extern (C
++) final class TypeEnum
: Type
5379 EnumDeclaration sym
;
5381 extern (D
) this(EnumDeclaration sym
) @safe
5387 override const(char)* kind() const
5392 override TypeEnum
syntaxCopy()
5397 override uinteger_t
size(const ref Loc loc
)
5399 return sym
.getMemtype(loc
).size(loc
);
5402 Type
memType(const ref Loc loc
= Loc
.initial
)
5404 return sym
.getMemtype(loc
);
5407 override uint alignsize()
5412 return t
.alignsize();
5415 override Dsymbol
toDsymbol(Scope
* sc
)
5420 override bool isintegral()
5422 return memType().isintegral();
5425 override bool isfloating()
5427 return memType().isfloating();
5430 override bool isreal()
5432 return memType().isreal();
5435 override bool isimaginary()
5437 return memType().isimaginary();
5440 override bool iscomplex()
5442 return memType().iscomplex();
5445 override bool isscalar()
5447 return memType().isscalar();
5450 override bool isunsigned()
5452 return memType().isunsigned();
5455 override bool isBoolean()
5457 return memType().isBoolean();
5460 override bool isString()
5462 return memType().isString();
5465 override bool isAssignable()
5467 return memType().isAssignable();
5470 override bool needsDestruction()
5472 return memType().needsDestruction();
5475 override bool needsCopyOrPostblit()
5477 return memType().needsCopyOrPostblit();
5480 override bool needsNested()
5482 return memType().needsNested();
5485 override MATCH
implicitConvTo(Type to
)
5488 //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars());
5489 if (ty
== to
.ty
&& sym
== (cast(TypeEnum
)to
).sym
)
5490 m
= (mod
== to
.mod
) ? MATCH
.exact
: MATCH
.constant
;
5491 else if (sym
.getMemtype(Loc
.initial
).implicitConvTo(to
))
5492 m
= MATCH
.convert
; // match with conversions
5494 m
= MATCH
.nomatch
; // no match
5498 override MATCH
constConv(Type to
)
5502 if (ty
== to
.ty
&& sym
== (cast(TypeEnum
)to
).sym
&& MODimplicitConv(mod
, to
.mod
))
5503 return MATCH
.constant
;
5504 return MATCH
.nomatch
;
5507 extern (D
) Type
toBasetype2()
5509 if (!sym
.members
&& !sym
.memtype
)
5511 auto tb
= sym
.getMemtype(Loc
.initial
).toBasetype();
5512 return tb
.castMod(mod
); // retain modifier bits from 'this'
5515 override bool isZeroInit(const ref Loc loc
)
5517 return sym
.getDefaultValue(loc
).toBool().hasValue(false);
5520 override bool hasPointers()
5522 return memType().hasPointers();
5525 override bool hasVoidInitPointers()
5527 return memType().hasVoidInitPointers();
5530 override bool hasSystemFields()
5532 return memType().hasSystemFields();
5535 override bool hasInvariant()
5537 return memType().hasInvariant();
5540 override Type
nextOf()
5542 return memType().nextOf();
5545 override void accept(Visitor v
)
5551 /***********************************************************
5553 extern (C
++) final class TypeClass
: Type
5555 ClassDeclaration sym
;
5556 AliasThisRec att
= AliasThisRec
.fwdref
;
5557 CPPMANGLE cppmangle
= CPPMANGLE
.def
;
5559 extern (D
) this(ClassDeclaration sym
) @safe
5565 override const(char)* kind() const
5570 override uinteger_t
size(const ref Loc loc
)
5572 return target
.ptrsize
;
5575 override TypeClass
syntaxCopy()
5580 override Dsymbol
toDsymbol(Scope
* sc
)
5585 override inout(ClassDeclaration
) isClassHandle() inout
5590 override bool isBaseOf(Type t
, int* poffset
)
5592 if (t
&& t
.ty
== Tclass
)
5594 ClassDeclaration cd
= (cast(TypeClass
)t
).sym
;
5595 if (cd
.semanticRun
< PASS
.semanticdone
&& !cd
.isBaseInfoComplete())
5596 cd
.dsymbolSemantic(null);
5597 if (sym
.semanticRun
< PASS
.semanticdone
&& !sym
.isBaseInfoComplete())
5598 sym
.dsymbolSemantic(null);
5600 if (sym
.isBaseOf(cd
, poffset
))
5606 extern (D
) MATCH
implicitConvToWithoutAliasThis(Type to
)
5608 // Run semantic before checking whether class is convertible
5609 ClassDeclaration cdto
= to
.isClassHandle();
5612 //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete());
5613 if (cdto
.semanticRun
< PASS
.semanticdone
&& !cdto
.isBaseInfoComplete())
5614 cdto
.dsymbolSemantic(null);
5615 if (sym
.semanticRun
< PASS
.semanticdone
&& !sym
.isBaseInfoComplete())
5616 sym
.dsymbolSemantic(null);
5618 MATCH m
= constConv(to
);
5619 if (m
> MATCH
.nomatch
)
5622 if (cdto
&& cdto
.isBaseOf(sym
, null) && MODimplicitConv(mod
, to
.mod
))
5624 //printf("'to' is base\n");
5625 return MATCH
.convert
;
5627 return MATCH
.nomatch
;
5630 extern (D
) MATCH
implicitConvToThroughAliasThis(Type to
)
5633 if (sym
.aliasthis
&& !(att
& AliasThisRec
.tracing
))
5635 if (auto ato
= aliasthisOf())
5637 att
= cast(AliasThisRec
)(att | AliasThisRec
.tracing
);
5638 m
= ato
.implicitConvTo(to
);
5639 att
= cast(AliasThisRec
)(att
& ~AliasThisRec
.tracing
);
5645 override MATCH
implicitConvTo(Type to
)
5647 //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
5648 MATCH m
= implicitConvToWithoutAliasThis(to
);
5649 return m ? m
: implicitConvToThroughAliasThis(to
);
5652 override MATCH
constConv(Type to
)
5656 if (ty
== to
.ty
&& sym
== (cast(TypeClass
)to
).sym
&& MODimplicitConv(mod
, to
.mod
))
5657 return MATCH
.constant
;
5659 /* Conversion derived to const(base)
5662 if (to
.isBaseOf(this, &offset
) && offset
== 0 && MODimplicitConv(mod
, to
.mod
))
5666 // inout(derived) to inout(base)
5667 if (!to
.isMutable() && !to
.isWild())
5668 return MATCH
.convert
;
5671 return MATCH
.nomatch
;
5674 override MOD
deduceWild(Type t
, bool isRef
)
5676 ClassDeclaration cd
= t
.isClassHandle();
5677 if (cd
&& (sym
== cd || cd
.isBaseOf(sym
, null)))
5678 return Type
.deduceWild(t
, isRef
);
5682 if (t
.hasWild() && sym
.aliasthis
&& !(att
& AliasThisRec
.tracing
))
5684 if (auto ato
= aliasthisOf())
5686 att
= cast(AliasThisRec
)(att | AliasThisRec
.tracing
);
5687 wm
= ato
.deduceWild(t
, isRef
);
5688 att
= cast(AliasThisRec
)(att
& ~AliasThisRec
.tracing
);
5695 override inout(Type
) toHeadMutable() inout
5700 override bool isZeroInit(const ref Loc loc
)
5705 override bool isscope()
5710 override bool isBoolean()
5715 override bool hasPointers()
5720 override void accept(Visitor v
)
5726 /***********************************************************
5728 extern (C
++) final class TypeTuple
: Type
5730 // 'logically immutable' cached global - don't modify!
5731 __gshared TypeTuple empty
= new TypeTuple();
5733 Parameters
* arguments
; // types making up the tuple
5735 extern (D
) this(Parameters
* arguments
) @safe
5738 //printf("TypeTuple(this = %p)\n", this);
5739 this.arguments
= arguments
;
5740 //printf("TypeTuple() %p, %s\n", this, toChars());
5745 for (size_t i
= 0; i
< arguments
.length
; i
++)
5747 Parameter arg
= (*arguments
)[i
];
5748 assert(arg
&& arg
.type
);
5755 * Form TypeTuple from the types of the expressions.
5756 * Assume exps[] is already tuple expanded.
5758 extern (D
) this(Expressions
* exps
)
5761 auto arguments
= new Parameters(exps ? exps
.length
: 0);
5764 for (size_t i
= 0; i
< exps
.length
; i
++)
5766 Expression e
= (*exps
)[i
];
5767 if (e
.type
.ty
== Ttuple
)
5768 error(e
.loc
, "cannot form sequence of sequences");
5769 auto arg
= new Parameter(e
.loc
, STC
.undefined_
, e
.type
, null, null, null);
5770 (*arguments
)[i
] = arg
;
5773 this.arguments
= arguments
;
5774 //printf("TypeTuple() %p, %s\n", this, toChars());
5777 static TypeTuple
create(Parameters
* arguments
) @safe
5779 return new TypeTuple(arguments
);
5782 /*******************************************
5783 * Type tuple with 0, 1 or 2 types in it.
5785 extern (D
) this() @safe
5788 arguments
= new Parameters();
5791 extern (D
) this(Type t1
)
5794 arguments
= new Parameters();
5795 arguments
.push(new Parameter(Loc
.initial
, 0, t1
, null, null, null));
5798 extern (D
) this(Type t1
, Type t2
)
5801 arguments
= new Parameters();
5802 arguments
.push(new Parameter(Loc
.initial
, 0, t1
, null, null, null));
5803 arguments
.push(new Parameter(Loc
.initial
, 0, t2
, null, null, null));
5806 static TypeTuple
create() @safe
5808 return new TypeTuple();
5811 static TypeTuple
create(Type t1
)
5813 return new TypeTuple(t1
);
5816 static TypeTuple
create(Type t1
, Type t2
)
5818 return new TypeTuple(t1
, t2
);
5821 override const(char)* kind() const
5826 override TypeTuple
syntaxCopy()
5828 Parameters
* args
= Parameter
.arraySyntaxCopy(arguments
);
5829 auto t
= new TypeTuple(args
);
5834 override bool equals(const RootObject o
) const
5836 Type t
= cast(Type
)o
;
5837 //printf("TypeTuple::equals(%s, %s)\n", toChars(), t.toChars());
5840 if (auto tt
= t
.isTypeTuple())
5842 if (arguments
.length
== tt
.arguments
.length
)
5844 for (size_t i
= 0; i
< tt
.arguments
.length
; i
++)
5846 const Parameter arg1
= (*arguments
)[i
];
5847 Parameter arg2
= (*tt
.arguments
)[i
];
5848 if (!arg1
.type
.equals(arg2
.type
))
5857 override MATCH
implicitConvTo(Type to
)
5861 if (auto tt
= to
.isTypeTuple())
5863 if (arguments
.length
== tt
.arguments
.length
)
5865 MATCH m
= MATCH
.exact
;
5866 for (size_t i
= 0; i
< tt
.arguments
.length
; i
++)
5868 Parameter arg1
= (*arguments
)[i
];
5869 Parameter arg2
= (*tt
.arguments
)[i
];
5870 MATCH mi
= arg1
.type
.implicitConvTo(arg2
.type
);
5877 return MATCH
.nomatch
;
5880 override void accept(Visitor v
)
5886 /***********************************************************
5887 * This is so we can slice a TypeTuple
5889 extern (C
++) final class TypeSlice
: TypeNext
5894 extern (D
) this(Type next
, Expression lwr
, Expression upr
) @safe
5896 super(Tslice
, next
);
5897 //printf("TypeSlice[%s .. %s]\n", lwr.toChars(), upr.toChars());
5902 override const(char)* kind() const
5907 override TypeSlice
syntaxCopy()
5909 auto t
= new TypeSlice(next
.syntaxCopy(), lwr
.syntaxCopy(), upr
.syntaxCopy());
5914 override void accept(Visitor v
)
5920 /***********************************************************
5922 extern (C
++) final class TypeNull
: Type
5924 extern (D
) this() @safe
5926 //printf("TypeNull %p\n", this);
5930 override const(char)* kind() const
5935 override TypeNull
syntaxCopy()
5937 // No semantic analysis done, no need to copy
5941 override MATCH
implicitConvTo(Type to
)
5943 //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
5944 //printf("from: %s\n", toChars());
5945 //printf("to : %s\n", to.toChars());
5946 MATCH m
= Type
.implicitConvTo(to
);
5947 if (m
!= MATCH
.nomatch
)
5950 // NULL implicitly converts to any pointer type or dynamic array
5951 //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
5953 Type tb
= to
.toBasetype();
5954 if (tb
.ty
== Tnull || tb
.ty
== Tpointer || tb
.ty
== Tarray || tb
.ty
== Taarray || tb
.ty
== Tclass || tb
.ty
== Tdelegate
)
5955 return MATCH
.constant
;
5958 return MATCH
.nomatch
;
5961 override bool hasPointers()
5963 /* Although null isn't dereferencable, treat it as a pointer type for
5964 * attribute inference, generic code, etc.
5969 override bool isBoolean()
5974 override uinteger_t
size(const ref Loc loc
)
5976 return tvoidptr
.size(loc
);
5979 override void accept(Visitor v
)
5985 /***********************************************************
5987 extern (C
++) final class TypeNoreturn
: Type
5989 extern (D
) this() @safe
5991 //printf("TypeNoreturn %p\n", this);
5995 override const(char)* kind() const
6000 override TypeNoreturn
syntaxCopy()
6002 // No semantic analysis done, no need to copy
6006 override MATCH
implicitConvTo(Type to
)
6008 //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
6009 //printf("from: %s\n", toChars());
6010 //printf("to : %s\n", to.toChars());
6011 if (this.equals(to
))
6014 // Different qualifiers?
6015 if (to
.ty
== Tnoreturn
)
6016 return MATCH
.constant
;
6018 // Implicitly convertible to any type
6019 return MATCH
.convert
;
6022 override MATCH
constConv(Type to
)
6024 // Either another noreturn or conversion to any type
6025 return this.implicitConvTo(to
);
6028 override bool isBoolean()
6030 return true; // bottom type can be implicitly converted to any other type
6033 override uinteger_t
size(const ref Loc loc
)
6038 override uint alignsize()
6043 override void accept(Visitor v
)
6049 /***********************************************************
6050 * Unlike D, C can declare/define struct/union/enum tag names
6051 * inside Declarators, instead of separately as in D.
6052 * The order these appear in the symbol table must be in lexical
6053 * order. There isn't enough info at the parsing stage to determine if
6054 * it's a declaration or a reference to an existing name, so this Type
6055 * collects the necessary info and defers it to semantic().
6057 extern (C
++) final class TypeTag
: Type
6059 Loc loc
; /// location of declaration
6060 TOK tok
; /// TOK.struct_, TOK.union_, TOK.enum_
6061 structalign_t packalign
; /// alignment of struct/union fields
6062 Identifier id
; /// tag name identifier
6063 Type base
; /// base type for enums otherwise null
6064 Dsymbols
* members
; /// members of struct, null if none
6066 Type resolved
; /// type after semantic() in case there are more others
6067 /// pointing to this instance, which can happen with
6068 /// struct S { int a; } s1, *s2;
6069 MOD mod
; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment)
6071 extern (D
) this(const ref Loc loc
, TOK tok
, Identifier id
, structalign_t packalign
, Type base
, Dsymbols
* members
) @safe
6073 //printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this);
6078 this.packalign
= packalign
;
6080 this.members
= members
;
6084 override const(char)* kind() const
6089 override TypeTag
syntaxCopy()
6091 //printf("TypeTag syntaxCopy()\n");
6092 // No semantic analysis done, no need to copy
6096 override void accept(Visitor v
)
6102 /***********************************************************
6103 * Represents a function's formal parameters + variadics info.
6104 * Length, indexing and iteration are based on a depth-first tuple expansion.
6105 * https://dlang.org/spec/function.html#ParameterList
6107 extern (C
++) struct ParameterList
6109 /// The raw (unexpanded) formal parameters, possibly containing tuples.
6110 Parameters
* parameters
;
6111 StorageClass
stc; // storage class of ...
6112 VarArg varargs
= VarArg
.none
;
6113 bool hasIdentifierList
; // true if C identifier-list style
6115 this(Parameters
* parameters
, VarArg varargs
= VarArg
.none
, StorageClass
stc = 0) @safe
6117 this.parameters
= parameters
;
6118 this.varargs
= varargs
;
6122 /// Returns the number of expanded parameters. Complexity: O(N).
6125 return Parameter
.dim(parameters
);
6128 /// Returns the expanded parameter at the given index, or null if out of
6129 /// bounds. Complexity: O(i).
6130 Parameter
opIndex(size_t i
)
6132 return Parameter
.getNth(parameters
, i
);
6135 /// Iterates over the expanded parameters. Complexity: O(N).
6136 /// Prefer this to avoid the O(N + N^2/2) complexity of calculating length
6137 /// and calling N times opIndex.
6138 extern (D
) int opApply(scope Parameter
.ForeachDg dg
)
6140 return Parameter
._foreach(parameters
, dg
);
6143 /// Iterates over the expanded parameters, matching them with the unexpanded
6144 /// ones, for semantic processing
6145 extern (D
) int opApply(scope Parameter
.SemanticForeachDg dg
)
6147 return Parameter
._foreach(this.parameters
, dg
);
6150 extern (D
) ParameterList
syntaxCopy()
6152 return ParameterList(Parameter
.arraySyntaxCopy(parameters
), varargs
);
6155 /// Compares this to another ParameterList (and expands tuples if necessary)
6156 extern (D
) bool opEquals(scope ref ParameterList other
) const
6158 if (stc != other
.stc || varargs
!= other
.varargs ||
(!parameters
!= !other
.parameters
))
6161 if (this.parameters
is other
.parameters
)
6167 // Pairwise compare each parameter
6168 // Can this avoid the O(n) indexing for the second list?
6169 foreach (_
, p1
; cast() this)
6171 auto p2
= other
[idx
++];
6172 if (!p2 || p1
!= p2
) {
6178 // Ensure no remaining parameters in `other`
6179 return !diff
&& other
[idx
] is null;
6182 /// Returns: `true` if any parameter has a default argument
6183 extern(D
) bool hasDefaultArgs()
6185 foreach (oidx
, oparam
, eidx
, eparam
; this)
6187 if (eparam
.defaultArg
)
6193 // Returns: `true` if any parameter doesn't have a default argument
6194 extern(D
) bool hasArgsWithoutDefault()
6196 foreach (oidx
, oparam
, eidx
, eparam
; this)
6198 if (!eparam
.defaultArg
)
6206 /***********************************************************
6208 extern (C
++) final class Parameter
: ASTNode
6210 import dmd
.attrib
: UserAttributeDeclaration
;
6213 StorageClass storageClass
;
6216 Expression defaultArg
;
6217 UserAttributeDeclaration userAttribDecl
; // user defined attributes
6219 extern (D
) this(const ref Loc loc
, StorageClass storageClass
, Type type
, Identifier ident
, Expression defaultArg
, UserAttributeDeclaration userAttribDecl
) @safe
6224 this.storageClass
= storageClass
;
6225 this.defaultArg
= defaultArg
;
6226 this.userAttribDecl
= userAttribDecl
;
6229 static Parameter
create(const ref Loc loc
, StorageClass storageClass
, Type type
, Identifier ident
, Expression defaultArg
, UserAttributeDeclaration userAttribDecl
) @safe
6231 return new Parameter(loc
, storageClass
, type
, ident
, defaultArg
, userAttribDecl
);
6234 Parameter
syntaxCopy()
6236 return new Parameter(loc
, storageClass
, type ? type
.syntaxCopy() : null, ident
, defaultArg ? defaultArg
.syntaxCopy() : null, userAttribDecl ? userAttribDecl
.syntaxCopy(null) : null);
6239 /****************************************************
6240 * Determine if parameter is a lazy array of delegates.
6241 * If so, return the return type of those delegates.
6242 * If not, return NULL.
6244 * Returns T if the type is one of the following forms:
6250 Type tb
= type
.toBasetype();
6251 if (tb
.ty
== Tsarray || tb
.ty
== Tarray
)
6253 Type tel
= (cast(TypeArray
)tb
).next
.toBasetype();
6254 if (auto td
= tel
.isTypeDelegate())
6256 TypeFunction tf
= td
.next
.toTypeFunction();
6257 if (tf
.parameterList
.varargs
== VarArg
.none
&& tf
.parameterList
.length
== 0)
6259 return tf
.next
; // return type of delegate
6266 /// Returns: Whether the function parameter is lazy
6267 bool isLazy() const @safe pure nothrow @nogc
6269 return (this.storageClass
& (STC
.lazy_
)) != 0;
6272 /// Returns: Whether the function parameter is a reference (out / ref)
6273 bool isReference() const @safe pure nothrow @nogc
6275 return (this.storageClass
& (STC
.ref_ | STC
.out_
)) != 0;
6278 // kludge for template.isType()
6279 override DYNCAST
dyncast() const
6281 return DYNCAST
.parameter
;
6284 override void accept(Visitor v
)
6289 extern (D
) static Parameters
* arraySyntaxCopy(Parameters
* parameters
)
6291 Parameters
* params
= null;
6294 params
= new Parameters(parameters
.length
);
6295 for (size_t i
= 0; i
< params
.length
; i
++)
6296 (*params
)[i
] = (*parameters
)[i
].syntaxCopy();
6301 /***************************************
6302 * Determine number of arguments, folding in tuples.
6304 static size_t
dim(Parameters
* parameters
)
6308 int dimDg(size_t n
, Parameter p
)
6314 _foreach(parameters
, &dimDg
);
6319 * Get nth `Parameter`, folding in tuples.
6321 * Since `parameters` can include tuples, which would increase its
6322 * length, this function allows to get the `nth` parameter as if
6323 * all tuples transitively contained in `parameters` were flattened.
6326 * parameters = Array of `Parameter` to iterate over
6327 * nth = Index of the desired parameter.
6330 * The parameter at index `nth` (taking tuples into account),
6331 * or `null` if out of bound.
6333 static Parameter
getNth(Parameters
* parameters
, size_t nth
)
6337 int getNthParamDg(size_t n
, Parameter p
)
6347 int res
= _foreach(parameters
, &getNthParamDg
);
6348 return res ? param
: null;
6351 /// Type of delegate when iterating solely on the parameters
6352 alias ForeachDg
= extern (D
) int delegate(size_t paramidx
, Parameter param
);
6353 /// Type of delegate when iterating on both the original set of parameters,
6354 /// and the type tuple. Useful for semantic analysis.
6355 /// 'o' stands for 'original' and 'e' stands for 'expanded'.
6356 alias SemanticForeachDg
= extern (D
) int delegate(
6357 size_t oidx
, Parameter oparam
, size_t eidx
, Parameter eparam
);
6359 /***************************************
6360 * Expands tuples in args in depth first order. Calls
6361 * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
6362 * If dg returns !=0, stops and returns that value else returns 0.
6363 * Use this function to avoid the O(N + N^2/2) complexity of
6364 * calculating dim and calling N times getNth.
6366 extern (D
) static int _foreach(Parameters
* parameters
, scope ForeachDg dg
)
6368 assert(dg
!is null);
6369 return _foreach(parameters
, (_oidx
, _oparam
, idx
, param
) => dg(idx
, param
));
6373 extern (D
) static int _foreach(
6374 Parameters
* parameters
, scope SemanticForeachDg dg
)
6376 assert(dg
!is null);
6377 if (parameters
is null)
6381 foreach (oidx
; 0 .. parameters
.length
)
6383 Parameter oparam
= (*parameters
)[oidx
];
6384 if (auto r
= _foreachImpl(dg
, oidx
, oparam
, eidx
, /* eparam */ oparam
))
6390 /// Implementation of the iteration process, which recurses in itself
6391 /// and just forwards `oidx` and `oparam`.
6392 extern (D
) private static int _foreachImpl(scope SemanticForeachDg dg
,
6393 size_t oidx
, Parameter oparam
, ref size_t eidx
, Parameter eparam
)
6398 Type t
= eparam
.type
.toBasetype();
6399 if (auto tu
= t
.isTypeTuple())
6401 // Check for empty tuples
6402 if (tu
.arguments
is null)
6405 foreach (nidx
; 0 .. tu
.arguments
.length
)
6407 Parameter nextep
= (*tu
.arguments
)[nidx
];
6408 if (auto r
= _foreachImpl(dg
, oidx
, oparam
, eidx
, nextep
))
6414 if (auto r
= dg(oidx
, oparam
, eidx
, eparam
))
6416 // The only place where we should increment eidx is here,
6417 // as a TypeTuple doesn't count as a parameter (for arity)
6424 override const(char)* toChars() const
6426 return ident ? ident
.toChars() : "__anonymous_param";
6429 /*********************************
6430 * Compute covariance of parameters `this` and `p`
6431 * as determined by the storage classes of both.
6434 * returnByRef = true if the function returns by ref
6435 * p = Parameter to compare with
6436 * previewIn = Whether `-preview=in` is being used, and thus if
6437 * `in` means `scope [ref]`.
6440 * true = `this` can be used in place of `p`
6443 bool isCovariant(bool returnByRef
, const Parameter p
, bool previewIn
= global
.params
.previewIn
)
6444 const pure nothrow @nogc @safe
6446 ulong thisSTC
= this.storageClass
;
6447 ulong otherSTC
= p
.storageClass
;
6451 if (thisSTC
& STC
.in_
)
6452 thisSTC |
= STC
.scope_
;
6453 if (otherSTC
& STC
.in_
)
6454 otherSTC |
= STC
.scope_
;
6457 const mask
= STC
.ref_ | STC
.out_ | STC
.lazy_ |
(previewIn ? STC
.in_
: 0);
6458 if ((thisSTC
& mask
) != (otherSTC
& mask
))
6460 return isCovariantScope(returnByRef
, thisSTC
, otherSTC
);
6463 extern (D
) static bool isCovariantScope(bool returnByRef
, StorageClass from
, StorageClass to
) pure nothrow @nogc @safe
6465 // Workaround for failing covariance when finding a common type of delegates,
6466 // some of which have parameters with inferred scope
6467 // https://issues.dlang.org/show_bug.cgi?id=21285
6468 // The root cause is that scopeinferred is not part of the mangle, and mangle
6469 // is used for type equality checks
6470 if (to
& STC
.returninferred
)
6472 // note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope
6473 if (to
& STC
.scopeinferred
&& !(to
& STC
.return_
))
6479 /* result is true if the 'from' can be used as a 'to'
6482 if ((from ^ to
) & STC
.ref_
) // differing in 'ref' means no covariance
6485 /* workaround until we get STC.returnScope reliably set correctly
6489 from
&= ~STC
.returnScope
;
6490 to
&= ~STC
.returnScope
;
6494 from |
= STC
.returnScope
;
6495 to |
= STC
.returnScope
;
6497 return covariant
[buildScopeRef(from
)][buildScopeRef(to
)];
6500 extern (D
) private static bool[ScopeRef
.max
+ 1][ScopeRef
.max
+ 1] covariantInit() pure nothrow @nogc @safe
6502 /* Initialize covariant[][] with this:
6509 From\To r rr rs rr-s r-rs
6514 Ref-ReturnScope X X X
6516 bool[ScopeRef
.max
+ 1][ScopeRef
.max
+ 1] covariant
;
6518 foreach (i
; 0 .. ScopeRef
.max
+ 1)
6520 covariant
[i
][i
] = true;
6521 covariant
[ScopeRef
.RefScope
][i
] = true;
6523 covariant
[ScopeRef
.ReturnScope
][ScopeRef
.None
] = true;
6524 covariant
[ScopeRef
.Scope
][ScopeRef
.None
] = true;
6525 covariant
[ScopeRef
.Scope
][ScopeRef
.ReturnScope
] = true;
6527 covariant
[ScopeRef
.Ref
][ScopeRef
.ReturnRef
] = true;
6528 covariant
[ScopeRef
.ReturnRef_Scope
][ScopeRef
.ReturnRef
] = true;
6529 covariant
[ScopeRef
.Ref_ReturnScope
][ScopeRef
.Ref
] = true;
6530 covariant
[ScopeRef
.Ref_ReturnScope
][ScopeRef
.ReturnRef
] = true;
6535 extern (D
) private static immutable bool[ScopeRef
.max
+ 1][ScopeRef
.max
+ 1] covariant
= covariantInit();
6537 extern (D
) bool opEquals(const Parameter other
) const
6539 return this.storageClass
== other
.storageClass
6540 && this.type
== other
.type
;
6544 /*************************************************************
6545 * For printing two types with qualification when necessary.
6547 * t1 = The first type to receive the type name for
6548 * t2 = The second type to receive the type name for
6550 * The fully-qualified names of both types if the two type names are not the same,
6551 * or the unqualified names of both types if the two type names are the same.
6553 const(char*)[2] toAutoQualChars(Type t1
, Type t2
)
6555 auto s1
= t1
.toChars();
6556 auto s2
= t2
.toChars();
6557 // show qualification only if it's different
6558 if (!t1
.equals(t2
) && strcmp(s1
, s2
) == 0)
6560 s1
= t1
.toPrettyChars(true);
6561 s2
= t2
.toPrettyChars(true);
6568 * For each active modifier (MODFlags.const_, MODFlags.immutable_, etc) call `fp` with a
6569 * void* for the work param and a string representation of the attribute.
6571 void modifiersApply(const TypeFunction tf
, void delegate(string
) dg
)
6573 immutable ubyte[4] modsArr
= [MODFlags
.const_
, MODFlags
.immutable_
, MODFlags
.wild
, MODFlags
.shared_
];
6575 foreach (modsarr
; modsArr
)
6577 if (tf
.mod
& modsarr
)
6579 dg(MODtoString(modsarr
));
6585 * For each active attribute (ref/const/nogc/etc) call `fp` with a void* for the
6586 * work param and a string representation of the attribute.
6588 void attributesApply(const TypeFunction tf
, void delegate(string
) dg
, TRUSTformat trustFormat
= TRUSTformatDefault
)
6600 if (tf
.isreturn
&& !tf
.isreturninferred
)
6602 if (tf
.isScopeQual
&& !tf
.isscopeinferred
)
6607 TRUST trustAttrib
= tf
.trust
;
6609 if (trustAttrib
== TRUST
.default_
)
6611 if (trustFormat
!= TRUSTformatSystem
)
6613 trustAttrib
= TRUST
.system
; // avoid calling with an empty string
6616 dg(trustToString(trustAttrib
));
6620 * If the type is a class or struct, returns the symbol for it,
6623 extern (C
++) AggregateDeclaration
isAggregate(Type t
)
6627 return (cast(TypeClass
)t
).sym
;
6628 if (t
.ty
== Tstruct
)
6629 return (cast(TypeStruct
)t
).sym
;
6633 /***************************************************
6634 * Determine if type t can be indexed or sliced given that it is not an
6635 * aggregate with operator overloads.
6639 * true if an expression of type t can be e1 in an array expression
6641 bool isIndexableNonAggregate(Type t
)
6644 return (t
.ty
== Tpointer || t
.ty
== Tsarray || t
.ty
== Tarray || t
.ty
== Taarray ||
6645 t
.ty
== Ttuple || t
.ty
== Tvector
);
6648 /***************************************************
6649 * Determine if type t is copyable.
6653 * true if we can copy it
6655 bool isCopyable(Type t
)
6657 //printf("isCopyable() %s\n", t.toChars());
6658 if (auto ts
= t
.isTypeStruct())
6660 if (ts
.sym
.postblit
&&
6661 ts
.sym
.postblit
.storage_class
& STC
.disable
)
6663 if (ts
.sym
.hasCopyCtor
)
6665 // check if there is a matching overload of the copy constructor and whether it is disabled or not
6666 // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
6667 Dsymbol ctor
= search_function(ts
.sym
, Id
.ctor
);
6669 scope el
= new IdentifierExp(Loc
.initial
, Id
.p
); // dummy lvalue
6670 el
.type
= cast() ts
;
6671 Expressions
* args
= new Expressions();
6673 FuncDeclaration f
= resolveFuncCall(Loc
.initial
, null, ctor
, null, cast()ts
, ArgumentList(args
), FuncResolveFlag
.quiet
);
6674 if (!f || f
.storage_class
& STC
.disable
)
6681 /***************************************
6682 * Computes how a parameter may be returned.
6683 * Shrinking the representation is necessary because StorageClass is so wide
6685 * stc = storage class of parameter
6687 * value from enum ScopeRef
6689 ScopeRef
buildScopeRef(StorageClass
stc) pure nothrow @nogc @safe
6692 stc |
= STC
.ref_
; // treat `out` and `ref` the same
6695 final switch (stc & (STC
.ref_ | STC
.scope_ | STC
.return_
))
6697 case 0: result
= ScopeRef
.None
; break;
6699 /* can occur in case test/compilable/testsctreturn.d
6700 * related to https://issues.dlang.org/show_bug.cgi?id=20149
6701 * where inout adds `return` without `scope` or `ref`
6703 case STC
.return_
: result
= ScopeRef
.Return
; break;
6705 case STC
.ref_
: result
= ScopeRef
.Ref
; break;
6706 case STC
.scope_
: result
= ScopeRef
.Scope
; break;
6707 case STC
.return_ | STC
.ref_
: result
= ScopeRef
.ReturnRef
; break;
6708 case STC
.return_ | STC
.scope_
: result
= ScopeRef
.ReturnScope
; break;
6709 case STC
.ref_ | STC
.scope_
: result
= ScopeRef
.RefScope
; break;
6711 case STC
.return_ | STC
.ref_ | STC
.scope_
:
6712 result
= stc & STC
.returnScope ? ScopeRef
.Ref_ReturnScope
6713 : ScopeRef
.ReturnRef_Scope
;
6720 * Classification of 'scope-return-ref' possibilities
6735 /*********************************
6736 * Give us a nice string for debugging purposes.
6740 * corresponding string
6742 const(char)* toChars(ScopeRef sr
) pure nothrow @nogc @safe
6746 static immutable char*[ScopeRef
.max
+ 1] names
=
6750 ReturnScope
: "ReturnScope",
6752 ReturnRef
: "ReturnRef",
6753 RefScope
: "RefScope",
6754 ReturnRef_Scope
: "ReturnRef_Scope",
6755 Ref_ReturnScope
: "Ref_ReturnScope",
6763 * Creates an appropriate vector type for `tv` that will hold one boolean
6764 * result for each element of the vector type. The result of vector comparisons
6765 * is a single or doubleword mask of all 1s (comparison true) or all 0s
6766 * (comparison false). This SIMD mask type does not have an equivalent D type,
6767 * however its closest equivalent would be an integer vector of the same unit
6771 * tv = The `TypeVector` to build a vector from.
6773 * A vector type suitable for the result of a vector comparison operation.
6775 TypeVector
toBooleanVector(TypeVector tv
)
6777 Type telem
= tv
.elementType();
6789 // No need to build an equivalent mask type.
6793 telem
= Type
.tuns32
;
6797 telem
= Type
.tuns64
;
6804 TypeSArray tsa
= tv
.basetype
.isTypeSArray();
6805 assert(tsa
!is null);
6807 return new TypeVector(new TypeSArray(telem
, tsa
.dim
));
6810 /*************************************************
6811 * Dispatch to function based on static type of Type.
6813 mixin template VisitType(Result
)
6815 Result
VisitType(Type t
)
6831 case TY
.Timaginary32
:
6832 case TY
.Timaginary64
:
6833 case TY
.Timaginary80
:
6842 case TY
.Tuns128
: mixin(visitTYCase("Basic"));
6843 case TY
.Tarray
: mixin(visitTYCase("DArray"));
6844 case TY
.Tsarray
: mixin(visitTYCase("SArray"));
6845 case TY
.Taarray
: mixin(visitTYCase("AArray"));
6846 case TY
.Tpointer
: mixin(visitTYCase("Pointer"));
6847 case TY
.Treference
: mixin(visitTYCase("Reference"));
6848 case TY
.Tfunction
: mixin(visitTYCase("Function"));
6849 case TY
.Tident
: mixin(visitTYCase("Identifier"));
6850 case TY
.Tclass
: mixin(visitTYCase("Class"));
6851 case TY
.Tstruct
: mixin(visitTYCase("Struct"));
6852 case TY
.Tenum
: mixin(visitTYCase("Enum"));
6853 case TY
.Tdelegate
: mixin(visitTYCase("Delegate"));
6854 case TY
.Terror
: mixin(visitTYCase("Error"));
6855 case TY
.Tinstance
: mixin(visitTYCase("Instance"));
6856 case TY
.Ttypeof
: mixin(visitTYCase("Typeof"));
6857 case TY
.Ttuple
: mixin(visitTYCase("Tuple"));
6858 case TY
.Tslice
: mixin(visitTYCase("Slice"));
6859 case TY
.Treturn
: mixin(visitTYCase("Return"));
6860 case TY
.Tnull
: mixin(visitTYCase("Null"));
6861 case TY
.Tvector
: mixin(visitTYCase("Vector"));
6862 case TY
.Ttraits
: mixin(visitTYCase("Traits"));
6863 case TY
.Tmixin
: mixin(visitTYCase("Mixin"));
6864 case TY
.Tnoreturn
: mixin(visitTYCase("Noreturn"));
6865 case TY
.Ttag
: mixin(visitTYCase("Tag"));
6866 case TY
.Tnone
: assert(0);
6871 /****************************************
6872 * CTFE-only helper function for VisitInitializer.
6874 * handler = string for the name of the visit handler
6875 * Returns: boilerplate code for a case
6877 pure string
visitTYCase(string handler
) @safe
6883 enum isVoid = is(Result == void);
6884 auto tx = t.isType"~handler
~"();
6885 static if (__traits(compiles, visit"~handler
~"(tx)))
6889 visit"~handler
~"(tx);
6894 if (Result r = visit"~handler
~"(tx))
6899 else static if (__traits(compiles, visitDefaultCase(t)))
6903 visitDefaultCase(tx);
6908 if (Result r = visitDefaultCase(t))
6914 static assert(0, "~handler
~");
6923 * `TypeIdentifier` corresponding to `object.Throwable`
6925 TypeIdentifier
getThrowable()
6927 auto tid
= new TypeIdentifier(Loc
.initial
, Id
.empty
);
6928 tid
.addIdent(Id
.object
);
6929 tid
.addIdent(Id
.Throwable
);
6935 * TypeIdentifier corresponding to `object.Exception`
6937 TypeIdentifier
getException()
6939 auto tid
= new TypeIdentifier(Loc
.initial
, Id
.empty
);
6940 tid
.addIdent(Id
.object
);
6941 tid
.addIdent(Id
.Exception
);
6945 /**************************************
6946 * Check and set 'att' if 't' is a recursive 'alias this' type
6948 * The goal is to prevent endless loops when there is a cycle in the alias this chain.
6949 * Since there is no multiple `alias this`, the chain either ends in a leaf,
6950 * or it loops back on itself as some point.
6952 * Example: S0 -> (S1 -> S2 -> S3 -> S1)
6954 * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
6955 * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
6956 * this still returns `false`, but `att1` is set to `S1`.
6957 * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
6958 * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
6961 * att = type reference used to detect recursion. Should be initialized to `null`.
6962 * t = type of 'alias this' rewrite to attempt
6965 * `false` if the rewrite is safe, `true` if it would loop back around
6967 bool isRecursiveAliasThis(ref Type att
, Type t
)
6969 //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
6970 auto tb
= t
.toBasetype();
6971 if (att
&& tb
.equivalent(att
))
6973 else if (!att
&& tb
.checkAliasThisRec())