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