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