1 /**
2  * Semantic analysis for D types.
3  *
4  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d)
8  * Documentation:  https://dlang.org/phobos/dmd_typesem.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d
10  */
11 
12 module dmd.typesem;
13 
14 import core.checkedint;
15 import core.stdc.string;
16 import core.stdc.stdio;
17 
18 import dmd.access;
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arrayop;
22 import dmd.arraytypes;
23 import dmd.astcodegen;
24 import dmd.astenums;
25 import dmd.dcast;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dimport;
30 import dmd.dmangle;
31 import dmd.dmodule;
32 import dmd.dscope;
33 import dmd.dstruct;
34 import dmd.dsymbol;
35 import dmd.dsymbolsem;
36 import dmd.dtemplate;
37 import dmd.errors;
38 import dmd.errorsink;
39 import dmd.expression;
40 import dmd.expressionsem;
41 import dmd.func;
42 import dmd.globals;
43 import dmd.hdrgen;
44 import dmd.id;
45 import dmd.identifier;
46 import dmd.imphint;
47 import dmd.importc;
48 import dmd.init;
49 import dmd.initsem;
50 import dmd.location;
51 import dmd.visitor;
52 import dmd.mtype;
53 import dmd.objc;
54 import dmd.opover;
55 import dmd.parse;
56 import dmd.root.complex;
57 import dmd.root.ctfloat;
58 import dmd.root.rmem;
59 import dmd.common.outbuffer;
60 import dmd.root.rootobject;
61 import dmd.root.string;
62 import dmd.root.stringtable;
63 import dmd.safe;
64 import dmd.semantic3;
65 import dmd.sideeffect;
66 import dmd.target;
67 import dmd.tokens;
68 
69 /*************************************
70  * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
71  * Setting one of pe/pt/ps.
72  * Params:
73  *      loc = location for error messages
74  *      sc = context
75  *      s = symbol being indexed - could be a tuple, could be an expression
76  *      pe = set if s[oindex] is an Expression, otherwise null
77  *      pt = set if s[oindex] is a Type, otherwise null
78  *      ps = set if s[oindex] is a Dsymbol, otherwise null
79  *      oindex = index into s
80  */
81 private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
82 {
83     auto tup = s.isTupleDeclaration();
84 
85     auto eindex = isExpression(oindex);
86     auto tindex = isType(oindex);
87     auto sindex = isDsymbol(oindex);
88 
89     if (!tup)
90     {
91         // It's really an index expression
92         if (tindex)
93             eindex = new TypeExp(loc, tindex);
94         else if (sindex)
95             eindex = symbolToExp(sindex, loc, sc, false);
96         Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex);
97         e = e.expressionSemantic(sc);
98         resolveExp(e, pt, pe, ps);
99         return;
100     }
101 
102     // Convert oindex to Expression, then try to resolve to constant.
103     if (tindex)
104         tindex.resolve(loc, sc, eindex, tindex, sindex);
105     if (sindex)
106         eindex = symbolToExp(sindex, loc, sc, false);
107     if (!eindex)
108     {
109         .error(loc, "index `%s` is not an expression", oindex.toChars());
110         pt = Type.terror;
111         return;
112     }
113 
114     eindex = semanticLength(sc, tup, eindex);
115     eindex = eindex.ctfeInterpret();
116     if (eindex.op == EXP.error)
117     {
118         pt = Type.terror;
119         return;
120     }
121     const(uinteger_t) d = eindex.toUInteger();
122     if (d >= tup.objects.length)
123     {
124         .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong)tup.objects.length);
125         pt = Type.terror;
126         return;
127     }
128 
129     RootObject o = (*tup.objects)[cast(size_t)d];
130     ps = isDsymbol(o);
131     if (auto t = isType(o))
132         pt = t.typeSemantic(loc, sc);
133     if (auto e = isExpression(o))
134         resolveExp(e, pt, pe, ps);
135 }
136 
137 /*************************************
138  * Takes an array of Identifiers and figures out if
139  * it represents a Type, Expression, or Dsymbol.
140  * Params:
141  *      mt = array of identifiers
142  *      loc = location for error messages
143  *      sc = context
144  *      s = symbol to start search at
145  *      scopesym = unused
146  *      pe = set if expression otherwise null
147  *      pt = set if type otherwise null
148  *      ps = set if symbol otherwise null
149  *      typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
150  */
151 private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
152     out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
153 {
154     version (none)
155     {
156         printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars());
157         if (scopesym)
158             printf("\tscopesym = '%s'\n", scopesym.toChars());
159     }
160 
161     if (!s)
162     {
163         /* Look for what user might have intended
164          */
165         const p = mt.mutableOf().unSharedOf().toChars();
166         auto id = Identifier.idPool(p, cast(uint)strlen(p));
167         if (const n = importHint(id.toString()))
168             error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr);
169         else if (auto s2 = sc.search_correct(id))
170             error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
171         else if (const q = Scope.search_correct_C(id))
172             error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
173         else if ((id == Id.This   && sc.getStructClassScope()) ||
174                  (id == Id._super && sc.getClassScope()))
175             error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
176         else
177             error(loc, "undefined identifier `%s`", p);
178 
179         pt = Type.terror;
180         return;
181     }
182 
183     //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
184     Declaration d = s.isDeclaration();
185     if (d && (d.storage_class & STC.templateparameter))
186         s = s.toAlias();
187     else
188     {
189         // check for deprecated or disabled aliases
190         // functions are checked after overloading
191         // templates are checked after matching constraints
192         if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
193             s.checkDeprecated(loc, sc);
194         if (d)
195             d.checkDisabled(loc, sc, true);
196     }
197     s = s.toAlias();
198     //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
199     for (size_t i = 0; i < mt.idents.length; i++)
200     {
201         RootObject id = mt.idents[i];
202         switch (id.dyncast()) with (DYNCAST)
203         {
204         case expression:
205         case type:
206             Type tx;
207             Expression ex;
208             Dsymbol sx;
209             resolveTupleIndex(loc, sc, s, ex, tx, sx, id);
210             if (sx)
211             {
212                 s = sx.toAlias();
213                 continue;
214             }
215             if (tx)
216                 ex = new TypeExp(loc, tx);
217             assert(ex);
218 
219             ex = typeToExpressionHelper(mt, ex, i + 1);
220             ex = ex.expressionSemantic(sc);
221             resolveExp(ex, pt, pe, ps);
222             return;
223         default:
224             break;
225         }
226 
227         Type t = s.getType(); // type symbol, type alias, or type tuple?
228         uint errorsave = global.errors;
229         int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
230 
231         Dsymbol sm = s.searchX(loc, sc, id, flags);
232         if (sm)
233         {
234             if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
235             {
236                 .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
237                 sm = null;
238             }
239             // Same check as in dotIdSemanticProp(DotIdExp)
240             else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
241             {
242                 // @@@DEPRECATED_2.106@@@
243                 // Should be an error in 2.106. Just remove the deprecation call
244                 // and uncomment the null assignment
245                 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
246                 //sm = null;
247             }
248         }
249         if (global.errors != errorsave)
250         {
251             pt = Type.terror;
252             return;
253         }
254 
255         void helper3()
256         {
257             Expression e;
258             VarDeclaration v = s.isVarDeclaration();
259             FuncDeclaration f = s.isFuncDeclaration();
260             if (intypeid || !v && !f)
261                 e = symbolToExp(s, loc, sc, true);
262             else
263                 e = new VarExp(loc, s.isDeclaration(), true);
264 
265             e = typeToExpressionHelper(mt, e, i);
266             e = e.expressionSemantic(sc);
267             resolveExp(e, pt, pe, ps);
268         }
269 
270         //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
271         if (intypeid && !t && sm && sm.needThis())
272             return helper3();
273 
274         if (VarDeclaration v = s.isVarDeclaration())
275         {
276             // https://issues.dlang.org/show_bug.cgi?id=19913
277             // v.type would be null if it is a forward referenced member.
278             if (v.type is null)
279                 v.dsymbolSemantic(sc);
280             if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
281                 v.type.isConst() || v.type.isImmutable())
282             {
283                 // https://issues.dlang.org/show_bug.cgi?id=13087
284                 // this.field is not constant always
285                 if (!v.isThisDeclaration())
286                     return helper3();
287             }
288         }
289 
290         if (!sm)
291             return helper3();
292 
293         if (sm.isAliasDeclaration)
294             sm.checkDeprecated(loc, sc);
295         s = sm.toAlias();
296     }
297 
298     if (auto em = s.isEnumMember())
299     {
300         // It's not a type, it's an expression
301         pe = em.getVarExp(loc, sc);
302         return;
303     }
304     if (auto v = s.isVarDeclaration())
305     {
306         /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
307          * because some variables used in type context need to prevent lowering
308          * to a literal or contextful expression. For example:
309          *
310          *  enum a = 1; alias b = a;
311          *  template X(alias e){ alias v = e; }  alias x = X!(1);
312          *  struct S { int v; alias w = v; }
313          *      // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
314          *      // because getDsymbol() need to work in AliasDeclaration::semantic().
315          */
316         if (!v.type ||
317             !v.type.deco && v.inuse)
318         {
319             if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
320                 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
321             else
322                 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
323             pt = Type.terror;
324             return;
325         }
326         if (v.type.ty == Terror)
327             pt = Type.terror;
328         else
329             pe = new VarExp(loc, v);
330         return;
331     }
332     if (auto fld = s.isFuncLiteralDeclaration())
333     {
334         //printf("'%s' is a function literal\n", fld.toChars());
335         auto e = new FuncExp(loc, fld);
336         pe = e.expressionSemantic(sc);
337         return;
338     }
339     version (none)
340     {
341         if (FuncDeclaration fd = s.isFuncDeclaration())
342         {
343             pe = new DsymbolExp(loc, fd);
344             return;
345         }
346     }
347 
348     Type t;
349     while (1)
350     {
351         t = s.getType();
352         if (t)
353             break;
354         ps = s;
355         return;
356     }
357 
358     if (auto ti = t.isTypeInstance())
359         if (ti != mt && !ti.deco)
360         {
361             if (!ti.tempinst.errors)
362                 error(loc, "forward reference to `%s`", ti.toChars());
363             pt = Type.terror;
364             return;
365         }
366 
367     if (t.ty == Ttuple)
368         pt = t;
369     else
370         pt = t.merge();
371 }
372 
373 /******************************************
374  * We've mistakenly parsed `t` as a type.
375  * Redo `t` as an Expression only if there are no type modifiers.
376  * Params:
377  *      t = mistaken type
378  * Returns:
379  *      t redone as Expression, null if cannot
380  */
381 Expression typeToExpression(Type t)
382 {
383     static Expression visitSArray(TypeSArray t)
384     {
385         if (auto e = t.next.typeToExpression())
386             return new ArrayExp(t.dim.loc, e, t.dim);
387         return null;
388     }
389 
390     static Expression visitAArray(TypeAArray t)
391     {
392         if (auto e = t.next.typeToExpression())
393         {
394             if (auto ei = t.index.typeToExpression())
395                 return new ArrayExp(t.loc, e, ei);
396         }
397         return null;
398     }
399 
400     static Expression visitIdentifier(TypeIdentifier t)
401     {
402         return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident));
403     }
404 
405     static Expression visitInstance(TypeInstance t)
406     {
407         return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst));
408     }
409 
410     // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
411     static Expression visitMixin(TypeMixin t)
412     {
413         return new TypeExp(t.loc, t);
414     }
415 
416     if (t.mod)
417         return null;
418     switch (t.ty)
419     {
420         case Tsarray:   return visitSArray(t.isTypeSArray());
421         case Taarray:   return visitAArray(t.isTypeAArray());
422         case Tident:    return visitIdentifier(t.isTypeIdentifier());
423         case Tinstance: return visitInstance(t.isTypeInstance());
424         case Tmixin:    return visitMixin(t.isTypeMixin());
425         default:        return null;
426     }
427 }
428 
429 /******************************************
430  * Perform semantic analysis on a type.
431  * Params:
432  *      type = Type AST node
433  *      loc = the location of the type
434  *      sc = context
435  * Returns:
436  *      `Type` with completed semantic analysis, `Terror` if errors
437  *      were encountered
438  */
439 extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
440 {
441     static Type error()
442     {
443         return Type.terror;
444     }
445 
446     Type visitType(Type t)
447     {
448         // @@@DEPRECATED_2.110@@@
449         // Use of `cent` and `ucent` has always been an error.
450         // Starting from 2.100, recommend core.int128 as a replace for the
451         // lack of compiler support.
452         if (t.ty == Tint128 || t.ty == Tuns128)
453         {
454             .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
455             return error();
456         }
457 
458         return t.merge();
459     }
460 
461     Type visitComplex(TypeBasic t)
462     {
463         if (!(sc.flags & SCOPE.Cfile))
464             return visitType(t);
465 
466         auto tc = getComplexLibraryType(loc, sc, t.ty);
467         if (tc.ty == Terror)
468             return tc;
469         return tc.addMod(t.mod).merge();
470     }
471 
472     Type visitVector(TypeVector mtype)
473     {
474         const errors = global.errors;
475         mtype.basetype = mtype.basetype.typeSemantic(loc, sc);
476         if (errors != global.errors)
477             return error();
478         mtype.basetype = mtype.basetype.toBasetype().mutableOf();
479         if (mtype.basetype.ty != Tsarray)
480         {
481             .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
482             return error();
483         }
484         TypeSArray t = mtype.basetype.isTypeSArray();
485         const sz = cast(int)t.size(loc);
486         final switch (target.isVectorTypeSupported(sz, t.nextOf()))
487         {
488         case 0:
489             // valid
490             break;
491 
492         case 1:
493             // no support at all
494             .error(loc, "SIMD vector types not supported on this platform");
495             return error();
496 
497         case 2:
498             // invalid base type
499             .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars());
500             return error();
501 
502         case 3:
503             // invalid size
504             .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars());
505             return error();
506         }
507         return merge(mtype);
508     }
509 
510     Type visitSArray(TypeSArray mtype)
511     {
512         //printf("TypeSArray::semantic() %s\n", toChars());
513         Type t;
514         Expression e;
515         Dsymbol s;
516         mtype.next.resolve(loc, sc, e, t, s);
517 
518         if (auto tup = s ? s.isTupleDeclaration() : null)
519         {
520             mtype.dim = semanticLength(sc, tup, mtype.dim);
521             mtype.dim = mtype.dim.ctfeInterpret();
522             if (mtype.dim.op == EXP.error)
523                 return error();
524 
525             uinteger_t d = mtype.dim.toUInteger();
526             if (d >= tup.objects.length)
527             {
528                 .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tup.objects.length);
529                 return error();
530             }
531 
532             RootObject o = (*tup.objects)[cast(size_t)d];
533             if (o.dyncast() != DYNCAST.type)
534             {
535                 .error(loc, "`%s` is not a type", mtype.toChars());
536                 return error();
537             }
538             return (cast(Type)o).addMod(mtype.mod);
539         }
540 
541         if (t && t.ty == Terror)
542             return error();
543 
544         Type tn = mtype.next.typeSemantic(loc, sc);
545         if (tn.ty == Terror)
546             return error();
547 
548         Type tbn = tn.toBasetype();
549         if (mtype.dim)
550         {
551             auto errors = global.errors;
552             mtype.dim = semanticLength(sc, tbn, mtype.dim);
553             mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
554             if (errors != global.errors)
555                 return error();
556 
557             mtype.dim = mtype.dim.optimize(WANTvalue);
558             mtype.dim = mtype.dim.ctfeInterpret();
559             if (mtype.dim.op == EXP.error)
560                 return error();
561 
562             errors = global.errors;
563             dinteger_t d1 = mtype.dim.toInteger();
564             if (errors != global.errors)
565                 return error();
566 
567             mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
568             mtype.dim = mtype.dim.optimize(WANTvalue);
569             if (mtype.dim.op == EXP.error)
570                 return error();
571 
572             errors = global.errors;
573             dinteger_t d2 = mtype.dim.toInteger();
574             if (errors != global.errors)
575                 return error();
576 
577             if (mtype.dim.op == EXP.error)
578                 return error();
579 
580             Type overflowError()
581             {
582                 .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
583                         mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize);
584                 return error();
585             }
586 
587             if (d1 != d2)
588                 return overflowError();
589 
590             Type tbx = tbn.baseElemOf();
591             if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members ||
592                 tbx.ty == Tenum && !tbx.isTypeEnum().sym.members)
593             {
594                 /* To avoid meaningless error message, skip the total size limit check
595                  * when the bottom of element type is opaque.
596                  */
597             }
598             else if (tbn.isTypeBasic() ||
599                      tbn.ty == Tpointer ||
600                      tbn.ty == Tarray ||
601                      tbn.ty == Tsarray ||
602                      tbn.ty == Taarray ||
603                      (tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) ||
604                      tbn.ty == Tclass)
605             {
606                 /* Only do this for types that don't need to have semantic()
607                  * run on them for the size, since they may be forward referenced.
608                  */
609                 bool overflow = false;
610                 if (mulu(tbn.size(loc), d2, overflow) > target.maxStaticDataSize || overflow)
611                     return overflowError();
612             }
613         }
614         switch (tbn.ty)
615         {
616         case Ttuple:
617             {
618                 // Index the tuple to get the type
619                 assert(mtype.dim);
620                 TypeTuple tt = tbn.isTypeTuple();
621                 uinteger_t d = mtype.dim.toUInteger();
622                 if (d >= tt.arguments.length)
623                 {
624                     .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tt.arguments.length);
625                     return error();
626                 }
627                 Type telem = (*tt.arguments)[cast(size_t)d].type;
628                 return telem.addMod(mtype.mod);
629             }
630 
631         case Tfunction:
632         case Tnone:
633             .error(loc, "cannot have array of `%s`", tbn.toChars());
634             return error();
635 
636         default:
637             break;
638         }
639         if (tbn.isscope())
640         {
641             .error(loc, "cannot have array of scope `%s`", tbn.toChars());
642             return error();
643         }
644 
645         /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
646          * and const(T)[3] become const(T[3])
647          */
648         mtype.next = tn;
649         mtype.transitive();
650         return mtype.addMod(tn.mod).merge();
651     }
652 
653     Type visitDArray(TypeDArray mtype)
654     {
655         Type tn = mtype.next.typeSemantic(loc, sc);
656         Type tbn = tn.toBasetype();
657         switch (tbn.ty)
658         {
659         case Ttuple:
660             return tbn;
661 
662         case Tfunction:
663         case Tnone:
664             .error(loc, "cannot have array of `%s`", tbn.toChars());
665             return error();
666 
667         case Terror:
668             return error();
669 
670         default:
671             break;
672         }
673         if (tn.isscope())
674         {
675             .error(loc, "cannot have array of scope `%s`", tn.toChars());
676             return error();
677         }
678         mtype.next = tn;
679         mtype.transitive();
680         return merge(mtype);
681     }
682 
683     Type visitAArray(TypeAArray mtype)
684     {
685         //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
686         if (mtype.deco)
687         {
688             return mtype;
689         }
690 
691         mtype.loc = loc;
692         if (sc)
693             sc.setNoFree();
694 
695         // Deal with the case where we thought the index was a type, but
696         // in reality it was an expression.
697         if (mtype.index.ty == Tident || mtype.index.ty == Tinstance || mtype.index.ty == Tsarray || mtype.index.ty == Ttypeof || mtype.index.ty == Treturn || mtype.index.ty == Tmixin)
698         {
699             Expression e;
700             Type t;
701             Dsymbol s;
702             mtype.index.resolve(loc, sc, e, t, s);
703 
704             // https://issues.dlang.org/show_bug.cgi?id=15478
705             if (s)
706                 e = symbolToExp(s, loc, sc, false);
707 
708             if (e)
709             {
710                 // It was an expression -
711                 // Rewrite as a static array
712                 auto tsa = new TypeSArray(mtype.next, e);
713                 return tsa.typeSemantic(loc, sc);
714             }
715             else if (t)
716                 mtype.index = t.typeSemantic(loc, sc);
717             else
718             {
719                 .error(loc, "index is not a type or an expression");
720                 return error();
721             }
722         }
723         else
724             mtype.index = mtype.index.typeSemantic(loc, sc);
725         mtype.index = mtype.index.merge2();
726 
727         if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable())
728         {
729             mtype.index = mtype.index.constOf().mutableOf();
730             version (none)
731             {
732                 printf("index is %p %s\n", mtype.index, mtype.index.toChars());
733                 mtype.index.check();
734                 printf("index.mod = x%x\n", mtype.index.mod);
735                 printf("index.ito = x%p\n", mtype.index.getMcache().ito);
736                 if (mtype.index.getMcache().ito)
737                 {
738                     printf("index.ito.mod = x%x\n", mtype.index.getMcache().ito.mod);
739                     printf("index.ito.ito = x%p\n", mtype.index.getMcache().ito.getMcache().ito);
740                 }
741             }
742         }
743 
744         switch (mtype.index.toBasetype().ty)
745         {
746         case Tfunction:
747         case Tvoid:
748         case Tnone:
749         case Ttuple:
750             .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars());
751             goto case Terror;
752         case Terror:
753             return error();
754 
755         default:
756             break;
757         }
758         Type tbase = mtype.index.baseElemOf();
759         while (tbase.ty == Tarray)
760             tbase = tbase.nextOf().baseElemOf();
761         if (auto ts = tbase.isTypeStruct())
762         {
763             /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
764              */
765             StructDeclaration sd = ts.sym;
766             if (sd.semanticRun < PASS.semanticdone)
767                 sd.dsymbolSemantic(null);
768 
769             // duplicate a part of StructDeclaration::semanticTypeInfoMembers
770             //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
771 
772             if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
773             {
774                 uint errors = global.startGagging();
775                 sd.xeq.semantic3(sd.xeq._scope);
776                 if (global.endGagging(errors))
777                     sd.xeq = sd.xerreq;
778             }
779 
780 
781             //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
782             const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : "";
783             if (!sd.xeq)
784             {
785                 // If sd.xhash != NULL:
786                 //   sd or its fields have user-defined toHash.
787                 //   AA assumes that its result is consistent with bitwise equality.
788                 // else:
789                 //   bitwise equality & hashing
790             }
791             else if (sd.xeq == sd.xerreq)
792             {
793                 if (search_function(sd, Id.eq))
794                 {
795                     .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
796                 }
797                 else
798                 {
799                     .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars());
800                 }
801                 return error();
802             }
803             else if (!sd.xhash)
804             {
805                 if (search_function(sd, Id.eq))
806                 {
807                     .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
808                 }
809                 else
810                 {
811                     .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars());
812                 }
813                 return error();
814             }
815             else
816             {
817                 // defined equality & hashing
818                 assert(sd.xeq && sd.xhash);
819 
820                 /* xeq and xhash may be implicitly defined by compiler. For example:
821                  *   struct S { int[] arr; }
822                  * With 'arr' field equality and hashing, compiler will implicitly
823                  * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
824                  */
825             }
826         }
827         else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration())
828         {
829             ClassDeclaration cd = tbase.isTypeClass().sym;
830             if (cd.semanticRun < PASS.semanticdone)
831                 cd.dsymbolSemantic(null);
832 
833             if (!ClassDeclaration.object)
834             {
835                 .error(Loc.initial, "missing or corrupt object.d");
836                 fatal();
837             }
838 
839             __gshared FuncDeclaration feq = null;
840             __gshared FuncDeclaration fcmp = null;
841             __gshared FuncDeclaration fhash = null;
842             if (!feq)
843                 feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
844             if (!fcmp)
845                 fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
846             if (!fhash)
847                 fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
848             assert(fcmp && feq && fhash);
849 
850             if (feq.vtblIndex < cd.vtbl.length && cd.vtbl[feq.vtblIndex] == feq)
851             {
852                 version (all)
853                 {
854                     if (fcmp.vtblIndex < cd.vtbl.length && cd.vtbl[fcmp.vtblIndex] != fcmp)
855                     {
856                         const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : "";
857                         .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars());
858                         errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`.");
859                     }
860                 }
861             }
862         }
863         mtype.next = mtype.next.typeSemantic(loc, sc).merge2();
864         mtype.transitive();
865 
866         switch (mtype.next.toBasetype().ty)
867         {
868         case Tfunction:
869         case Tvoid:
870         case Tnone:
871         case Ttuple:
872             .error(loc, "cannot have associative array of `%s`", mtype.next.toChars());
873             goto case Terror;
874         case Terror:
875             return error();
876         default:
877             break;
878         }
879         if (mtype.next.isscope())
880         {
881             .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
882             return error();
883         }
884         return merge(mtype);
885     }
886 
887     Type visitPointer(TypePointer mtype)
888     {
889         //printf("TypePointer::semantic() %s\n", toChars());
890         if (mtype.deco)
891         {
892             return mtype;
893         }
894         Type n = mtype.next.typeSemantic(loc, sc);
895         switch (n.toBasetype().ty)
896         {
897         case Ttuple:
898             .error(loc, "cannot have pointer to `%s`", n.toChars());
899             goto case Terror;
900         case Terror:
901             return error();
902         default:
903             break;
904         }
905         if (n != mtype.next)
906         {
907             mtype.deco = null;
908         }
909         mtype.next = n;
910         if (mtype.next.ty != Tfunction)
911         {
912             mtype.transitive();
913             return merge(mtype);
914         }
915         version (none)
916         {
917             return merge(mtype);
918         }
919         else
920         {
921             mtype.deco = merge(mtype).deco;
922             /* Don't return merge(), because arg identifiers and default args
923              * can be different
924              * even though the types match
925              */
926             return mtype;
927         }
928     }
929 
930     Type visitReference(TypeReference mtype)
931     {
932         //printf("TypeReference::semantic()\n");
933         Type n = mtype.next.typeSemantic(loc, sc);
934         if (n != mtype.next)
935            mtype.deco = null;
936         mtype.next = n;
937         mtype.transitive();
938         return merge(mtype);
939     }
940 
941     Type visitFunction(TypeFunction mtype)
942     {
943         if (mtype.deco) // if semantic() already run
944         {
945             //printf("already done\n");
946             return mtype;
947         }
948         //printf("TypeFunction::semantic() this = %p\n", mtype);
949         //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc);
950 
951         bool errors = false;
952 
953         if (mtype.inuse > global.recursionLimit)
954         {
955             mtype.inuse = 0;
956             .error(loc, "recursive type");
957             return error();
958         }
959 
960         /* Copy in order to not mess up original.
961          * This can produce redundant copies if inferring return type,
962          * as semantic() will get called again on this.
963          */
964         TypeFunction tf = mtype.copy().toTypeFunction();
965         if (mtype.parameterList.parameters)
966         {
967             tf.parameterList.parameters = mtype.parameterList.parameters.copy();
968             for (size_t i = 0; i < mtype.parameterList.parameters.length; i++)
969             {
970                 Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter));
971                 memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter));
972                 (*tf.parameterList.parameters)[i] = p;
973             }
974         }
975 
976         if (sc.stc & STC.pure_)
977             tf.purity = PURE.fwdref;
978         if (sc.stc & STC.nothrow_)
979             tf.isnothrow = true;
980         if (sc.stc & STC.nogc)
981             tf.isnogc = true;
982         if (sc.stc & STC.ref_)
983             tf.isref = true;
984         if (sc.stc & STC.return_)
985             tf.isreturn = true;
986         if (sc.stc & STC.returnScope)
987             tf.isreturnscope = true;
988         if (sc.stc & STC.returninferred)
989             tf.isreturninferred = true;
990         if (sc.stc & STC.scope_)
991             tf.isScopeQual = true;
992         if (sc.stc & STC.scopeinferred)
993             tf.isscopeinferred = true;
994 
995 //        if (tf.isreturn && !tf.isref)
996 //            tf.isScopeQual = true;                                  // return by itself means 'return scope'
997 
998         if (tf.trust == TRUST.default_)
999         {
1000             if (sc.stc & STC.safe)
1001                 tf.trust = TRUST.safe;
1002             else if (sc.stc & STC.system)
1003                 tf.trust = TRUST.system;
1004             else if (sc.stc & STC.trusted)
1005                 tf.trust = TRUST.trusted;
1006         }
1007 
1008         if (sc.stc & STC.property)
1009             tf.isproperty = true;
1010         if (sc.stc & STC.live)
1011             tf.islive = true;
1012 
1013         tf.linkage = sc.linkage;
1014         if (tf.linkage == LINK.system)
1015             tf.linkage = target.systemLinkage();
1016 
1017         version (none)
1018         {
1019             /* If the parent is @safe, then this function defaults to safe
1020              * too.
1021              * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
1022              * to be inferred first.
1023              */
1024             if (tf.trust == TRUST.default_)
1025                 for (Dsymbol p = sc.func; p; p = p.toParent2())
1026                 {
1027                     FuncDeclaration fd = p.isFuncDeclaration();
1028                     if (fd)
1029                     {
1030                         if (fd.isSafeBypassingInference())
1031                             tf.trust = TRUST.safe; // default to @safe
1032                         break;
1033                     }
1034                 }
1035         }
1036 
1037         bool wildreturn = false;
1038         if (tf.next)
1039         {
1040             sc = sc.push();
1041             sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR);
1042             tf.next = tf.next.typeSemantic(loc, sc);
1043             sc = sc.pop();
1044             errors |= tf.checkRetType(loc);
1045             if (tf.next.isscope() && !tf.isctor)
1046             {
1047                 .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
1048                 errors = true;
1049             }
1050             if (tf.next.hasWild())
1051                 wildreturn = true;
1052 
1053             if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
1054             {
1055                 tf.isreturn = false;
1056             }
1057         }
1058 
1059         /// Perform semantic on the default argument to a parameter
1060         /// Modify the `defaultArg` field of `fparam`, which must not be `null`
1061         /// Returns `false` whether an error was encountered.
1062         static bool defaultArgSemantic (ref Parameter fparam, Scope* sc)
1063         {
1064             Expression e = fparam.defaultArg;
1065             const isRefOrOut = fparam.isReference();
1066             const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref);
1067             if (isRefOrOut && !isAuto)
1068             {
1069                 e = e.expressionSemantic(sc);
1070                 e = resolveProperties(sc, e);
1071             }
1072             else
1073             {
1074                 e = inferType(e, fparam.type);
1075                 Initializer iz = new ExpInitializer(e.loc, e);
1076                 iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
1077                 e = iz.initializerToExpression();
1078             }
1079             if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
1080             {
1081                 FuncExp fe = e.isFuncExp();
1082                 // Replace function literal with a function symbol,
1083                 // since default arg expression must be copied when used
1084                 // and copying the literal itself is wrong.
1085                 e = new VarExp(e.loc, fe.fd, false);
1086                 e = new AddrExp(e.loc, e);
1087                 e = e.expressionSemantic(sc);
1088             }
1089             if (isRefOrOut && (!isAuto || e.isLvalue())
1090                 && !MODimplicitConv(e.type.mod, fparam.type.mod))
1091             {
1092                 const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
1093                 .error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
1094                       e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
1095             }
1096             e = e.implicitCastTo(sc, fparam.type);
1097 
1098             // default arg must be an lvalue
1099             if (isRefOrOut && !isAuto &&
1100                 !(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
1101                 global.params.rvalueRefParam != FeatureState.enabled)
1102                 e = e.toLvalue(sc, e);
1103 
1104             fparam.defaultArg = e;
1105             return (e.op != EXP.error);
1106         }
1107 
1108         ubyte wildparams = 0;
1109         if (tf.parameterList.parameters)
1110         {
1111             /* Create a scope for evaluating the default arguments for the parameters
1112              */
1113             Scope* argsc = sc.push();
1114             argsc.stc = 0; // don't inherit storage class
1115             argsc.visibility = Visibility(Visibility.Kind.public_);
1116             argsc.func = null;
1117 
1118             size_t dim = tf.parameterList.length;
1119             for (size_t i = 0; i < dim; i++)
1120             {
1121                 Parameter fparam = tf.parameterList[i];
1122                 fparam.storageClass |= STC.parameter;
1123                 mtype.inuse++;
1124                 fparam.type = fparam.type.typeSemantic(loc, argsc);
1125                 mtype.inuse--;
1126 
1127                 if (fparam.type.ty == Terror)
1128                 {
1129                     errors = true;
1130                     continue;
1131                 }
1132 
1133                 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
1134 
1135                 if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_))
1136                 {
1137                     if (!fparam.type)
1138                         continue;
1139                 }
1140 
1141                 fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
1142 
1143                 Type t = fparam.type.toBasetype();
1144 
1145                 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
1146                  * change.
1147                  */
1148                 if (auto tt = t.isTypeTuple())
1149                 {
1150                     /* TypeFunction::parameter also is used as the storage of
1151                      * Parameter objects for FuncDeclaration. So we should copy
1152                      * the elements of TypeTuple::arguments to avoid unintended
1153                      * sharing of Parameter object among other functions.
1154                      */
1155                     if (tt.arguments && tt.arguments.length)
1156                     {
1157                         /* Propagate additional storage class from tuple parameters to their
1158                          * element-parameters.
1159                          * Make a copy, as original may be referenced elsewhere.
1160                          */
1161                         size_t tdim = tt.arguments.length;
1162                         auto newparams = new Parameters(tdim);
1163                         for (size_t j = 0; j < tdim; j++)
1164                         {
1165                             Parameter narg = (*tt.arguments)[j];
1166 
1167                             // https://issues.dlang.org/show_bug.cgi?id=12744
1168                             // If the storage classes of narg
1169                             // conflict with the ones in fparam, it's ignored.
1170                             StorageClass stc  = fparam.storageClass | narg.storageClass;
1171                             StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1172                             StorageClass stc2 =   narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
1173                             if (stc1 && stc2 && stc1 != stc2)
1174                             {
1175                                 OutBuffer buf1;  stcToBuffer(&buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
1176                                 OutBuffer buf2;  stcToBuffer(&buf2, stc2);
1177 
1178                                 .error(loc, "incompatible parameter storage classes `%s` and `%s`",
1179                                     buf1.peekChars(), buf2.peekChars());
1180                                 errors = true;
1181                                 stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_));
1182                             }
1183                             (*newparams)[j] = new Parameter(
1184                                 stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
1185                         }
1186                         fparam.type = new TypeTuple(newparams);
1187                         fparam.type = fparam.type.typeSemantic(loc, argsc);
1188                     }
1189                     fparam.storageClass = STC.parameter;
1190 
1191                     /* Reset number of parameters, and back up one to do this fparam again,
1192                      * now that it is a tuple
1193                      */
1194                     dim = tf.parameterList.length;
1195                     i--;
1196                     continue;
1197                 }
1198 
1199                 // -preview=in: Always add `ref` when used with `extern(C++)` functions
1200                 // Done here to allow passing opaque types with `in`
1201                 if ((fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
1202                 {
1203                     switch (tf.linkage)
1204                     {
1205                     case LINK.cpp:
1206                         if (global.params.previewIn)
1207                             fparam.storageClass |= STC.ref_;
1208                         break;
1209                     case LINK.default_, LINK.d:
1210                         break;
1211                     default:
1212                         if (global.params.previewIn)
1213                         {
1214                             .error(loc, "cannot use `in` parameters with `extern(%s)` functions",
1215                                    linkageToChars(tf.linkage));
1216                             .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
1217                         }
1218                         else
1219                         {
1220                             // Note that this deprecation will not trigger on `in ref` / `ref in`
1221                             // parameters, however the parser will trigger a deprecation on them.
1222                             .deprecation(loc, "using `in` parameters with `extern(%s)` functions is deprecated",
1223                                          linkageToChars(tf.linkage));
1224                             .deprecationSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
1225                         }
1226                         break;
1227                     }
1228                 }
1229 
1230                 if (t.ty == Tfunction)
1231                 {
1232                     .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());
1233                     errors = true;
1234                 }
1235                 else if (!fparam.isReference() &&
1236                          (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
1237                 {
1238                     Type tb2 = t.baseElemOf();
1239                     if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members ||
1240                         tb2.ty == Tenum   && !tb2.isTypeEnum().sym.memtype)
1241                     {
1242                         if (global.params.previewIn && (fparam.storageClass & STC.in_))
1243                         {
1244                             .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
1245                                    fparam.toChars(), fparam.type.toChars());
1246                         }
1247                         else
1248                             .error(loc, "cannot have parameter of opaque type `%s` by value",
1249                                    fparam.type.toChars());
1250                         errors = true;
1251                     }
1252                 }
1253                 else if (!fparam.isLazy() && t.ty == Tvoid)
1254                 {
1255                     .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
1256                     errors = true;
1257                 }
1258 
1259                 const bool isTypesafeVariadic = i + 1 == dim &&
1260                                                 tf.parameterList.varargs == VarArg.typesafe &&
1261                                                 (t.isTypeDArray() || t.isTypeClass());
1262                 if (isTypesafeVariadic)
1263                 {
1264                     /* typesafe variadic arguments are constructed on the stack, so must be `scope`
1265                      */
1266                     fparam.storageClass |= STC.scope_ | STC.scopeinferred;
1267                 }
1268 
1269                 if (fparam.storageClass & STC.return_)
1270                 {
1271                     if (!fparam.isReference())
1272                     {
1273                         if (!(fparam.storageClass & STC.scope_))
1274                             fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
1275                         if (tf.isref)
1276                         {
1277                         }
1278                         else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
1279                         {
1280                             fparam.storageClass &= ~STC.return_;   // https://issues.dlang.org/show_bug.cgi?id=18963
1281                         }
1282                     }
1283 
1284                     if (isTypesafeVariadic)
1285                     {
1286                         /* This is because they can be constructed on the stack
1287                          * https://dlang.org/spec/function.html#typesafe_variadic_functions
1288                          */
1289                         .error(loc, "typesafe variadic function parameter `%s` of type `%s` cannot be marked `return`",
1290                             fparam.ident ? fparam.ident.toChars() : "", t.toChars());
1291                         errors = true;
1292                     }
1293                 }
1294 
1295                 if (fparam.storageClass & STC.out_)
1296                 {
1297                     if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild))
1298                     {
1299                         .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars());
1300                         errors = true;
1301                     }
1302                     else
1303                     {
1304                         Type tv = t.baseElemOf();
1305                         if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor)
1306                         {
1307                             .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
1308                             errors = true;
1309                         }
1310                     }
1311                 }
1312 
1313                 if (t.hasWild())
1314                 {
1315                     wildparams |= 1;
1316                     //if (tf.next && !wildreturn)
1317                     //    error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
1318                 }
1319 
1320                 // Remove redundant storage classes for type, they are already applied
1321                 fparam.storageClass &= ~(STC.TYPECTOR);
1322 
1323                 // -preview=in: add `ref` storage class to suited `in` params
1324                 if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
1325                 {
1326                     auto ts = t.baseElemOf().isTypeStruct();
1327                     const isPOD = !ts || ts.sym.isPOD();
1328                     if (!isPOD || target.preferPassByRef(t))
1329                         fparam.storageClass |= STC.ref_;
1330                 }
1331             }
1332 
1333             // Now that we completed semantic for the argument types,
1334             // run semantic on their default values,
1335             // bearing in mind tuples have been expanded.
1336             // We need to keep a pair of [oidx, eidx] (original index,
1337             // extended index), as we need to run semantic when `oidx` changes.
1338             size_t tupleOrigIdx = size_t.max;
1339             size_t tupleExtIdx = size_t.max;
1340             foreach (oidx, oparam, eidx, eparam; tf.parameterList)
1341             {
1342                 // oparam (original param) will always have the default arg
1343                 // if there's one, but `eparam` will not if it's an expanded
1344                 // tuple. When we see an expanded tuple, we need to save its
1345                 // position to get the offset in it later on.
1346                 if (oparam.defaultArg)
1347                 {
1348                     // Get the obvious case out of the way
1349                     if (oparam is eparam)
1350                         errors |= !defaultArgSemantic(eparam, argsc);
1351                     // We're seeing a new tuple
1352                     else if (tupleOrigIdx == size_t.max || tupleOrigIdx < oidx)
1353                     {
1354                         /* https://issues.dlang.org/show_bug.cgi?id=18572
1355                          *
1356                          * If a tuple parameter has a default argument, when expanding the parameter
1357                          * tuple the default argument tuple must also be expanded.
1358                          */
1359                         tupleOrigIdx = oidx;
1360                         tupleExtIdx = eidx;
1361                         errors |= !defaultArgSemantic(oparam, argsc);
1362                         TupleExp te = oparam.defaultArg.isTupleExp();
1363                         if (te && te.exps && te.exps.length)
1364                             eparam.defaultArg = (*te.exps)[0];
1365                     }
1366                     // Processing an already-seen tuple
1367                     else
1368                     {
1369                         TupleExp te = oparam.defaultArg.isTupleExp();
1370                         if (te && te.exps && te.exps.length)
1371                             eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
1372                     }
1373                 }
1374 
1375                 // We need to know the default argument to resolve `auto ref`,
1376                 // hence why this has to take place as the very last step.
1377                 /* Resolve "auto ref" storage class to be either ref or value,
1378                  * based on the argument matching the parameter
1379                  */
1380                 if (eparam.storageClass & STC.auto_)
1381                 {
1382                     Expression farg = mtype.fargs && eidx < mtype.fargs.length ?
1383                         (*mtype.fargs)[eidx] : eparam.defaultArg;
1384                     if (farg && (eparam.storageClass & STC.ref_))
1385                     {
1386                         if (!farg.isLvalue())
1387                             eparam.storageClass &= ~STC.ref_; // value parameter
1388                         eparam.storageClass &= ~STC.auto_;    // https://issues.dlang.org/show_bug.cgi?id=14656
1389                         eparam.storageClass |= STC.autoref;
1390                     }
1391                     else if (mtype.incomplete && (eparam.storageClass & STC.ref_))
1392                     {
1393                         // the default argument may have been temporarily removed,
1394                         // see usage of `TypeFunction.incomplete`.
1395                         // https://issues.dlang.org/show_bug.cgi?id=19891
1396                         eparam.storageClass &= ~STC.auto_;
1397                         eparam.storageClass |= STC.autoref;
1398                     }
1399                     else if (eparam.storageClass & STC.ref_)
1400                     {
1401                         .error(loc, "cannot explicitly instantiate template function with `auto ref` parameter");
1402                         errors = true;
1403                     }
1404                     else
1405                     {
1406                         .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
1407                         errors = true;
1408                     }
1409                 }
1410             }
1411 
1412             argsc.pop();
1413         }
1414         if (tf.isWild())
1415             wildparams |= 2;
1416 
1417         if (wildreturn && !wildparams)
1418         {
1419             .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars());
1420             errors = true;
1421         }
1422         tf.isInOutParam = (wildparams & 1) != 0;
1423         tf.isInOutQual  = (wildparams & 2) != 0;
1424 
1425         if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
1426         {
1427             .error(loc, "properties can only have zero, one, or two parameter");
1428             errors = true;
1429         }
1430 
1431         if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
1432             !(sc.flags & SCOPE.Cfile))
1433         {
1434             .error(loc, "variadic functions with non-D linkage must have at least one parameter");
1435             errors = true;
1436         }
1437 
1438         if (errors)
1439             return error();
1440 
1441         if (tf.next)
1442             tf.deco = tf.merge().deco;
1443 
1444         /* Don't return merge(), because arg identifiers and default args
1445          * can be different
1446          * even though the types match
1447          */
1448         return tf;
1449     }
1450 
1451     Type visitDelegate(TypeDelegate mtype)
1452     {
1453         //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
1454         if (mtype.deco) // if semantic() already run
1455         {
1456             //printf("already done\n");
1457             return mtype;
1458         }
1459         mtype.next = mtype.next.typeSemantic(loc, sc);
1460         if (mtype.next.ty != Tfunction)
1461             return error();
1462 
1463         /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
1464          * perhaps default arguments should
1465          * be removed from next before the merge.
1466          */
1467         version (none)
1468         {
1469             return mtype.merge();
1470         }
1471         else
1472         {
1473             /* Don't return merge(), because arg identifiers and default args
1474              * can be different
1475              * even though the types match
1476              */
1477             mtype.deco = mtype.merge().deco;
1478             return mtype;
1479         }
1480     }
1481 
1482     Type visitIdentifier(TypeIdentifier mtype)
1483     {
1484         Type t;
1485         Expression e;
1486         Dsymbol s;
1487         //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
1488         mtype.resolve(loc, sc, e, t, s);
1489         if (t)
1490         {
1491             //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
1492             return t.addMod(mtype.mod);
1493         }
1494         else
1495         {
1496             if (s)
1497             {
1498                 auto td = s.isTemplateDeclaration;
1499                 if (td && td.onemember && td.onemember.isAggregateDeclaration)
1500                     .error(loc, "template %s `%s` is used as a type without instantiation"
1501                         ~ "; to instantiate it use `%s!(arguments)`",
1502                         s.kind, s.toPrettyChars, s.ident.toChars);
1503                 else
1504                     .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
1505                 //assert(0);
1506             }
1507             else if (e.op == EXP.variable) // special case: variable is used as a type
1508             {
1509                 /*
1510                     N.B. This branch currently triggers for the following code
1511                     template test(x* x)
1512                     {
1513 
1514                     }
1515                     i.e. the compiler prints "variable x is used as a type"
1516                     which isn't a particularly good error message (x is a variable?).
1517                 */
1518                 Dsymbol varDecl = mtype.toDsymbol(sc);
1519                 const(Loc) varDeclLoc = varDecl.getLoc();
1520                 Module varDeclModule = varDecl.getModule(); //This can be null
1521 
1522                 .error(loc, "variable `%s` is used as a type", mtype.toChars());
1523                 //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
1524                 if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
1525                 {
1526                     const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
1527                     .errorSupplemental(
1528                         varDeclModuleImportLoc,
1529                         "variable `%s` is imported here from: `%s`",
1530                         varDecl.toChars,
1531                         varDeclModule.toPrettyChars,
1532                     );
1533                 }
1534 
1535                 .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
1536             }
1537             else
1538                 .error(loc, "`%s` is used as a type", mtype.toChars());
1539             return error();
1540         }
1541     }
1542 
1543     Type visitInstance(TypeInstance mtype)
1544     {
1545         Type t;
1546         Expression e;
1547         Dsymbol s;
1548 
1549         //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
1550         {
1551             const errors = global.errors;
1552             mtype.resolve(loc, sc, e, t, s);
1553             // if we had an error evaluating the symbol, suppress further errors
1554             if (!t && errors != global.errors)
1555                 return error();
1556         }
1557 
1558         if (!t)
1559         {
1560             if (!e && s && s.errors)
1561             {
1562                 // if there was an error evaluating the symbol, it might actually
1563                 // be a type. Avoid misleading error messages.
1564                 .error(loc, "`%s` had previous errors", mtype.toChars());
1565             }
1566             else
1567                 .error(loc, "`%s` is used as a type", mtype.toChars());
1568             return error();
1569         }
1570         return t;
1571     }
1572 
1573     Type visitTypeof(TypeTypeof mtype)
1574     {
1575         //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
1576         Expression e;
1577         Type t;
1578         Dsymbol s;
1579         mtype.resolve(loc, sc, e, t, s);
1580         if (s && (t = s.getType()) !is null)
1581             t = t.addMod(mtype.mod);
1582         if (!t)
1583         {
1584             .error(loc, "`%s` is used as a type", mtype.toChars());
1585             return error();
1586         }
1587         return t;
1588     }
1589 
1590     Type visitTraits(TypeTraits mtype)
1591     {
1592         Expression e;
1593         Type t;
1594         Dsymbol s;
1595         mtype.resolve(loc, sc, e, t, s);
1596 
1597         if (!t)
1598         {
1599             if (!global.errors)
1600                 .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars);
1601             return error();
1602         }
1603         return t;
1604     }
1605 
1606     Type visitReturn(TypeReturn mtype)
1607     {
1608         //printf("TypeReturn::semantic() %s\n", toChars());
1609         Expression e;
1610         Type t;
1611         Dsymbol s;
1612         mtype.resolve(loc, sc, e, t, s);
1613         if (s && (t = s.getType()) !is null)
1614             t = t.addMod(mtype.mod);
1615         if (!t)
1616         {
1617             .error(loc, "`%s` is used as a type", mtype.toChars());
1618             return error();
1619         }
1620         return t;
1621     }
1622 
1623     Type visitStruct(TypeStruct mtype)
1624     {
1625         //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
1626         if (mtype.deco)
1627             return mtype;
1628 
1629         /* Don't semantic for sym because it should be deferred until
1630          * sizeof needed or its members accessed.
1631          */
1632         // instead, parent should be set correctly
1633         assert(mtype.sym.parent);
1634 
1635         if (mtype.sym.type.ty == Terror)
1636             return error();
1637 
1638         return merge(mtype);
1639     }
1640 
1641     Type visitEnum(TypeEnum mtype)
1642     {
1643         //printf("TypeEnum::semantic() %s\n", toChars());
1644         return mtype.deco ? mtype : merge(mtype);
1645     }
1646 
1647     Type visitClass(TypeClass mtype)
1648     {
1649         //printf("TypeClass::semantic(%s)\n", mtype.toChars());
1650         if (mtype.deco)
1651             return mtype;
1652 
1653         /* Don't semantic for sym because it should be deferred until
1654          * sizeof needed or its members accessed.
1655          */
1656         // instead, parent should be set correctly
1657         assert(mtype.sym.parent);
1658 
1659         if (mtype.sym.type.ty == Terror)
1660             return error();
1661 
1662         return merge(mtype);
1663     }
1664 
1665     Type visitTuple(TypeTuple mtype)
1666     {
1667         //printf("TypeTuple::semantic(this = %p)\n", this);
1668         //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
1669         if (!mtype.deco)
1670             mtype.deco = merge(mtype).deco;
1671 
1672         /* Don't return merge(), because a tuple with one type has the
1673          * same deco as that type.
1674          */
1675         return mtype;
1676     }
1677 
1678     Type visitSlice(TypeSlice mtype)
1679     {
1680         //printf("TypeSlice::semantic() %s\n", toChars());
1681         Type tn = mtype.next.typeSemantic(loc, sc);
1682         //printf("next: %s\n", tn.toChars());
1683 
1684         Type tbn = tn.toBasetype();
1685         if (tbn.ty != Ttuple)
1686         {
1687             .error(loc, "can only slice tuple types, not `%s`", tbn.toChars());
1688             return error();
1689         }
1690         TypeTuple tt = cast(TypeTuple)tbn;
1691 
1692         mtype.lwr = semanticLength(sc, tbn, mtype.lwr);
1693         mtype.upr = semanticLength(sc, tbn, mtype.upr);
1694         mtype.lwr = mtype.lwr.ctfeInterpret();
1695         mtype.upr = mtype.upr.ctfeInterpret();
1696         if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
1697             return error();
1698 
1699         uinteger_t i1 = mtype.lwr.toUInteger();
1700         uinteger_t i2 = mtype.upr.toUInteger();
1701         if (!(i1 <= i2 && i2 <= tt.arguments.length))
1702         {
1703             .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
1704                 cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.length);
1705             return error();
1706         }
1707 
1708         mtype.next = tn;
1709         mtype.transitive();
1710 
1711         auto args = new Parameters();
1712         args.reserve(cast(size_t)(i2 - i1));
1713         foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2])
1714         {
1715             args.push(arg);
1716         }
1717         Type t = new TypeTuple(args);
1718         return t.typeSemantic(loc, sc);
1719     }
1720 
1721     Type visitMixin(TypeMixin mtype)
1722     {
1723         //printf("TypeMixin::semantic() %s\n", toChars());
1724 
1725         Expression e;
1726         Type t;
1727         Dsymbol s;
1728         mtype.resolve(loc, sc, e, t, s);
1729 
1730         if (t && t.ty != Terror)
1731             return t;
1732 
1733         .error(mtype.loc, "`mixin(%s)` does not give a valid type", mtype.obj.toChars);
1734         return error();
1735     }
1736 
1737     Type visitTag(TypeTag mtype)
1738     {
1739         //printf("TypeTag.semantic() %s\n", mtype.toChars());
1740         if (mtype.resolved)
1741         {
1742             /* struct S s, *p;
1743              */
1744             return mtype.resolved.addSTC(mtype.mod);
1745         }
1746 
1747         /* Find the current scope by skipping tag scopes.
1748          * In C, tag scopes aren't considered scopes.
1749          */
1750         Scope* sc2 = sc;
1751         while (1)
1752         {
1753             sc2 = sc2.inner();
1754             auto scopesym = sc2.scopesym;
1755             if (scopesym.isStructDeclaration())
1756             {
1757                 sc2 = sc2.enclosing;
1758                 continue;
1759             }
1760             break;
1761         }
1762 
1763         /* Declare mtype as a struct/union/enum declaration
1764          */
1765         void declareTag()
1766         {
1767             void declare(ScopeDsymbol sd)
1768             {
1769                 sd.members = mtype.members;
1770                 auto scopesym = sc2.inner().scopesym;
1771                 if (scopesym.members)
1772                     scopesym.members.push(sd);
1773                 if (scopesym.symtab && !scopesym.symtabInsert(sd))
1774                 {
1775                     Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
1776                     handleTagSymbols(*sc2, sd, s2, scopesym);
1777                 }
1778                 sd.parent = sc2.parent;
1779                 sd.dsymbolSemantic(sc2);
1780             }
1781 
1782             switch (mtype.tok)
1783             {
1784                 case TOK.enum_:
1785                     auto ed = new EnumDeclaration(mtype.loc, mtype.id, mtype.base);
1786                     declare(ed);
1787                     mtype.resolved = visitEnum(new TypeEnum(ed));
1788                     break;
1789 
1790                 case TOK.struct_:
1791                     auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
1792                     sd.alignment = mtype.packalign;
1793                     declare(sd);
1794                     mtype.resolved = visitStruct(new TypeStruct(sd));
1795                     break;
1796 
1797                 case TOK.union_:
1798                     auto ud = new UnionDeclaration(mtype.loc, mtype.id);
1799                     ud.alignment = mtype.packalign;
1800                     declare(ud);
1801                     mtype.resolved = visitStruct(new TypeStruct(ud));
1802                     break;
1803 
1804                 default:
1805                     assert(0);
1806             }
1807         }
1808 
1809         /* If it doesn't have a tag by now, supply one.
1810          * It'll be unique, and therefore introducing.
1811          * Declare it, and done.
1812          */
1813         if (!mtype.id)
1814         {
1815             mtype.id = Identifier.generateId("__tag"[]);
1816             declareTag();
1817             return mtype.resolved.addSTC(mtype.mod);
1818         }
1819 
1820         /* look for pre-existing declaration
1821          */
1822         Dsymbol scopesym;
1823         auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
1824         if (!s || s.isModule())
1825         {
1826             // no pre-existing declaration, so declare it
1827             if (mtype.tok == TOK.enum_ && !mtype.members)
1828                 .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
1829             declareTag();
1830             return mtype.resolved.addSTC(mtype.mod);
1831         }
1832 
1833         /* A redeclaration only happens if both declarations are in
1834          * the same scope
1835          */
1836         const bool redeclar = (scopesym == sc2.inner().scopesym);
1837 
1838         if (redeclar)
1839         {
1840             if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
1841             {
1842                 auto ed = s.isEnumDeclaration();
1843                 if (mtype.members && ed.members)
1844                     .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
1845                 else if (!ed.members)
1846                 {
1847                     ed.members = mtype.members;
1848                 }
1849                 else
1850                 {
1851                 }
1852                 mtype.resolved = ed.type;
1853             }
1854             else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
1855                      mtype.tok == TOK.struct_ && s.isStructDeclaration())
1856             {
1857                 // Add members to original declaration
1858                 auto sd = s.isStructDeclaration();
1859                 if (mtype.members && sd.members)
1860                 {
1861                     /* struct S { int b; };
1862                      * struct S { int a; } *s;
1863                      */
1864                     .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
1865                 }
1866                 else if (!sd.members)
1867                 {
1868                     /* struct S;
1869                      * struct S { int a; } *s;
1870                      */
1871                     sd.members = mtype.members;
1872                     if (sd.semanticRun == PASS.semanticdone)
1873                     {
1874                         /* The first semantic pass marked `sd` as an opaque struct.
1875                          * Re-run semantic so that all newly assigned members are
1876                          * picked up and added to the symtab.
1877                          */
1878                         sd.semanticRun = PASS.semantic;
1879                         sd.dsymbolSemantic(sc2);
1880                     }
1881                 }
1882                 else
1883                 {
1884                     /* struct S { int a; };
1885                      * struct S *s;
1886                      */
1887                 }
1888                 mtype.resolved = sd.type;
1889             }
1890             else
1891             {
1892                 /* int S;
1893                  * struct S { int a; } *s;
1894                  */
1895                 .error(mtype.loc, "redeclaration of `%s`", mtype.id.toChars());
1896                 mtype.resolved = error();
1897             }
1898         }
1899         else if (mtype.members)
1900         {
1901             /* struct S;
1902              * { struct S { int a; } *s; }
1903              */
1904             declareTag();
1905         }
1906         else
1907         {
1908             if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
1909             {
1910                 mtype.resolved = s.isEnumDeclaration().type;
1911             }
1912             else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
1913                      mtype.tok == TOK.struct_ && s.isStructDeclaration())
1914             {
1915                 /* struct S;
1916                  * { struct S *s; }
1917                  */
1918                 mtype.resolved = s.isStructDeclaration().type;
1919             }
1920             else
1921             {
1922                 /* union S;
1923                  * { struct S *s; }
1924                  */
1925                 .error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
1926                     s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
1927                 declareTag();
1928             }
1929         }
1930         return mtype.resolved.addSTC(mtype.mod);
1931     }
1932 
1933     switch (type.ty)
1934     {
1935         default:         return visitType(type);
1936         case Tcomplex32:
1937         case Tcomplex64:
1938         case Tcomplex80: return visitComplex(type.isTypeBasic());
1939         case Tvector:    return visitVector(type.isTypeVector());
1940         case Tsarray:    return visitSArray(type.isTypeSArray());
1941         case Tarray:     return visitDArray(type.isTypeDArray());
1942         case Taarray:    return visitAArray(type.isTypeAArray());
1943         case Tpointer:   return visitPointer(type.isTypePointer());
1944         case Treference: return visitReference(type.isTypeReference());
1945         case Tfunction:  return visitFunction(type.isTypeFunction());
1946         case Tdelegate:  return visitDelegate(type.isTypeDelegate());
1947         case Tident:     return visitIdentifier(type.isTypeIdentifier());
1948         case Tinstance:  return visitInstance(type.isTypeInstance());
1949         case Ttypeof:    return visitTypeof(type.isTypeTypeof());
1950         case Ttraits:    return visitTraits(type.isTypeTraits());
1951         case Treturn:    return visitReturn(type.isTypeReturn());
1952         case Tstruct:    return visitStruct(type.isTypeStruct());
1953         case Tenum:      return visitEnum(type.isTypeEnum());
1954         case Tclass:     return visitClass(type.isTypeClass());
1955         case Ttuple:     return visitTuple(type.isTypeTuple());
1956         case Tslice:     return visitSlice(type.isTypeSlice());
1957         case Tmixin:     return visitMixin(type.isTypeMixin());
1958         case Ttag:       return visitTag(type.isTypeTag());
1959     }
1960 }
1961 
1962 /************************************
1963  * If an identical type to `type` is in `type.stringtable`, return
1964  * the latter one. Otherwise, add it to `type.stringtable`.
1965  * Some types don't get merged and are returned as-is.
1966  * Params:
1967  *      type = Type to check against existing types
1968  * Returns:
1969  *      the type that was merged
1970  */
1971 extern (C++) Type merge(Type type)
1972 {
1973     switch (type.ty)
1974     {
1975         case Terror:
1976         case Ttypeof:
1977         case Tident:
1978         case Tinstance:
1979         case Tmixin:
1980         case Ttag:
1981             return type;        // don't merge placeholder types
1982 
1983         case Tsarray:
1984             // prevents generating the mangle if the array dim is not yet known
1985             if (!type.isTypeSArray().dim.isIntegerExp())
1986                 return type;
1987             goto default;
1988 
1989         case Tenum:
1990             break;
1991 
1992         case Taarray:
1993             if (!type.isTypeAArray().index.merge().deco)
1994                 return type;
1995             goto default;
1996 
1997         default:
1998             if (type.nextOf() && !type.nextOf().deco)
1999                 return type;
2000             break;
2001     }
2002 
2003     //printf("merge(%s)\n", toChars());
2004     if (!type.deco)
2005     {
2006         OutBuffer buf;
2007         buf.reserve(32);
2008 
2009         mangleToBuffer(type, &buf);
2010 
2011         auto sv = type.stringtable.update(buf[]);
2012         if (sv.value)
2013         {
2014             Type t = sv.value;
2015             debug
2016             {
2017                 import core.stdc.stdio;
2018                 if (!t.deco)
2019                     printf("t = %s\n", t.toChars());
2020             }
2021             assert(t.deco);
2022             //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
2023             return t;
2024         }
2025         else
2026         {
2027             Type t = stripDefaultArgs(type);
2028             sv.value = t;
2029             type.deco = t.deco = cast(char*)sv.toDchars();
2030             //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
2031             return t;
2032         }
2033     }
2034     return type;
2035 }
2036 
2037 /***************************************
2038  * Calculate built-in properties which just the type is necessary.
2039  *
2040  * Params:
2041  *  t = the type for which the property is calculated
2042  *  scope_ = the scope from which the property is being accessed. Used for visibility checks only.
2043  *  loc = the location where the property is encountered
2044  *  ident = the identifier of the property
2045  *  flag = if flag & 1, don't report "not a property" error and just return NULL.
2046  *  src = expression for type `t` or null.
2047  * Returns:
2048  *      expression representing the property, or null if not a property and (flag & 1)
2049  */
2050 Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag,
2051     Expression src = null)
2052 {
2053     Expression visitType(Type mt)
2054     {
2055         Expression e;
2056         static if (LOGDOTEXP)
2057         {
2058             printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2059         }
2060         if (ident == Id.__sizeof)
2061         {
2062             const sz = mt.size(loc);
2063             if (sz == SIZE_INVALID)
2064                 return ErrorExp.get();
2065             e = new IntegerExp(loc, sz, Type.tsize_t);
2066         }
2067         else if (ident == Id.__xalignof)
2068         {
2069             const explicitAlignment = mt.alignment();
2070             const naturalAlignment = mt.alignsize();
2071             const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
2072             e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
2073         }
2074         else if (ident == Id._init)
2075         {
2076             Type tb = mt.toBasetype();
2077             e = mt.defaultInitLiteral(loc);
2078             if (tb.ty == Tstruct && tb.needsNested())
2079             {
2080                 e.isStructLiteralExp().useStaticInit = true;
2081             }
2082         }
2083         else if (ident == Id._mangleof)
2084         {
2085             if (!mt.deco)
2086             {
2087                 error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
2088                 e = ErrorExp.get();
2089             }
2090             else
2091             {
2092                 e = new StringExp(loc, mt.deco.toDString());
2093                 Scope sc;
2094                 e = e.expressionSemantic(&sc);
2095             }
2096         }
2097         else if (ident == Id.stringof)
2098         {
2099             const s = mt.toChars();
2100             e = new StringExp(loc, s.toDString());
2101             Scope sc;
2102             e = e.expressionSemantic(&sc);
2103         }
2104         else if (flag && mt != Type.terror)
2105         {
2106             return null;
2107         }
2108         else
2109         {
2110             Dsymbol s = null;
2111             if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
2112                 s = mt.toDsymbol(null);
2113             if (s)
2114                 s = s.search_correct(ident);
2115             if (s && !symbolIsVisible(scope_, s))
2116                 s = null;
2117             if (mt != Type.terror)
2118             {
2119                 if (s)
2120                     error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
2121                 else if (ident == Id.call && mt.ty == Tclass)
2122                     error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
2123 
2124                 else if (const n = importHint(ident.toString()))
2125                         error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
2126                 else
2127                 {
2128                     if (src)
2129                         error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true));
2130                     else
2131                         error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
2132                     if (auto dsym = mt.toDsymbol(scope_))
2133                         if (auto sym = dsym.isAggregateDeclaration())
2134                         {
2135                             if (auto fd = search_function(sym, Id.opDispatch))
2136                                 errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
2137                             else if (!sym.members)
2138                                 errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
2139                         }
2140                 }
2141             }
2142             e = ErrorExp.get();
2143         }
2144         return e;
2145     }
2146 
2147     Expression visitError(TypeError)
2148     {
2149         return ErrorExp.get();
2150     }
2151 
2152     Expression visitBasic(TypeBasic mt)
2153     {
2154         Expression integerValue(dinteger_t i)
2155         {
2156             return new IntegerExp(loc, i, mt);
2157         }
2158 
2159         Expression intValue(dinteger_t i)
2160         {
2161             return new IntegerExp(loc, i, Type.tint32);
2162         }
2163 
2164         Expression floatValue(real_t r)
2165         {
2166             if (mt.isreal() || mt.isimaginary())
2167                 return new RealExp(loc, r, mt);
2168             else
2169             {
2170                 return new ComplexExp(loc, complex_t(r, r), mt);
2171             }
2172         }
2173 
2174         //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
2175         if (ident == Id.max)
2176         {
2177             switch (mt.ty)
2178             {
2179             case Tint8:        return integerValue(byte.max);
2180             case Tuns8:        return integerValue(ubyte.max);
2181             case Tint16:       return integerValue(short.max);
2182             case Tuns16:       return integerValue(ushort.max);
2183             case Tint32:       return integerValue(int.max);
2184             case Tuns32:       return integerValue(uint.max);
2185             case Tint64:       return integerValue(long.max);
2186             case Tuns64:       return integerValue(ulong.max);
2187             case Tbool:        return integerValue(bool.max);
2188             case Tchar:        return integerValue(char.max);
2189             case Twchar:       return integerValue(wchar.max);
2190             case Tdchar:       return integerValue(dchar.max);
2191             case Tcomplex32:
2192             case Timaginary32:
2193             case Tfloat32:     return floatValue(target.FloatProperties.max);
2194             case Tcomplex64:
2195             case Timaginary64:
2196             case Tfloat64:     return floatValue(target.DoubleProperties.max);
2197             case Tcomplex80:
2198             case Timaginary80:
2199             case Tfloat80:     return floatValue(target.RealProperties.max);
2200             default:           break;
2201             }
2202         }
2203         else if (ident == Id.min)
2204         {
2205             switch (mt.ty)
2206             {
2207             case Tint8:        return integerValue(byte.min);
2208             case Tuns8:
2209             case Tuns16:
2210             case Tuns32:
2211             case Tuns64:
2212             case Tbool:
2213             case Tchar:
2214             case Twchar:
2215             case Tdchar:       return integerValue(0);
2216             case Tint16:       return integerValue(short.min);
2217             case Tint32:       return integerValue(int.min);
2218             case Tint64:       return integerValue(long.min);
2219             default:           break;
2220             }
2221         }
2222         else if (ident == Id.min_normal)
2223         {
2224             switch (mt.ty)
2225             {
2226             case Tcomplex32:
2227             case Timaginary32:
2228             case Tfloat32:     return floatValue(target.FloatProperties.min_normal);
2229             case Tcomplex64:
2230             case Timaginary64:
2231             case Tfloat64:     return floatValue(target.DoubleProperties.min_normal);
2232             case Tcomplex80:
2233             case Timaginary80:
2234             case Tfloat80:     return floatValue(target.RealProperties.min_normal);
2235             default:           break;
2236             }
2237         }
2238         else if (ident == Id.nan)
2239         {
2240             switch (mt.ty)
2241             {
2242             case Tcomplex32:
2243             case Tcomplex64:
2244             case Tcomplex80:
2245             case Timaginary32:
2246             case Timaginary64:
2247             case Timaginary80:
2248             case Tfloat32:
2249             case Tfloat64:
2250             case Tfloat80:     return floatValue(target.RealProperties.nan);
2251             default:           break;
2252             }
2253         }
2254         else if (ident == Id.infinity)
2255         {
2256             switch (mt.ty)
2257             {
2258             case Tcomplex32:
2259             case Tcomplex64:
2260             case Tcomplex80:
2261             case Timaginary32:
2262             case Timaginary64:
2263             case Timaginary80:
2264             case Tfloat32:
2265             case Tfloat64:
2266             case Tfloat80:     return floatValue(target.RealProperties.infinity);
2267             default:           break;
2268             }
2269         }
2270         else if (ident == Id.dig)
2271         {
2272             switch (mt.ty)
2273             {
2274             case Tcomplex32:
2275             case Timaginary32:
2276             case Tfloat32:     return intValue(target.FloatProperties.dig);
2277             case Tcomplex64:
2278             case Timaginary64:
2279             case Tfloat64:     return intValue(target.DoubleProperties.dig);
2280             case Tcomplex80:
2281             case Timaginary80:
2282             case Tfloat80:     return intValue(target.RealProperties.dig);
2283             default:           break;
2284             }
2285         }
2286         else if (ident == Id.epsilon)
2287         {
2288             switch (mt.ty)
2289             {
2290             case Tcomplex32:
2291             case Timaginary32:
2292             case Tfloat32:     return floatValue(target.FloatProperties.epsilon);
2293             case Tcomplex64:
2294             case Timaginary64:
2295             case Tfloat64:     return floatValue(target.DoubleProperties.epsilon);
2296             case Tcomplex80:
2297             case Timaginary80:
2298             case Tfloat80:     return floatValue(target.RealProperties.epsilon);
2299             default:           break;
2300             }
2301         }
2302         else if (ident == Id.mant_dig)
2303         {
2304             switch (mt.ty)
2305             {
2306             case Tcomplex32:
2307             case Timaginary32:
2308             case Tfloat32:     return intValue(target.FloatProperties.mant_dig);
2309             case Tcomplex64:
2310             case Timaginary64:
2311             case Tfloat64:     return intValue(target.DoubleProperties.mant_dig);
2312             case Tcomplex80:
2313             case Timaginary80:
2314             case Tfloat80:     return intValue(target.RealProperties.mant_dig);
2315             default:           break;
2316             }
2317         }
2318         else if (ident == Id.max_10_exp)
2319         {
2320             switch (mt.ty)
2321             {
2322             case Tcomplex32:
2323             case Timaginary32:
2324             case Tfloat32:     return intValue(target.FloatProperties.max_10_exp);
2325             case Tcomplex64:
2326             case Timaginary64:
2327             case Tfloat64:     return intValue(target.DoubleProperties.max_10_exp);
2328             case Tcomplex80:
2329             case Timaginary80:
2330             case Tfloat80:     return intValue(target.RealProperties.max_10_exp);
2331             default:           break;
2332             }
2333         }
2334         else if (ident == Id.max_exp)
2335         {
2336             switch (mt.ty)
2337             {
2338             case Tcomplex32:
2339             case Timaginary32:
2340             case Tfloat32:     return intValue(target.FloatProperties.max_exp);
2341             case Tcomplex64:
2342             case Timaginary64:
2343             case Tfloat64:     return intValue(target.DoubleProperties.max_exp);
2344             case Tcomplex80:
2345             case Timaginary80:
2346             case Tfloat80:     return intValue(target.RealProperties.max_exp);
2347             default:           break;
2348             }
2349         }
2350         else if (ident == Id.min_10_exp)
2351         {
2352             switch (mt.ty)
2353             {
2354             case Tcomplex32:
2355             case Timaginary32:
2356             case Tfloat32:     return intValue(target.FloatProperties.min_10_exp);
2357             case Tcomplex64:
2358             case Timaginary64:
2359             case Tfloat64:     return intValue(target.DoubleProperties.min_10_exp);
2360             case Tcomplex80:
2361             case Timaginary80:
2362             case Tfloat80:     return intValue(target.RealProperties.min_10_exp);
2363             default:           break;
2364             }
2365         }
2366         else if (ident == Id.min_exp)
2367         {
2368             switch (mt.ty)
2369             {
2370             case Tcomplex32:
2371             case Timaginary32:
2372             case Tfloat32:     return intValue(target.FloatProperties.min_exp);
2373             case Tcomplex64:
2374             case Timaginary64:
2375             case Tfloat64:     return intValue(target.DoubleProperties.min_exp);
2376             case Tcomplex80:
2377             case Timaginary80:
2378             case Tfloat80:     return intValue(target.RealProperties.min_exp);
2379             default:           break;
2380             }
2381         }
2382         return visitType(mt);
2383     }
2384 
2385     Expression visitVector(TypeVector mt)
2386     {
2387         return visitType(mt);
2388     }
2389 
2390     Expression visitEnum(TypeEnum mt)
2391     {
2392         Expression e;
2393         if (ident == Id.max || ident == Id.min)
2394         {
2395             return mt.sym.getMaxMinValue(loc, ident);
2396         }
2397         else if (ident == Id._init)
2398         {
2399             e = mt.defaultInitLiteral(loc);
2400         }
2401         else if (ident == Id.stringof)
2402         {
2403             e = new StringExp(loc, mt.toString());
2404             Scope sc;
2405             e = e.expressionSemantic(&sc);
2406         }
2407         else if (ident == Id._mangleof)
2408         {
2409             e = visitType(mt);
2410         }
2411         else
2412         {
2413             e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
2414         }
2415         return e;
2416     }
2417 
2418     Expression visitTuple(TypeTuple mt)
2419     {
2420         Expression e;
2421         static if (LOGDOTEXP)
2422         {
2423             printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
2424         }
2425         if (ident == Id.length)
2426         {
2427             e = new IntegerExp(loc, mt.arguments.length, Type.tsize_t);
2428         }
2429         else if (ident == Id._init)
2430         {
2431             e = mt.defaultInitLiteral(loc);
2432         }
2433         else if (flag)
2434         {
2435             e = null;
2436         }
2437         else
2438         {
2439             error(loc, "no property `%s` for tuple `%s`", ident.toChars(), mt.toChars());
2440             e = ErrorExp.get();
2441         }
2442         return e;
2443     }
2444 
2445     switch (t.ty)
2446     {
2447         default:        return t.isTypeBasic() ?
2448                                 visitBasic(cast(TypeBasic)t) :
2449                                 visitType(t);
2450 
2451         case Terror:    return visitError (t.isTypeError());
2452         case Tvector:   return visitVector(t.isTypeVector());
2453         case Tenum:     return visitEnum  (t.isTypeEnum());
2454         case Ttuple:    return visitTuple (t.isTypeTuple());
2455     }
2456 }
2457 
2458 /***************************************
2459  * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
2460  * Params:
2461  *      exp = Expression to look at
2462  *      t = if exp should be a Type, set t to that Type else null
2463  *      s = if exp should be a Dsymbol, set s to that Dsymbol else null
2464  *      e = if exp should remain an Expression, set e to that Expression else null
2465  *
2466  */
2467 private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbol s)
2468 {
2469     if (exp.isTypeExp())
2470         t = exp.type;
2471     else if (auto ve = exp.isVarExp())
2472     {
2473         if (auto v = ve.var.isVarDeclaration())
2474             e = exp;
2475         else
2476             s = ve.var;
2477     }
2478     else if (auto te = exp.isTemplateExp())
2479         s = te.td;
2480     else if (auto se = exp.isScopeExp())
2481         s = se.sds;
2482     else if (exp.isFuncExp())
2483         s = getDsymbol(exp);
2484     else if (auto dte = exp.isDotTemplateExp())
2485         s = dte.td;
2486     else if (exp.isErrorExp())
2487         t = Type.terror;
2488     else
2489         e = exp;
2490 }
2491 
2492 /************************************
2493  * Resolve type 'mt' to either type, symbol, or expression.
2494  * If errors happened, resolved to Type.terror.
2495  *
2496  * Params:
2497  *  mt = type to be resolved
2498  *  loc = the location where the type is encountered
2499  *  sc = the scope of the type
2500  *  pe = is set if t is an expression
2501  *  pt = is set if t is a type
2502  *  ps = is set if t is a symbol
2503  *  intypeid = true if in type id
2504  */
2505 void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
2506 {
2507     void returnExp(Expression e)
2508     {
2509         pe = e;
2510         pt = null;
2511         ps = null;
2512     }
2513 
2514     void returnType(Type t)
2515     {
2516         pe = null;
2517         pt = t;
2518         ps = null;
2519     }
2520 
2521     void returnSymbol(Dsymbol s)
2522     {
2523         pe = null;
2524         pt = null;
2525         ps = s;
2526     }
2527 
2528     void returnError()
2529     {
2530         returnType(Type.terror);
2531     }
2532 
2533     void visitType(Type mt)
2534     {
2535         //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
2536         Type t = typeSemantic(mt, loc, sc);
2537         assert(t);
2538         returnType(t);
2539     }
2540 
2541     void visitSArray(TypeSArray mt)
2542     {
2543         //printf("TypeSArray::resolve() %s\n", mt.toChars());
2544         mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2545         //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2546         if (pe)
2547         {
2548             // It's really an index expression
2549             if (Dsymbol s = getDsymbol(pe))
2550                 pe = new DsymbolExp(loc, s);
2551             returnExp(new ArrayExp(loc, pe, mt.dim));
2552         }
2553         else if (ps)
2554         {
2555             Dsymbol s = ps;
2556             if (auto tup = s.isTupleDeclaration())
2557             {
2558                 mt.dim = semanticLength(sc, tup, mt.dim);
2559                 mt.dim = mt.dim.ctfeInterpret();
2560                 if (mt.dim.op == EXP.error)
2561                     return returnError();
2562 
2563                 const d = mt.dim.toUInteger();
2564                 if (d >= tup.objects.length)
2565                 {
2566                     error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong) tup.objects.length);
2567                     return returnError();
2568                 }
2569 
2570                 RootObject o = (*tup.objects)[cast(size_t)d];
2571                 switch (o.dyncast()) with (DYNCAST)
2572                 {
2573                 case dsymbol:
2574                     return returnSymbol(cast(Dsymbol)o);
2575                 case expression:
2576                     Expression e = cast(Expression)o;
2577                     if (e.op == EXP.dSymbol)
2578                         return returnSymbol(e.isDsymbolExp().s);
2579                     else
2580                         return returnExp(e);
2581                 case type:
2582                     return returnType((cast(Type)o).addMod(mt.mod));
2583                 default:
2584                     break;
2585                 }
2586 
2587                 /* Create a new TupleDeclaration which
2588                  * is a slice [d..d+1] out of the old one.
2589                  * Do it this way because TemplateInstance::semanticTiargs()
2590                  * can handle unresolved Objects this way.
2591                  */
2592                 auto objects = new Objects(1);
2593                 (*objects)[0] = o;
2594                 return returnSymbol(new TupleDeclaration(loc, tup.ident, objects));
2595             }
2596             else
2597                 return visitType(mt);
2598         }
2599         else
2600         {
2601             if (pt.ty != Terror)
2602                 mt.next = pt; // prevent re-running semantic() on 'next'
2603             visitType(mt);
2604         }
2605 
2606     }
2607 
2608     void visitDArray(TypeDArray mt)
2609     {
2610         //printf("TypeDArray::resolve() %s\n", mt.toChars());
2611         mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2612         //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
2613         if (pe)
2614         {
2615             // It's really a slice expression
2616             if (Dsymbol s = getDsymbol(pe))
2617                 pe = new DsymbolExp(loc, s);
2618             returnExp(new ArrayExp(loc, pe));
2619         }
2620         else if (ps)
2621         {
2622             if (auto tup = ps.isTupleDeclaration())
2623             {
2624                 // keep ps
2625             }
2626             else
2627                 visitType(mt);
2628         }
2629         else
2630         {
2631             if (pt.ty != Terror)
2632                 mt.next = pt; // prevent re-running semantic() on 'next'
2633             visitType(mt);
2634         }
2635     }
2636 
2637     void visitAArray(TypeAArray mt)
2638     {
2639         //printf("TypeAArray::resolve() %s\n", mt.toChars());
2640         // Deal with the case where we thought the index was a type, but
2641         // in reality it was an expression.
2642         if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray)
2643         {
2644             Expression e;
2645             Type t;
2646             Dsymbol s;
2647             mt.index.resolve(loc, sc, e, t, s, intypeid);
2648             if (e)
2649             {
2650                 // It was an expression -
2651                 // Rewrite as a static array
2652                 auto tsa = new TypeSArray(mt.next, e);
2653                 tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done
2654                 return tsa.resolve(loc, sc, pe, pt, ps, intypeid);
2655             }
2656             else if (t)
2657                 mt.index = t;
2658             else
2659                 .error(loc, "index is not a type or an expression");
2660         }
2661         visitType(mt);
2662     }
2663 
2664     /*************************************
2665      * Takes an array of Identifiers and figures out if
2666      * it represents a Type or an Expression.
2667      * Output:
2668      *      if expression, pe is set
2669      *      if type, pt is set
2670      */
2671     void visitIdentifier(TypeIdentifier mt)
2672     {
2673         //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2674         if (mt.ident == Id.ctfe)
2675         {
2676             error(loc, "variable `__ctfe` cannot be read at compile time");
2677             return returnError();
2678         }
2679         if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
2680         {
2681             /* Since we don't support __builtin_va_start, -arg, -end, we don't
2682              * have to actually care what -list is. A void* will do.
2683              * If we ever do care, import core.stdc.stdarg and pull
2684              * the definition out of that, similarly to how std.math is handled for PowExp
2685              */
2686             pt = target.va_listType(loc, sc);
2687             return;
2688         }
2689 
2690         Dsymbol scopesym;
2691         Dsymbol s = sc.search(loc, mt.ident, &scopesym);
2692         /*
2693          * https://issues.dlang.org/show_bug.cgi?id=1170
2694          * https://issues.dlang.org/show_bug.cgi?id=10739
2695          *
2696          * If a symbol is not found, it might be declared in
2697          * a mixin-ed string or a mixin-ed template, so before
2698          * issuing an error semantically analyze all string/template
2699          * mixins that are members of the current ScopeDsymbol.
2700          */
2701         if (!s && sc.enclosing)
2702         {
2703             ScopeDsymbol sds = sc.enclosing.scopesym;
2704             if (sds && sds.members)
2705             {
2706                 void semanticOnMixin(Dsymbol member)
2707                 {
2708                     if (auto compileDecl = member.isMixinDeclaration())
2709                         compileDecl.dsymbolSemantic(sc);
2710                     else if (auto mixinTempl = member.isTemplateMixin())
2711                         mixinTempl.dsymbolSemantic(sc);
2712                 }
2713                 sds.members.foreachDsymbol( s => semanticOnMixin(s) );
2714                 s = sc.search(loc, mt.ident, &scopesym);
2715             }
2716         }
2717 
2718         if (s)
2719         {
2720             // https://issues.dlang.org/show_bug.cgi?id=16042
2721             // If `f` is really a function template, then replace `f`
2722             // with the function template declaration.
2723             if (auto f = s.isFuncDeclaration())
2724             {
2725                 if (auto td = getFuncTemplateDecl(f))
2726                 {
2727                     // If not at the beginning of the overloaded list of
2728                     // `TemplateDeclaration`s, then get the beginning
2729                     if (td.overroot)
2730                         td = td.overroot;
2731                     s = td;
2732                 }
2733             }
2734         }
2735 
2736         mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
2737         if (pt)
2738             pt = pt.addMod(mt.mod);
2739     }
2740 
2741     void visitInstance(TypeInstance mt)
2742     {
2743         // Note close similarity to TypeIdentifier::resolve()
2744 
2745         //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
2746         mt.tempinst.dsymbolSemantic(sc);
2747         if (!global.gag && mt.tempinst.errors)
2748             return returnError();
2749 
2750         mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid);
2751         if (pt)
2752             pt = pt.addMod(mt.mod);
2753         //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
2754     }
2755 
2756     void visitTypeof(TypeTypeof mt)
2757     {
2758         //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
2759         //static int nest; if (++nest == 50) *(char*)0=0;
2760         if (sc is null)
2761         {
2762             error(loc, "invalid scope");
2763             return returnError();
2764         }
2765         if (mt.inuse)
2766         {
2767             mt.inuse = 2;
2768             error(loc, "circular `typeof` definition");
2769         Lerr:
2770             mt.inuse--;
2771             return returnError();
2772         }
2773         mt.inuse++;
2774 
2775         /* Currently we cannot evaluate 'exp' in speculative context, because
2776          * the type implementation may leak to the final execution. Consider:
2777          *
2778          * struct S(T) {
2779          *   string toString() const { return "x"; }
2780          * }
2781          * void main() {
2782          *   alias X = typeof(S!int());
2783          *   assert(typeid(X).toString() == "x");
2784          * }
2785          */
2786         Scope* sc2 = sc.push();
2787 
2788         if (!mt.exp.isTypeidExp())
2789             /* Treat typeof(typeid(exp)) as needing
2790              * the full semantic analysis of the typeid.
2791              * https://issues.dlang.org/show_bug.cgi?id=20958
2792              */
2793             sc2.intypeof = 1;
2794 
2795         auto exp2 = mt.exp.expressionSemantic(sc2);
2796         exp2 = resolvePropertiesOnly(sc2, exp2);
2797         sc2.pop();
2798 
2799         if (exp2.op == EXP.error)
2800         {
2801             if (!global.gag)
2802                 mt.exp = exp2;
2803             goto Lerr;
2804         }
2805         mt.exp = exp2;
2806 
2807         if ((mt.exp.op == EXP.type || mt.exp.op == EXP.scope_) &&
2808             // https://issues.dlang.org/show_bug.cgi?id=23863
2809             // compile time sequences are valid types
2810             !mt.exp.type.isTypeTuple())
2811         {
2812             if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
2813                 mt.exp.checkType())
2814                 goto Lerr;
2815 
2816             /* Today, 'typeof(func)' returns void if func is a
2817              * function template (TemplateExp), or
2818              * template lambda (FuncExp).
2819              * It's actually used in Phobos as an idiom, to branch code for
2820              * template functions.
2821              */
2822         }
2823         if (auto f = mt.exp.op == EXP.variable    ? mt.exp.isVarExp().var.isFuncDeclaration()
2824                    : mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null)
2825         {
2826             // f might be a unittest declaration which is incomplete when compiled
2827             // without -unittest. That causes a segfault in checkForwardRef, see
2828             // https://issues.dlang.org/show_bug.cgi?id=20626
2829             if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc))
2830                 goto Lerr;
2831         }
2832         if (auto f = isFuncAddress(mt.exp))
2833         {
2834             if (f.checkForwardRef(loc))
2835                 goto Lerr;
2836         }
2837 
2838         Type t = mt.exp.type;
2839         if (!t)
2840         {
2841             error(loc, "expression `%s` has no type", mt.exp.toChars());
2842             goto Lerr;
2843         }
2844         if (t.ty == Ttypeof)
2845         {
2846             error(loc, "forward reference to `%s`", mt.toChars());
2847             goto Lerr;
2848         }
2849         if (mt.idents.length == 0)
2850         {
2851             returnType(t.addMod(mt.mod));
2852         }
2853         else
2854         {
2855             if (Dsymbol s = t.toDsymbol(sc))
2856                 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
2857             else
2858             {
2859                 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
2860                 e = e.expressionSemantic(sc);
2861                 resolveExp(e, pt, pe, ps);
2862             }
2863             if (pt)
2864                 pt = pt.addMod(mt.mod);
2865         }
2866         mt.inuse--;
2867     }
2868 
2869     void visitReturn(TypeReturn mt)
2870     {
2871         //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
2872         Type t;
2873         {
2874             FuncDeclaration func = sc.func;
2875             if (!func)
2876             {
2877                 error(loc, "`typeof(return)` must be inside function");
2878                 return returnError();
2879             }
2880             if (func.fes)
2881                 func = func.fes.func;
2882             t = func.type.nextOf();
2883             if (!t)
2884             {
2885                 error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars());
2886                 return returnError();
2887             }
2888         }
2889         if (mt.idents.length == 0)
2890         {
2891             return returnType(t.addMod(mt.mod));
2892         }
2893         else
2894         {
2895             if (Dsymbol s = t.toDsymbol(sc))
2896                 mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
2897             else
2898             {
2899                 auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
2900                 e = e.expressionSemantic(sc);
2901                 resolveExp(e, pt, pe, ps);
2902             }
2903             if (pt)
2904                 pt = pt.addMod(mt.mod);
2905         }
2906     }
2907 
2908     void visitSlice(TypeSlice mt)
2909     {
2910         mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
2911         if (pe)
2912         {
2913             // It's really a slice expression
2914             if (Dsymbol s = getDsymbol(pe))
2915                 pe = new DsymbolExp(loc, s);
2916             return returnExp(new ArrayExp(loc, pe, new IntervalExp(loc, mt.lwr, mt.upr)));
2917         }
2918         else if (ps)
2919         {
2920             Dsymbol s = ps;
2921             TupleDeclaration td = s.isTupleDeclaration();
2922             if (td)
2923             {
2924                 /* It's a slice of a TupleDeclaration
2925                  */
2926                 ScopeDsymbol sym = new ArrayScopeSymbol(sc, td);
2927                 sym.parent = sc.scopesym;
2928                 sc = sc.push(sym);
2929                 sc = sc.startCTFE();
2930                 mt.lwr = mt.lwr.expressionSemantic(sc);
2931                 mt.upr = mt.upr.expressionSemantic(sc);
2932                 sc = sc.endCTFE();
2933                 sc = sc.pop();
2934 
2935                 mt.lwr = mt.lwr.ctfeInterpret();
2936                 mt.upr = mt.upr.ctfeInterpret();
2937                 const i1 = mt.lwr.toUInteger();
2938                 const i2 = mt.upr.toUInteger();
2939                 if (!(i1 <= i2 && i2 <= td.objects.length))
2940                 {
2941                     error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1, i2, cast(ulong) td.objects.length);
2942                     return returnError();
2943                 }
2944 
2945                 if (i1 == 0 && i2 == td.objects.length)
2946                 {
2947                     return returnSymbol(td);
2948                 }
2949 
2950                 /* Create a new TupleDeclaration which
2951                  * is a slice [i1..i2] out of the old one.
2952                  */
2953                 auto objects = new Objects(cast(size_t)(i2 - i1));
2954                 for (size_t i = 0; i < objects.length; i++)
2955                 {
2956                     (*objects)[i] = (*td.objects)[cast(size_t)i1 + i];
2957                 }
2958 
2959                 return returnSymbol(new TupleDeclaration(loc, td.ident, objects));
2960             }
2961             else
2962                 visitType(mt);
2963         }
2964         else
2965         {
2966             if (pt.ty != Terror)
2967                 mt.next = pt; // prevent re-running semantic() on 'next'
2968             visitType(mt);
2969         }
2970     }
2971 
2972     void visitMixin(TypeMixin mt)
2973     {
2974         RootObject o = mt.obj;
2975 
2976         // if already resolved just set pe/pt/ps and return.
2977         if (o)
2978         {
2979             pe = o.isExpression();
2980             pt = o.isType();
2981             ps = o.isDsymbol();
2982             return;
2983         }
2984 
2985         o = mt.compileTypeMixin(loc, sc);
2986         if (auto t = o.isType())
2987         {
2988             resolve(t, loc, sc, pe, pt, ps, intypeid);
2989             if (pt)
2990                 pt = pt.addMod(mt.mod);
2991         }
2992         else if (auto e = o.isExpression())
2993         {
2994             e = e.expressionSemantic(sc);
2995             if (auto et = e.isTypeExp())
2996                 returnType(et.type.addMod(mt.mod));
2997             else
2998                 returnExp(e);
2999         }
3000         else
3001             returnError();
3002 
3003         // save the result
3004         mt.obj = pe ? pe : (pt ? pt : ps);
3005     }
3006 
3007     void visitTraits(TypeTraits mt)
3008     {
3009         // if already resolved just return the cached object.
3010         if (mt.obj)
3011         {
3012             pt = mt.obj.isType();
3013             ps = mt.obj.isDsymbol();
3014             pe = mt.obj.isExpression();
3015             return;
3016         }
3017 
3018         import dmd.traits : semanticTraits;
3019 
3020         if (Expression e = semanticTraits(mt.exp, sc))
3021         {
3022             switch (e.op)
3023             {
3024             case EXP.dotVariable:
3025                 mt.obj = e.isDotVarExp().var;
3026                 break;
3027             case EXP.variable:
3028                 mt.obj = e.isVarExp().var;
3029                 break;
3030             case EXP.function_:
3031                 auto fe = e.isFuncExp();
3032                 mt.obj = fe.td ? fe.td : fe.fd;
3033                 break;
3034             case EXP.dotTemplateDeclaration:
3035                 mt.obj = e.isDotTemplateExp().td;
3036                 break;
3037             case EXP.dSymbol:
3038                 mt.obj = e.isDsymbolExp().s;
3039                 break;
3040             case EXP.template_:
3041                 mt.obj = e.isTemplateExp().td;
3042                 break;
3043             case EXP.scope_:
3044                 mt.obj = e.isScopeExp().sds;
3045                 break;
3046             case EXP.tuple:
3047                 TupleExp te = e.isTupleExp();
3048                 Objects* elems = new Objects(te.exps.length);
3049                 foreach (i; 0 .. elems.length)
3050                 {
3051                     auto src = (*te.exps)[i];
3052                     switch (src.op)
3053                     {
3054                     case EXP.type:
3055                         (*elems)[i] = src.isTypeExp().type;
3056                         break;
3057                     case EXP.dotType:
3058                         (*elems)[i] = src.isDotTypeExp().sym.isType();
3059                         break;
3060                     case EXP.overloadSet:
3061                         (*elems)[i] = src.isOverExp().type;
3062                         break;
3063                     default:
3064                         if (auto sym = isDsymbol(src))
3065                             (*elems)[i] = sym;
3066                         else
3067                             (*elems)[i] = src;
3068                     }
3069                 }
3070                 TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
3071                 mt.obj = td;
3072                 break;
3073             case EXP.dotType:
3074                 mt.obj = e.isDotTypeExp().sym.isType();
3075                 break;
3076             case EXP.type:
3077                 mt.obj = e.isTypeExp().type;
3078                 break;
3079             case EXP.overloadSet:
3080                 mt.obj = e.isOverExp().type;
3081                 break;
3082             case EXP.error:
3083                 break;
3084             default:
3085                 mt.obj = e;
3086                 break;
3087             }
3088         }
3089 
3090         if (mt.obj)
3091         {
3092             if (auto t = mt.obj.isType())
3093             {
3094                 t = t.addMod(mt.mod);
3095                 mt.obj = t;
3096                 returnType(t);
3097             }
3098             else if (auto s = mt.obj.isDsymbol())
3099                 returnSymbol(s);
3100             else if (auto e = mt.obj.isExpression())
3101                 returnExp(e);
3102         }
3103         else
3104         {
3105             assert(global.errors);
3106             mt.obj = Type.terror;
3107             return returnError();
3108         }
3109     }
3110 
3111     switch (mt.ty)
3112     {
3113         default:        visitType      (mt);                    break;
3114         case Tsarray:   visitSArray    (mt.isTypeSArray());     break;
3115         case Tarray:    visitDArray    (mt.isTypeDArray());     break;
3116         case Taarray:   visitAArray    (mt.isTypeAArray());     break;
3117         case Tident:    visitIdentifier(mt.isTypeIdentifier()); break;
3118         case Tinstance: visitInstance  (mt.isTypeInstance());   break;
3119         case Ttypeof:   visitTypeof    (mt.isTypeTypeof());     break;
3120         case Treturn:   visitReturn    (mt.isTypeReturn());     break;
3121         case Tslice:    visitSlice     (mt.isTypeSlice());      break;
3122         case Tmixin:    visitMixin     (mt.isTypeMixin());      break;
3123         case Ttraits:   visitTraits    (mt.isTypeTraits());     break;
3124     }
3125 }
3126 
3127 /************************
3128  * Access the members of the object e. This type is same as e.type.
3129  * Params:
3130  *  mt = type for which the dot expression is used
3131  *  sc = instantiating scope
3132  *  e = expression to convert
3133  *  ident = identifier being used
3134  *  flag = DotExpFlag bit flags
3135  *
3136  * Returns:
3137  *  resulting expression with e.ident resolved
3138  */
3139 Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
3140 {
3141     Expression visitType(Type mt)
3142     {
3143         VarDeclaration v = null;
3144         static if (LOGDOTEXP)
3145         {
3146             printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3147         }
3148         Expression ex = e.lastComma();
3149         if (ex.op == EXP.dotVariable)
3150         {
3151             DotVarExp dv = cast(DotVarExp)ex;
3152             v = dv.var.isVarDeclaration();
3153         }
3154         else if (ex.op == EXP.variable)
3155         {
3156             VarExp ve = cast(VarExp)ex;
3157             v = ve.var.isVarDeclaration();
3158         }
3159         if (v)
3160         {
3161             if (ident == Id.offsetof)
3162             {
3163                 v.dsymbolSemantic(null);
3164                 if (v.isField())
3165                 {
3166                     auto ad = v.isMember();
3167                     objc.checkOffsetof(e, ad);
3168                     ad.size(e.loc);
3169                     if (ad.sizeok != Sizeok.done)
3170                         return ErrorExp.get();
3171                     return new IntegerExp(e.loc, v.offset, Type.tsize_t);
3172                 }
3173             }
3174             else if (ident == Id._init)
3175             {
3176                 Type tb = mt.toBasetype();
3177                 e = mt.defaultInitLiteral(e.loc);
3178                 if (tb.ty == Tstruct && tb.needsNested())
3179                 {
3180                     e.isStructLiteralExp().useStaticInit = true;
3181                 }
3182                 goto Lreturn;
3183             }
3184         }
3185         if (ident == Id.stringof)
3186         {
3187             /* https://issues.dlang.org/show_bug.cgi?id=3796
3188              * this should demangle e.type.deco rather than
3189              * pretty-printing the type.
3190              */
3191             e = new StringExp(e.loc, e.toString());
3192         }
3193         else
3194             e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
3195 
3196     Lreturn:
3197         if (e)
3198             e = e.expressionSemantic(sc);
3199         return e;
3200     }
3201 
3202     Expression visitError(TypeError)
3203     {
3204         return ErrorExp.get();
3205     }
3206 
3207     Expression visitBasic(TypeBasic mt)
3208     {
3209         static if (LOGDOTEXP)
3210         {
3211             printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3212         }
3213         Type t;
3214         if (ident == Id.re)
3215         {
3216             switch (mt.ty)
3217             {
3218             case Tcomplex32:
3219                 t = mt.tfloat32;
3220                 goto L1;
3221 
3222             case Tcomplex64:
3223                 t = mt.tfloat64;
3224                 goto L1;
3225 
3226             case Tcomplex80:
3227                 t = mt.tfloat80;
3228                 goto L1;
3229             L1:
3230                 e = e.castTo(sc, t);
3231                 break;
3232 
3233             case Tfloat32:
3234             case Tfloat64:
3235             case Tfloat80:
3236                 break;
3237 
3238             case Timaginary32:
3239                 t = mt.tfloat32;
3240                 goto L2;
3241 
3242             case Timaginary64:
3243                 t = mt.tfloat64;
3244                 goto L2;
3245 
3246             case Timaginary80:
3247                 t = mt.tfloat80;
3248                 goto L2;
3249             L2:
3250                 e = new RealExp(e.loc, CTFloat.zero, t);
3251                 break;
3252 
3253             default:
3254                 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3255                 break;
3256             }
3257         }
3258         else if (ident == Id.im)
3259         {
3260             Type t2;
3261             switch (mt.ty)
3262             {
3263             case Tcomplex32:
3264                 t = mt.timaginary32;
3265                 t2 = mt.tfloat32;
3266                 goto L3;
3267 
3268             case Tcomplex64:
3269                 t = mt.timaginary64;
3270                 t2 = mt.tfloat64;
3271                 goto L3;
3272 
3273             case Tcomplex80:
3274                 t = mt.timaginary80;
3275                 t2 = mt.tfloat80;
3276                 goto L3;
3277             L3:
3278                 e = e.castTo(sc, t);
3279                 e.type = t2;
3280                 break;
3281 
3282             case Timaginary32:
3283                 t = mt.tfloat32;
3284                 goto L4;
3285 
3286             case Timaginary64:
3287                 t = mt.tfloat64;
3288                 goto L4;
3289 
3290             case Timaginary80:
3291                 t = mt.tfloat80;
3292                 goto L4;
3293             L4:
3294                 e = e.copy();
3295                 e.type = t;
3296                 break;
3297 
3298             case Tfloat32:
3299             case Tfloat64:
3300             case Tfloat80:
3301                 e = new RealExp(e.loc, CTFloat.zero, mt);
3302                 break;
3303 
3304             default:
3305                 e = mt.Type.getProperty(sc, e.loc, ident, flag);
3306                 break;
3307             }
3308         }
3309         else
3310         {
3311             return visitType(mt);
3312         }
3313         if (!(flag & 1) || e)
3314             e = e.expressionSemantic(sc);
3315         return e;
3316     }
3317 
3318     Expression visitVector(TypeVector mt)
3319     {
3320         static if (LOGDOTEXP)
3321         {
3322             printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3323         }
3324         if (ident == Id.ptr && e.op == EXP.call)
3325         {
3326             /* The trouble with EXP.call is the return ABI for float[4] is different from
3327              * __vector(float[4]), and a type paint won't do.
3328              */
3329             e = new AddrExp(e.loc, e);
3330             e = e.expressionSemantic(sc);
3331             return e.castTo(sc, mt.basetype.nextOf().pointerTo());
3332         }
3333         if (ident == Id.array)
3334         {
3335             //e = e.castTo(sc, basetype);
3336             // Keep lvalue-ness
3337             e = new VectorArrayExp(e.loc, e);
3338             e = e.expressionSemantic(sc);
3339             return e;
3340         }
3341         if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof)
3342         {
3343             // init should return a new VectorExp
3344             // https://issues.dlang.org/show_bug.cgi?id=12776
3345             // offsetof does not work on a cast expression, so use e directly
3346             // stringof should not add a cast to the output
3347             return visitType(mt);
3348         }
3349 
3350         // Properties based on the vector element type and are values of the element type
3351         if (ident == Id.max || ident == Id.min || ident == Id.min_normal ||
3352             ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
3353         {
3354             auto vet = mt.basetype.isTypeSArray().next; // vector element type
3355             if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
3356                 return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
3357         }
3358 
3359         return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
3360     }
3361 
3362     Expression visitArray(TypeArray mt)
3363     {
3364         static if (LOGDOTEXP)
3365         {
3366             printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3367         }
3368 
3369         e = visitType(mt);
3370 
3371         if (!(flag & 1) || e)
3372             e = e.expressionSemantic(sc);
3373         return e;
3374     }
3375 
3376     Expression visitSArray(TypeSArray mt)
3377     {
3378         static if (LOGDOTEXP)
3379         {
3380             printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3381         }
3382         if (ident == Id.length)
3383         {
3384             Loc oldLoc = e.loc;
3385             e = mt.dim.copy();
3386             e.loc = oldLoc;
3387         }
3388         else if (ident == Id.ptr)
3389         {
3390             if (e.op == EXP.type)
3391             {
3392                 e.error("`%s` is not an expression", e.toChars());
3393                 return ErrorExp.get();
3394             }
3395             else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
3396             {
3397                 // .ptr on static array is @safe unless size is 0
3398                 // https://issues.dlang.org/show_bug.cgi?id=20853
3399                 return ErrorExp.get();
3400             }
3401             e = e.castTo(sc, e.type.nextOf().pointerTo());
3402         }
3403         else if (ident == Id._tupleof)
3404         {
3405             if (e.isTypeExp())
3406             {
3407                 e.error("`.tupleof` cannot be used on type `%s`", mt.toChars);
3408                 return ErrorExp.get();
3409             }
3410             else
3411             {
3412                 Expression e0;
3413                 Expression ev = e;
3414                 ev = extractSideEffect(sc, "__tup", e0, ev);
3415 
3416                 const length = cast(size_t)mt.dim.toUInteger();
3417                 auto exps = new Expressions();
3418                 exps.reserve(length);
3419                 foreach (i; 0 .. length)
3420                     exps.push(new IndexExp(e.loc, ev, new IntegerExp(e.loc, i, Type.tsize_t)));
3421                 e = new TupleExp(e.loc, e0, exps);
3422             }
3423         }
3424         else
3425         {
3426             e = visitArray(mt);
3427         }
3428         if (!(flag & 1) || e)
3429             e = e.expressionSemantic(sc);
3430         return e;
3431     }
3432 
3433     Expression visitDArray(TypeDArray mt)
3434     {
3435         static if (LOGDOTEXP)
3436         {
3437             printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3438         }
3439         if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
3440         {
3441             e.error("`%s` is not an expression", e.toChars());
3442             return ErrorExp.get();
3443         }
3444         if (ident == Id.length)
3445         {
3446             if (e.op == EXP.string_)
3447             {
3448                 StringExp se = cast(StringExp)e;
3449                 return new IntegerExp(se.loc, se.len, Type.tsize_t);
3450             }
3451             if (e.op == EXP.null_)
3452             {
3453                 return new IntegerExp(e.loc, 0, Type.tsize_t);
3454             }
3455             if (checkNonAssignmentArrayOp(e))
3456             {
3457                 return ErrorExp.get();
3458             }
3459             e = new ArrayLengthExp(e.loc, e);
3460             e.type = Type.tsize_t;
3461             return e;
3462         }
3463         else if (ident == Id.ptr)
3464         {
3465             if (checkUnsafeDotExp(sc, e, ident, flag))
3466                 return ErrorExp.get();
3467             return e.castTo(sc, mt.next.pointerTo());
3468         }
3469         else
3470         {
3471             return visitArray(mt);
3472         }
3473     }
3474 
3475     Expression visitAArray(TypeAArray mt)
3476     {
3477         static if (LOGDOTEXP)
3478         {
3479             printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3480         }
3481         if (ident == Id.length)
3482         {
3483             __gshared FuncDeclaration fd_aaLen = null;
3484             if (fd_aaLen is null)
3485             {
3486                 auto fparams = new Parameters();
3487                 fparams.push(new Parameter(STC.const_ | STC.scope_, mt, null, null, null));
3488                 fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
3489                 TypeFunction tf = fd_aaLen.type.toTypeFunction();
3490                 tf.purity = PURE.const_;
3491                 tf.isnothrow = true;
3492                 tf.isnogc = false;
3493             }
3494             Expression ev = new VarExp(e.loc, fd_aaLen, false);
3495             e = new CallExp(e.loc, ev, e);
3496             e.type = fd_aaLen.type.toTypeFunction().next;
3497             return e;
3498         }
3499         else
3500         {
3501             return visitType(mt);
3502         }
3503     }
3504 
3505     Expression visitReference(TypeReference mt)
3506     {
3507         static if (LOGDOTEXP)
3508         {
3509             printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3510         }
3511         // References just forward things along
3512         return mt.next.dotExp(sc, e, ident, flag);
3513     }
3514 
3515     Expression visitDelegate(TypeDelegate mt)
3516     {
3517         static if (LOGDOTEXP)
3518         {
3519             printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3520         }
3521         if (ident == Id.ptr)
3522         {
3523             e = new DelegatePtrExp(e.loc, e);
3524             e = e.expressionSemantic(sc);
3525         }
3526         else if (ident == Id.funcptr)
3527         {
3528             if (checkUnsafeDotExp(sc, e, ident, flag))
3529             {
3530                 return ErrorExp.get();
3531             }
3532             e = new DelegateFuncptrExp(e.loc, e);
3533             e = e.expressionSemantic(sc);
3534         }
3535         else
3536         {
3537             return visitType(mt);
3538         }
3539         return e;
3540     }
3541 
3542     /***************************************
3543      * `ident` was not found as a member of `mt`.
3544      * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
3545      * If that fails, forward to visitType().
3546      * Params:
3547      *  mt = class or struct
3548      *  sc = context
3549      *  e = `this` for `ident`
3550      *  ident = name of member
3551      *  flag = flag & 1, don't report "not a property" error and just return NULL.
3552      *         flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
3553      * Returns:
3554      *  resolved expression if found, otherwise null
3555      */
3556     Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
3557     {
3558         //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
3559 
3560         bool gagError = flag & 1;
3561 
3562         __gshared int nest;      // https://issues.dlang.org/show_bug.cgi?id=17380
3563 
3564         static Expression returnExp(Expression e)
3565         {
3566             --nest;
3567             return e;
3568         }
3569 
3570         if (++nest > global.recursionLimit)
3571         {
3572             .error(e.loc, "cannot resolve identifier `%s`", ident.toChars());
3573             return returnExp(gagError ? null : ErrorExp.get());
3574         }
3575 
3576 
3577         assert(mt.ty == Tstruct || mt.ty == Tclass);
3578         auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
3579         assert(sym);
3580         if (// https://issues.dlang.org/show_bug.cgi?id=22054
3581             // if a class or struct does not have a body
3582             // there is no point in searching for its members
3583             sym.members &&
3584             ident != Id.__sizeof &&
3585             ident != Id.__xalignof &&
3586             ident != Id._init &&
3587             ident != Id._mangleof &&
3588             ident != Id.stringof &&
3589             ident != Id.offsetof &&
3590             // https://issues.dlang.org/show_bug.cgi?id=15045
3591             // Don't forward special built-in member functions.
3592             ident != Id.ctor &&
3593             ident != Id.dtor &&
3594             ident != Id.__xdtor &&
3595             ident != Id.postblit &&
3596             ident != Id.__xpostblit)
3597         {
3598             /* Look for overloaded opDot() to see if we should forward request
3599              * to it.
3600              */
3601             if (auto fd = search_function(sym, Id.opDot))
3602             {
3603                 /* Rewrite e.ident as:
3604                  *  e.opDot().ident
3605                  */
3606                 e = build_overload(e.loc, sc, e, null, fd);
3607                 // @@@DEPRECATED_2.110@@@.
3608                 // Deprecated in 2.082, made an error in 2.100.
3609                 e.error("`opDot` is obsolete. Use `alias this`");
3610                 return ErrorExp.get();
3611             }
3612 
3613             /* Look for overloaded opDispatch to see if we should forward request
3614              * to it.
3615              */
3616             if (auto fd = search_function(sym, Id.opDispatch))
3617             {
3618                 /* Rewrite e.ident as:
3619                  *  e.opDispatch!("ident")
3620                  */
3621                 TemplateDeclaration td = fd.isTemplateDeclaration();
3622                 if (!td)
3623                 {
3624                     fd.error("must be a template `opDispatch(string s)`, not a %s", fd.kind());
3625                     return returnExp(ErrorExp.get());
3626                 }
3627                 auto se = new StringExp(e.loc, ident.toString());
3628                 auto tiargs = new Objects();
3629                 tiargs.push(se);
3630                 auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
3631                 dti.ti.tempdecl = td;
3632                 /* opDispatch, which doesn't need IFTI,  may occur instantiate error.
3633                  * e.g.
3634                  *  template opDispatch(name) if (isValid!name) { ... }
3635                  */
3636                 uint errors = gagError ? global.startGagging() : 0;
3637                 e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none);
3638                 if (gagError && global.endGagging(errors))
3639                     e = null;
3640                 return returnExp(e);
3641             }
3642 
3643             /* See if we should forward to the alias this.
3644              */
3645             auto alias_e = flag & DotExpFlag.noAliasThis ? null
3646                                                          : resolveAliasThis(sc, e, gagError);
3647             if (alias_e && alias_e != e)
3648             {
3649                 /* Rewrite e.ident as:
3650                  *  e.aliasthis.ident
3651                  */
3652                 auto die = new DotIdExp(e.loc, alias_e, ident);
3653 
3654                 auto errors = gagError ? 0 : global.startGagging();
3655                 auto exp = die.dotIdSemanticProp(sc, gagError);
3656                 if (!gagError)
3657                 {
3658                     global.endGagging(errors);
3659                     if (exp && exp.op == EXP.error)
3660                         exp = null;
3661                 }
3662 
3663                 if (exp && gagError)
3664                     // now that we know that the alias this leads somewhere useful,
3665                     // go back and print deprecations/warnings that we skipped earlier due to the gag
3666                     resolveAliasThis(sc, e, false);
3667 
3668                 return returnExp(exp);
3669             }
3670         }
3671         return returnExp(visitType(mt));
3672     }
3673 
3674     Expression visitStruct(TypeStruct mt)
3675     {
3676         Dsymbol s;
3677         static if (LOGDOTEXP)
3678         {
3679             printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3680         }
3681         assert(e.op != EXP.dot);
3682 
3683         // https://issues.dlang.org/show_bug.cgi?id=14010
3684         if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
3685         {
3686             return mt.getProperty(sc, e.loc, ident, flag & 1);
3687         }
3688 
3689         /* If e.tupleof
3690          */
3691         if (ident == Id._tupleof)
3692         {
3693             /* Create a TupleExp out of the fields of the struct e:
3694              * (e.field0, e.field1, e.field2, ...)
3695              */
3696             e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
3697 
3698             if (!mt.sym.determineFields())
3699             {
3700                 error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars());
3701             }
3702 
3703             Expression e0;
3704             Expression ev = e.op == EXP.type ? null : e;
3705             if (ev)
3706                 ev = extractSideEffect(sc, "__tup", e0, ev);
3707 
3708             auto exps = new Expressions();
3709             exps.reserve(mt.sym.fields.length);
3710             for (size_t i = 0; i < mt.sym.fields.length; i++)
3711             {
3712                 VarDeclaration v = mt.sym.fields[i];
3713                 Expression ex;
3714                 if (ev)
3715                     ex = new DotVarExp(e.loc, ev, v);
3716                 else
3717                 {
3718                     ex = new VarExp(e.loc, v);
3719                     ex.type = ex.type.addMod(e.type.mod);
3720                 }
3721                 exps.push(ex);
3722             }
3723 
3724             e = new TupleExp(e.loc, e0, exps);
3725             Scope* sc2 = sc.push();
3726             sc2.flags |= SCOPE.noaccesscheck;
3727             e = e.expressionSemantic(sc2);
3728             sc2.pop();
3729             return e;
3730         }
3731 
3732         immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
3733         s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
3734     L1:
3735         if (!s)
3736         {
3737             return noMember(mt, sc, e, ident, flag);
3738         }
3739         if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
3740         {
3741             return noMember(mt, sc, e, ident, flag);
3742         }
3743         // check before alias resolution; the alias itself might be deprecated!
3744         if (s.isAliasDeclaration)
3745             e.checkDeprecated(sc, s);
3746         s = s.toAlias();
3747 
3748         if (auto em = s.isEnumMember())
3749         {
3750             return em.getVarExp(e.loc, sc);
3751         }
3752         if (auto v = s.isVarDeclaration())
3753         {
3754             v.checkDeprecated(e.loc, sc);
3755             v.checkDisabled(e.loc, sc);
3756             if (!v.type ||
3757                 !v.type.deco && v.inuse)
3758             {
3759                 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
3760                     e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
3761                 else
3762                     e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
3763                 return ErrorExp.get();
3764             }
3765             if (v.type.ty == Terror)
3766             {
3767                 return ErrorExp.get();
3768             }
3769 
3770             if ((v.storage_class & STC.manifest) && v._init)
3771             {
3772                 if (v.inuse)
3773                 {
3774                     e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
3775                     return ErrorExp.get();
3776                 }
3777                 checkAccess(e.loc, sc, null, v);
3778                 Expression ve = new VarExp(e.loc, v);
3779                 if (!isTrivialExp(e))
3780                 {
3781                     ve = new CommaExp(e.loc, e, ve);
3782                 }
3783                 return ve.expressionSemantic(sc);
3784             }
3785         }
3786 
3787         if (auto t = s.getType())
3788         {
3789             return (new TypeExp(e.loc, t)).expressionSemantic(sc);
3790         }
3791 
3792         TemplateMixin tm = s.isTemplateMixin();
3793         if (tm)
3794         {
3795             return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
3796         }
3797 
3798         TemplateDeclaration td = s.isTemplateDeclaration();
3799         if (td)
3800         {
3801             if (e.op == EXP.type)
3802                 e = new TemplateExp(e.loc, td);
3803             else
3804                 e = new DotTemplateExp(e.loc, e, td);
3805             return e.expressionSemantic(sc);
3806         }
3807 
3808         TemplateInstance ti = s.isTemplateInstance();
3809         if (ti)
3810         {
3811             if (!ti.semanticRun)
3812             {
3813                 ti.dsymbolSemantic(sc);
3814                 if (!ti.inst || ti.errors) // if template failed to expand
3815                 {
3816                     return ErrorExp.get();
3817                 }
3818             }
3819             s = ti.inst.toAlias();
3820             if (!s.isTemplateInstance())
3821                 goto L1;
3822             if (e.op == EXP.type)
3823                 e = new ScopeExp(e.loc, ti);
3824             else
3825                 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
3826             return e.expressionSemantic(sc);
3827         }
3828 
3829         if (s.isImport() || s.isModule() || s.isPackage())
3830         {
3831             return symbolToExp(s, e.loc, sc, false);
3832         }
3833 
3834         OverloadSet o = s.isOverloadSet();
3835         if (o)
3836         {
3837             auto oe = new OverExp(e.loc, o);
3838             if (e.op == EXP.type)
3839             {
3840                 return oe;
3841             }
3842             return new DotExp(e.loc, e, oe);
3843         }
3844 
3845         Declaration d = s.isDeclaration();
3846         if (!d)
3847         {
3848             e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
3849             return ErrorExp.get();
3850         }
3851 
3852         if (e.op == EXP.type)
3853         {
3854             /* It's:
3855              *    Struct.d
3856              */
3857             if (TupleDeclaration tup = d.isTupleDeclaration())
3858             {
3859                 e = new TupleExp(e.loc, tup);
3860                 return e.expressionSemantic(sc);
3861             }
3862             if (d.needThis() && sc.intypeof != 1)
3863             {
3864                 /* Rewrite as:
3865                  *  this.d
3866                  *
3867                  * only if the scope in which we are
3868                  * has a `this` that matches the type
3869                  * of the lhs of the dot expression.
3870                  *
3871                  * https://issues.dlang.org/show_bug.cgi?id=23617
3872                  */
3873                 auto fd = hasThis(sc);
3874                 if (fd && fd.isThis() == mt.sym)
3875                 {
3876                     e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
3877                     return e.expressionSemantic(sc);
3878                 }
3879             }
3880             if (d.semanticRun == PASS.initial)
3881                 d.dsymbolSemantic(null);
3882             checkAccess(e.loc, sc, e, d);
3883             auto ve = new VarExp(e.loc, d);
3884             if (d.isVarDeclaration() && d.needThis())
3885                 ve.type = d.type.addMod(e.type.mod);
3886             return ve;
3887         }
3888 
3889         bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
3890         if (d.isDataseg() || unreal && d.isField())
3891         {
3892             // (e, d)
3893             checkAccess(e.loc, sc, e, d);
3894             Expression ve = new VarExp(e.loc, d);
3895             e = unreal ? ve : new CommaExp(e.loc, e, ve);
3896             return e.expressionSemantic(sc);
3897         }
3898 
3899         e = new DotVarExp(e.loc, e, d);
3900         return e.expressionSemantic(sc);
3901     }
3902 
3903     Expression visitEnum(TypeEnum mt)
3904     {
3905         static if (LOGDOTEXP)
3906         {
3907             printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars());
3908         }
3909         // https://issues.dlang.org/show_bug.cgi?id=14010
3910         if (ident == Id._mangleof)
3911         {
3912             return mt.getProperty(sc, e.loc, ident, flag & 1);
3913         }
3914 
3915         if (mt.sym.semanticRun < PASS.semanticdone)
3916             mt.sym.dsymbolSemantic(null);
3917 
3918         Dsymbol s = mt.sym.search(e.loc, ident);
3919         if (!s)
3920         {
3921             if (ident == Id._init)
3922             {
3923                 return mt.getProperty(sc, e.loc, ident, flag & 1);
3924             }
3925 
3926             /* Allow special enums to not need a member list
3927              */
3928             if ((ident == Id.max || ident == Id.min) && (mt.sym.members || !mt.sym.isSpecial()))
3929             {
3930                 return mt.getProperty(sc, e.loc, ident, flag & 1);
3931             }
3932 
3933             Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag);
3934             if (!(flag & 1) && !res)
3935             {
3936                 if (auto ns = mt.sym.search_correct(ident))
3937                     e.error("no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
3938                         ns.toChars());
3939                 else
3940                     e.error("no property `%s` for type `%s`", ident.toChars(),
3941                         mt.toChars());
3942 
3943                 return ErrorExp.get();
3944             }
3945             return res;
3946         }
3947         EnumMember m = s.isEnumMember();
3948         return m.getVarExp(e.loc, sc);
3949     }
3950 
3951     Expression visitClass(TypeClass mt)
3952     {
3953         Dsymbol s;
3954         static if (LOGDOTEXP)
3955         {
3956             printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
3957         }
3958         assert(e.op != EXP.dot);
3959 
3960         // https://issues.dlang.org/show_bug.cgi?id=12543
3961         if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
3962         {
3963             return mt.Type.getProperty(sc, e.loc, ident, 0);
3964         }
3965 
3966         /* If e.tupleof
3967          */
3968         if (ident == Id._tupleof)
3969         {
3970             objc.checkTupleof(e, mt);
3971 
3972             /* Create a TupleExp
3973              */
3974             e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
3975 
3976             mt.sym.size(e.loc); // do semantic of type
3977 
3978             Expression e0;
3979             Expression ev = e.op == EXP.type ? null : e;
3980             if (ev)
3981                 ev = extractSideEffect(sc, "__tup", e0, ev);
3982 
3983             auto exps = new Expressions();
3984             exps.reserve(mt.sym.fields.length);
3985             for (size_t i = 0; i < mt.sym.fields.length; i++)
3986             {
3987                 VarDeclaration v = mt.sym.fields[i];
3988                 // Don't include hidden 'this' pointer
3989                 if (v.isThisDeclaration())
3990                     continue;
3991                 Expression ex;
3992                 if (ev)
3993                     ex = new DotVarExp(e.loc, ev, v);
3994                 else
3995                 {
3996                     ex = new VarExp(e.loc, v);
3997                     ex.type = ex.type.addMod(e.type.mod);
3998                 }
3999                 exps.push(ex);
4000             }
4001 
4002             e = new TupleExp(e.loc, e0, exps);
4003             Scope* sc2 = sc.push();
4004             sc2.flags |= SCOPE.noaccesscheck;
4005             e = e.expressionSemantic(sc2);
4006             sc2.pop();
4007             return e;
4008         }
4009 
4010         int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
4011         s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
4012 
4013     L1:
4014         if (!s)
4015         {
4016             // See if it's a 'this' class or a base class
4017             if (mt.sym.ident == ident)
4018             {
4019                 if (e.op == EXP.type)
4020                 {
4021                     return mt.Type.getProperty(sc, e.loc, ident, 0);
4022                 }
4023                 e = new DotTypeExp(e.loc, e, mt.sym);
4024                 e = e.expressionSemantic(sc);
4025                 return e;
4026             }
4027             if (auto cbase = mt.sym.searchBase(ident))
4028             {
4029                 if (e.op == EXP.type)
4030                 {
4031                     return mt.Type.getProperty(sc, e.loc, ident, 0);
4032                 }
4033                 if (auto ifbase = cbase.isInterfaceDeclaration())
4034                     e = new CastExp(e.loc, e, ifbase.type);
4035                 else
4036                     e = new DotTypeExp(e.loc, e, cbase);
4037                 e = e.expressionSemantic(sc);
4038                 return e;
4039             }
4040 
4041             if (ident == Id.classinfo)
4042             {
4043                 if (!Type.typeinfoclass)
4044                 {
4045                     error(e.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
4046                     return ErrorExp.get();
4047                 }
4048 
4049                 Type t = Type.typeinfoclass.type;
4050                 if (e.op == EXP.type || e.op == EXP.dotType)
4051                 {
4052                     /* For type.classinfo, we know the classinfo
4053                      * at compile time.
4054                      */
4055                     if (!mt.sym.vclassinfo)
4056                         mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type);
4057                     e = new VarExp(e.loc, mt.sym.vclassinfo);
4058                     e = e.addressOf();
4059                     e.type = t; // do this so we don't get redundant dereference
4060                 }
4061                 else
4062                 {
4063                     /* For class objects, the classinfo reference is the first
4064                      * entry in the vtbl[]
4065                      */
4066                     e = new PtrExp(e.loc, e);
4067                     e.type = t.pointerTo();
4068                     if (mt.sym.isInterfaceDeclaration())
4069                     {
4070                         if (mt.sym.isCPPinterface())
4071                         {
4072                             /* C++ interface vtbl[]s are different in that the
4073                              * first entry is always pointer to the first virtual
4074                              * function, not classinfo.
4075                              * We can't get a .classinfo for it.
4076                              */
4077                             error(e.loc, "no `.classinfo` for C++ interface objects");
4078                         }
4079                         /* For an interface, the first entry in the vtbl[]
4080                          * is actually a pointer to an instance of struct Interface.
4081                          * The first member of Interface is the .classinfo,
4082                          * so add an extra pointer indirection.
4083                          */
4084                         e.type = e.type.pointerTo();
4085                         e = new PtrExp(e.loc, e);
4086                         e.type = t.pointerTo();
4087                     }
4088                     e = new PtrExp(e.loc, e, t);
4089                 }
4090                 return e;
4091             }
4092 
4093             if (ident == Id.__vptr)
4094             {
4095                 /* The pointer to the vtbl[]
4096                  * *cast(immutable(void*)**)e
4097                  */
4098                 e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo());
4099                 e = new PtrExp(e.loc, e);
4100                 e = e.expressionSemantic(sc);
4101                 return e;
4102             }
4103 
4104             if (ident == Id.__monitor && mt.sym.hasMonitor())
4105             {
4106                 /* The handle to the monitor (call it a void*)
4107                  * *(cast(void**)e + 1)
4108                  */
4109                 e = e.castTo(sc, mt.tvoidptr.pointerTo());
4110                 e = new AddExp(e.loc, e, IntegerExp.literal!1);
4111                 e = new PtrExp(e.loc, e);
4112                 e = e.expressionSemantic(sc);
4113                 return e;
4114             }
4115 
4116             if (ident == Id.outer && mt.sym.vthis)
4117             {
4118                 if (mt.sym.vthis.semanticRun == PASS.initial)
4119                     mt.sym.vthis.dsymbolSemantic(null);
4120 
4121                 if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
4122                 {
4123                     auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4124                     dve.type = cdp.type.addMod(e.type.mod);
4125                     return dve;
4126                 }
4127 
4128                 /* https://issues.dlang.org/show_bug.cgi?id=15839
4129                  * Find closest parent class through nested functions.
4130                  */
4131                 for (auto p = mt.sym.toParentLocal(); p; p = p.toParentLocal())
4132                 {
4133                     auto fd = p.isFuncDeclaration();
4134                     if (!fd)
4135                         break;
4136                     auto ad = fd.isThis();
4137                     if (!ad && fd.isNested())
4138                         continue;
4139                     if (!ad)
4140                         break;
4141                     if (auto cdp = ad.isClassDeclaration())
4142                     {
4143                         auto ve = new ThisExp(e.loc);
4144 
4145                         ve.var = fd.vthis;
4146                         const nestedError = fd.vthis.checkNestedReference(sc, e.loc);
4147                         assert(!nestedError);
4148 
4149                         ve.type = cdp.type.addMod(fd.vthis.type.mod).addMod(e.type.mod);
4150                         return ve;
4151                     }
4152                     break;
4153                 }
4154 
4155                 // Continue to show enclosing function's frame (stack or closure).
4156                 auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
4157                 dve.type = mt.sym.vthis.type.addMod(e.type.mod);
4158                 return dve;
4159             }
4160 
4161             return noMember(mt, sc, e, ident, flag & 1);
4162         }
4163         if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
4164         {
4165             return noMember(mt, sc, e, ident, flag);
4166         }
4167         if (!s.isFuncDeclaration()) // because of overloading
4168         {
4169             s.checkDeprecated(e.loc, sc);
4170             if (auto d = s.isDeclaration())
4171                 d.checkDisabled(e.loc, sc);
4172         }
4173         s = s.toAlias();
4174 
4175         if (auto em = s.isEnumMember())
4176         {
4177             return em.getVarExp(e.loc, sc);
4178         }
4179         if (auto v = s.isVarDeclaration())
4180         {
4181             if (!v.type ||
4182                 !v.type.deco && v.inuse)
4183             {
4184                 if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
4185                     e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
4186                 else
4187                     e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
4188                 return ErrorExp.get();
4189             }
4190             if (v.type.ty == Terror)
4191             {
4192                 e.error("type of variable `%s` has errors", v.toPrettyChars);
4193                 return ErrorExp.get();
4194             }
4195 
4196             if ((v.storage_class & STC.manifest) && v._init)
4197             {
4198                 if (v.inuse)
4199                 {
4200                     e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
4201                     return ErrorExp.get();
4202                 }
4203                 checkAccess(e.loc, sc, null, v);
4204                 Expression ve = new VarExp(e.loc, v);
4205                 ve = ve.expressionSemantic(sc);
4206                 return ve;
4207             }
4208         }
4209 
4210         if (auto t = s.getType())
4211         {
4212             return (new TypeExp(e.loc, t)).expressionSemantic(sc);
4213         }
4214 
4215         TemplateMixin tm = s.isTemplateMixin();
4216         if (tm)
4217         {
4218             return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
4219         }
4220 
4221         TemplateDeclaration td = s.isTemplateDeclaration();
4222 
4223         Expression toTemplateExp(TemplateDeclaration td)
4224         {
4225             if (e.op == EXP.type)
4226                 e = new TemplateExp(e.loc, td);
4227             else
4228                 e = new DotTemplateExp(e.loc, e, td);
4229             e = e.expressionSemantic(sc);
4230             return e;
4231         }
4232 
4233         if (td)
4234         {
4235             return toTemplateExp(td);
4236         }
4237 
4238         TemplateInstance ti = s.isTemplateInstance();
4239         if (ti)
4240         {
4241             if (!ti.semanticRun)
4242             {
4243                 ti.dsymbolSemantic(sc);
4244                 if (!ti.inst || ti.errors) // if template failed to expand
4245                 {
4246                     return ErrorExp.get();
4247                 }
4248             }
4249             s = ti.inst.toAlias();
4250             if (!s.isTemplateInstance())
4251                 goto L1;
4252             if (e.op == EXP.type)
4253                 e = new ScopeExp(e.loc, ti);
4254             else
4255                 e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
4256             return e.expressionSemantic(sc);
4257         }
4258 
4259         if (s.isImport() || s.isModule() || s.isPackage())
4260         {
4261             e = symbolToExp(s, e.loc, sc, false);
4262             return e;
4263         }
4264 
4265         OverloadSet o = s.isOverloadSet();
4266         if (o)
4267         {
4268             auto oe = new OverExp(e.loc, o);
4269             if (e.op == EXP.type)
4270             {
4271                 return oe;
4272             }
4273             return new DotExp(e.loc, e, oe);
4274         }
4275 
4276         Declaration d = s.isDeclaration();
4277         if (!d)
4278         {
4279             e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
4280             return ErrorExp.get();
4281         }
4282 
4283         if (e.op == EXP.type)
4284         {
4285             /* It's:
4286              *    Class.d
4287              */
4288             if (TupleDeclaration tup = d.isTupleDeclaration())
4289             {
4290                 e = new TupleExp(e.loc, tup);
4291                 e = e.expressionSemantic(sc);
4292                 return e;
4293             }
4294 
4295             if (mt.sym.classKind == ClassKind.objc
4296                 && d.isFuncDeclaration()
4297                 && d.isFuncDeclaration().isStatic
4298                 && d.isFuncDeclaration().objc.selector)
4299             {
4300                 auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
4301                 return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
4302             }
4303             else if (d.needThis() && sc.intypeof != 1)
4304             {
4305                 /* Rewrite as:
4306                  *  this.d
4307                  */
4308                 AggregateDeclaration ad = d.isMemberLocal();
4309                 if (auto f = hasThis(sc))
4310                 {
4311                     // This is almost same as getRightThis() in expressionsem.d
4312                     Expression e1;
4313                     Type t;
4314                     /* returns: true to continue, false to return */
4315                     if (f.hasDualContext())
4316                     {
4317                         if (f.followInstantiationContext(ad))
4318                         {
4319                             e1 = new VarExp(e.loc, f.vthis);
4320                             e1 = new PtrExp(e1.loc, e1);
4321                             e1 = new IndexExp(e1.loc, e1, IntegerExp.literal!1);
4322                             auto pd = f.toParent2().isDeclaration();
4323                             assert(pd);
4324                             t = pd.type.toBasetype();
4325                             e1 = getThisSkipNestedFuncs(e1.loc, sc, f.toParent2(), ad, e1, t, d, true);
4326                             if (!e1)
4327                             {
4328                                 e = new VarExp(e.loc, d);
4329                                 return e;
4330                             }
4331                             goto L2;
4332                         }
4333                     }
4334                     e1 = new ThisExp(e.loc);
4335                     e1 = e1.expressionSemantic(sc);
4336                 L2:
4337                     t = e1.type.toBasetype();
4338                     ClassDeclaration cd = e.type.isClassHandle();
4339                     ClassDeclaration tcd = t.isClassHandle();
4340                     if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null)))
4341                     {
4342                         e = new DotTypeExp(e1.loc, e1, cd);
4343                         e = new DotVarExp(e.loc, e, d);
4344                         e = e.expressionSemantic(sc);
4345                         return e;
4346                     }
4347                     if (tcd && tcd.isNested())
4348                     {
4349                         /* e1 is the 'this' pointer for an inner class: tcd.
4350                          * Rewrite it as the 'this' pointer for the outer class.
4351                          */
4352                         auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
4353                         e1 = new DotVarExp(e.loc, e1, vthis);
4354                         e1.type = vthis.type;
4355                         e1.type = e1.type.addMod(t.mod);
4356                         // Do not call ensureStaticLinkTo()
4357                         //e1 = e1.expressionSemantic(sc);
4358 
4359                         // Skip up over nested functions, and get the enclosing
4360                         // class type.
4361                         e1 = getThisSkipNestedFuncs(e1.loc, sc, tcd.toParentP(ad), ad, e1, t, d, true);
4362                         if (!e1)
4363                         {
4364                             e = new VarExp(e.loc, d);
4365                             return e;
4366                         }
4367                         goto L2;
4368                     }
4369                 }
4370             }
4371             //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
4372             if (d.semanticRun == PASS.initial)
4373                 d.dsymbolSemantic(null);
4374 
4375             // If static function, get the most visible overload.
4376             // Later on the call is checked for correctness.
4377             // https://issues.dlang.org/show_bug.cgi?id=12511
4378             Dsymbol d2 = d;
4379             if (auto fd = d.isFuncDeclaration())
4380             {
4381                 import dmd.access : mostVisibleOverload;
4382                 d2 = mostVisibleOverload(fd, sc._module);
4383             }
4384 
4385             checkAccess(e.loc, sc, e, d2);
4386             if (d2.isDeclaration())
4387             {
4388                 d = cast(Declaration)d2;
4389                 auto ve = new VarExp(e.loc, d);
4390                 if (d.isVarDeclaration() && d.needThis())
4391                     ve.type = d.type.addMod(e.type.mod);
4392                 return ve;
4393             }
4394             else if (d2.isTemplateDeclaration())
4395             {
4396                 return toTemplateExp(cast(TemplateDeclaration)d2);
4397             }
4398             else
4399                 assert(0);
4400         }
4401 
4402         bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
4403         if (d.isDataseg() || unreal && d.isField())
4404         {
4405             // (e, d)
4406             checkAccess(e.loc, sc, e, d);
4407             Expression ve = new VarExp(e.loc, d);
4408             e = unreal ? ve : new CommaExp(e.loc, e, ve);
4409             e = e.expressionSemantic(sc);
4410             return e;
4411         }
4412 
4413         e = new DotVarExp(e.loc, e, d);
4414         e = e.expressionSemantic(sc);
4415         return e;
4416     }
4417 
4418     switch (mt.ty)
4419     {
4420         case Tvector:    return visitVector   (mt.isTypeVector());
4421         case Tsarray:    return visitSArray   (mt.isTypeSArray());
4422         case Tstruct:    return visitStruct   (mt.isTypeStruct());
4423         case Tenum:      return visitEnum     (mt.isTypeEnum());
4424         case Terror:     return visitError    (mt.isTypeError());
4425         case Tarray:     return visitDArray   (mt.isTypeDArray());
4426         case Taarray:    return visitAArray   (mt.isTypeAArray());
4427         case Treference: return visitReference(mt.isTypeReference());
4428         case Tdelegate:  return visitDelegate (mt.isTypeDelegate());
4429         case Tclass:     return visitClass    (mt.isTypeClass());
4430 
4431         default:         return mt.isTypeBasic()
4432                                 ? visitBasic(cast(TypeBasic)mt)
4433                                 : visitType(mt);
4434     }
4435 }
4436 
4437 
4438 /************************
4439  * Get the default initialization expression for a type.
4440  * Params:
4441  *  mt = the type for which the init expression is returned
4442  *  loc = the location where the expression needs to be evaluated
4443  *  isCfile = default initializers are different with C
4444  *
4445  * Returns:
4446  *  The initialization expression for the type.
4447  */
4448 extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
4449 {
4450     Expression visitBasic(TypeBasic mt)
4451     {
4452         static if (LOGDEFAULTINIT)
4453         {
4454             printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
4455         }
4456         dinteger_t value = 0;
4457 
4458         switch (mt.ty)
4459         {
4460         case Tchar:
4461             value = isCfile ? 0 : 0xFF;
4462             break;
4463 
4464         case Twchar:
4465         case Tdchar:
4466             value = isCfile ? 0 : 0xFFFF;
4467             break;
4468 
4469         case Timaginary32:
4470         case Timaginary64:
4471         case Timaginary80:
4472         case Tfloat32:
4473         case Tfloat64:
4474         case Tfloat80:
4475             return new RealExp(loc, isCfile ? CTFloat.zero : target.RealProperties.nan, mt);
4476 
4477         case Tcomplex32:
4478         case Tcomplex64:
4479         case Tcomplex80:
4480             {
4481                 // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
4482                 const cvalue = isCfile ? complex_t(CTFloat.zero, CTFloat.zero)
4483                                        : complex_t(target.RealProperties.nan, target.RealProperties.nan);
4484                 return new ComplexExp(loc, cvalue, mt);
4485             }
4486 
4487         case Tvoid:
4488             error(loc, "`void` does not have a default initializer");
4489             return ErrorExp.get();
4490 
4491         default:
4492             break;
4493         }
4494         return new IntegerExp(loc, value, mt);
4495     }
4496 
4497     Expression visitVector(TypeVector mt)
4498     {
4499         //printf("TypeVector::defaultInit()\n");
4500         assert(mt.basetype.ty == Tsarray);
4501         Expression e = mt.basetype.defaultInit(loc, isCfile);
4502         auto ve = new VectorExp(loc, e, mt);
4503         ve.type = mt;
4504         ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc));
4505         return ve;
4506     }
4507 
4508     Expression visitSArray(TypeSArray mt)
4509     {
4510         static if (LOGDEFAULTINIT)
4511         {
4512             printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
4513         }
4514         if (mt.next.ty == Tvoid)
4515             return mt.tuns8.defaultInit(loc, isCfile);
4516         else
4517             return mt.next.defaultInit(loc, isCfile);
4518     }
4519 
4520     Expression visitFunction(TypeFunction mt)
4521     {
4522         error(loc, "`function` does not have a default initializer");
4523         return ErrorExp.get();
4524     }
4525 
4526     Expression visitStruct(TypeStruct mt)
4527     {
4528         static if (LOGDEFAULTINIT)
4529         {
4530             printf("TypeStruct::defaultInit() '%s'\n", mt.toChars());
4531         }
4532         Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym);
4533         assert(d);
4534         d.type = mt;
4535         d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398
4536         return new VarExp(mt.sym.loc, d);
4537     }
4538 
4539     Expression visitEnum(TypeEnum mt)
4540     {
4541         static if (LOGDEFAULTINIT)
4542         {
4543             printf("TypeEnum::defaultInit() '%s'\n", mt.toChars());
4544         }
4545         // Initialize to first member of enum
4546         Expression e = mt.sym.getDefaultValue(loc);
4547         e = e.copy();
4548         e.loc = loc;
4549         e.type = mt; // to deal with const, immutable, etc., variants
4550         return e;
4551     }
4552 
4553     Expression visitTuple(TypeTuple mt)
4554     {
4555         static if (LOGDEFAULTINIT)
4556         {
4557             printf("TypeTuple::defaultInit() '%s'\n", mt.toChars());
4558         }
4559         auto exps = new Expressions(mt.arguments.length);
4560         for (size_t i = 0; i < mt.arguments.length; i++)
4561         {
4562             Parameter p = (*mt.arguments)[i];
4563             assert(p.type);
4564             Expression e = p.type.defaultInitLiteral(loc);
4565             if (e.op == EXP.error)
4566             {
4567                 return e;
4568             }
4569             (*exps)[i] = e;
4570         }
4571         return new TupleExp(loc, exps);
4572     }
4573 
4574     Expression visitNoreturn(TypeNoreturn mt)
4575     {
4576         static if (LOGDEFAULTINIT)
4577         {
4578             printf("TypeNoreturn::defaultInit() '%s'\n", mt.toChars());
4579         }
4580         auto cond = IntegerExp.createBool(false);
4581         auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
4582         msg.type = Type.tstring;
4583         auto ae = new AssertExp(loc, cond, msg);
4584         ae.type = mt;
4585         return ae;
4586     }
4587 
4588     switch (mt.ty)
4589     {
4590         case Tvector:   return visitVector  (mt.isTypeVector());
4591         case Tsarray:   return visitSArray  (mt.isTypeSArray());
4592         case Tfunction: return visitFunction(mt.isTypeFunction());
4593         case Tstruct:   return visitStruct  (mt.isTypeStruct());
4594         case Tenum:     return visitEnum    (mt.isTypeEnum());
4595         case Ttuple:    return visitTuple   (mt.isTypeTuple());
4596 
4597         case Tnull:     return new NullExp(Loc.initial, Type.tnull);
4598 
4599         case Terror:    return ErrorExp.get();
4600 
4601         case Tarray:
4602         case Taarray:
4603         case Tpointer:
4604         case Treference:
4605         case Tdelegate:
4606         case Tclass:    return new NullExp(loc, mt);
4607         case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn());
4608 
4609         default:        return mt.isTypeBasic() ?
4610                                 visitBasic(cast(TypeBasic)mt) :
4611                                 null;
4612     }
4613 }
4614 
4615 
4616 /**********************************************
4617  * Extract complex type from core.stdc.config
4618  * Params:
4619  *      loc = for error messages
4620  *      sc = context
4621  *      ty = a complex or imaginary type
4622  * Returns:
4623  *      Complex!float, Complex!double, Complex!real or null for error
4624  */
4625 
4626 Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
4627 {
4628     // singleton
4629     __gshared Type complex_float;
4630     __gshared Type complex_double;
4631     __gshared Type complex_real;
4632 
4633     Type* pt;
4634     Identifier id;
4635     switch (ty)
4636     {
4637         case Timaginary32:
4638         case Tcomplex32:   id = Id.c_complex_float;  pt = &complex_float;  break;
4639         case Timaginary64:
4640         case Tcomplex64:   id = Id.c_complex_double; pt = &complex_double; break;
4641         case Timaginary80:
4642         case Tcomplex80:   id = Id.c_complex_real;   pt = &complex_real;   break;
4643         default:
4644              return Type.terror;
4645     }
4646 
4647     if (*pt)
4648         return *pt;
4649     *pt = Type.terror;
4650 
4651     Module mConfig = Module.loadCoreStdcConfig();
4652     if (!mConfig)
4653     {
4654         error(loc, "`core.stdc.config` is required for complex numbers");
4655         return *pt;
4656     }
4657 
4658     Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports);
4659     if (!s)
4660     {
4661         error(loc, "`%s` not found in core.stdc.config", id.toChars());
4662         return *pt;
4663     }
4664     s = s.toAlias();
4665     if (auto t = s.getType())
4666     {
4667         if (auto ts = t.toBasetype().isTypeStruct())
4668         {
4669             *pt = ts;
4670             return ts;
4671         }
4672     }
4673     if (auto sd = s.isStructDeclaration())
4674     {
4675         *pt = sd.type;
4676         return sd.type;
4677     }
4678 
4679     error(loc, "`%s` must be an alias for a complex struct", s.toChars());
4680     return *pt;
4681 }
4682 
4683 /******************************* Private *****************************************/
4684 
4685 private:
4686 
4687 /* Helper function for `typeToExpression`. Contains common code
4688  * for TypeQualified derived classes.
4689  */
4690 Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
4691 {
4692     //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
4693     foreach (id; t.idents[i .. t.idents.length])
4694     {
4695         //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
4696 
4697         final switch (id.dyncast())
4698         {
4699             // ... '. ident'
4700             case DYNCAST.identifier:
4701                 e = new DotIdExp(e.loc, e, cast(Identifier)id);
4702                 break;
4703 
4704             // ... '. name!(tiargs)'
4705             case DYNCAST.dsymbol:
4706                 auto ti = (cast(Dsymbol)id).isTemplateInstance();
4707                 assert(ti);
4708                 e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
4709                 break;
4710 
4711             // ... '[type]'
4712             case DYNCAST.type:          // https://issues.dlang.org/show_bug.cgi?id=1215
4713                 e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
4714                 break;
4715 
4716             // ... '[expr]'
4717             case DYNCAST.expression:    // https://issues.dlang.org/show_bug.cgi?id=1215
4718                 e = new ArrayExp(t.loc, e, cast(Expression)id);
4719                 break;
4720 
4721             case DYNCAST.object:
4722             case DYNCAST.tuple:
4723             case DYNCAST.parameter:
4724             case DYNCAST.statement:
4725             case DYNCAST.condition:
4726             case DYNCAST.templateparameter:
4727             case DYNCAST.initializer:
4728                 assert(0);
4729         }
4730     }
4731     return e;
4732 }
4733 
4734 /**************************
4735  * This evaluates exp while setting length to be the number
4736  * of elements in the tuple t.
4737  */
4738 Expression semanticLength(Scope* sc, Type t, Expression exp)
4739 {
4740     if (auto tt = t.isTypeTuple())
4741     {
4742         ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
4743         sym.parent = sc.scopesym;
4744         sc = sc.push(sym);
4745         sc = sc.startCTFE();
4746         exp = exp.expressionSemantic(sc);
4747         exp = resolveProperties(sc, exp);
4748         sc = sc.endCTFE();
4749         sc.pop();
4750     }
4751     else
4752     {
4753         sc = sc.startCTFE();
4754         exp = exp.expressionSemantic(sc);
4755         exp = resolveProperties(sc, exp);
4756         sc = sc.endCTFE();
4757     }
4758     return exp;
4759 }
4760 
4761 Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
4762 {
4763     ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
4764     sym.parent = sc.scopesym;
4765 
4766     sc = sc.push(sym);
4767     sc = sc.startCTFE();
4768     exp = exp.expressionSemantic(sc);
4769     exp = resolveProperties(sc, exp);
4770     sc = sc.endCTFE();
4771     sc.pop();
4772 
4773     return exp;
4774 }
4775 
4776 /************************************
4777  * Transitively search a type for all function types.
4778  * If any function types with parameters are found that have parameter identifiers
4779  * or default arguments, remove those and create a new type stripped of those.
4780  * This is used to determine the "canonical" version of a type which is useful for
4781  * comparisons.
4782  * Params:
4783  *      t = type to scan
4784  * Returns:
4785  *      `t` if no parameter identifiers or default arguments found, otherwise a new type that is
4786  *      the same as t but with no parameter identifiers or default arguments.
4787  */
4788 Type stripDefaultArgs(Type t)
4789 {
4790     static Parameters* stripParams(Parameters* parameters)
4791     {
4792         static Parameter stripParameter(Parameter p)
4793         {
4794             Type t = stripDefaultArgs(p.type);
4795             return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
4796                 ? new Parameter(p.storageClass, t, null, null, null)
4797                 : null;
4798         }
4799 
4800         if (parameters)
4801         {
4802             foreach (i, p; *parameters)
4803             {
4804                 Parameter ps = stripParameter(p);
4805                 if (ps)
4806                 {
4807                     // Replace params with a copy we can modify
4808                     Parameters* nparams = new Parameters(parameters.length);
4809 
4810                     foreach (j, ref np; *nparams)
4811                     {
4812                         Parameter pj = (*parameters)[j];
4813                         if (j < i)
4814                             np = pj;
4815                         else if (j == i)
4816                             np = ps;
4817                         else
4818                         {
4819                             Parameter nps = stripParameter(pj);
4820                             np = nps ? nps : pj;
4821                         }
4822                     }
4823                     return nparams;
4824                 }
4825             }
4826         }
4827         return parameters;
4828     }
4829 
4830     if (t is null)
4831         return t;
4832 
4833     if (auto tf = t.isTypeFunction())
4834     {
4835         Type tret = stripDefaultArgs(tf.next);
4836         Parameters* params = stripParams(tf.parameterList.parameters);
4837         if (tret == tf.next && params == tf.parameterList.parameters)
4838             return t;
4839         TypeFunction tr = tf.copy().isTypeFunction();
4840         tr.parameterList.parameters = params;
4841         tr.next = tret;
4842         //printf("strip %s\n   <- %s\n", tr.toChars(), t.toChars());
4843         return tr;
4844     }
4845     else if (auto tt = t.isTypeTuple())
4846     {
4847         Parameters* args = stripParams(tt.arguments);
4848         if (args == tt.arguments)
4849             return t;
4850         TypeTuple tr = t.copy().isTypeTuple();
4851         tr.arguments = args;
4852         return tr;
4853     }
4854     else if (t.ty == Tenum)
4855     {
4856         // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
4857         return t;
4858     }
4859     else
4860     {
4861         Type tn = t.nextOf();
4862         Type n = stripDefaultArgs(tn);
4863         if (n == tn)
4864             return t;
4865         TypeNext tr = cast(TypeNext)t.copy();
4866         tr.next = n;
4867         return tr;
4868     }
4869 }
4870 
4871 /******************************
4872  * Get the value of the .max/.min property of `ed` as an Expression.
4873  * Lazily computes the value and caches it in maxval/minval.
4874  * Reports any errors.
4875  * Params:
4876  *      ed = the EnumDeclaration being examined
4877  *      loc = location to use for error messages
4878  *      id = Id::max or Id::min
4879  * Returns:
4880  *      corresponding value of .max/.min
4881  */
4882 Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
4883 {
4884     //printf("EnumDeclaration::getMaxValue()\n");
4885 
4886     static Expression pvalToResult(Expression e, const ref Loc loc)
4887     {
4888         if (e.op != EXP.error)
4889         {
4890             e = e.copy();
4891             e.loc = loc;
4892         }
4893         return e;
4894     }
4895 
4896     Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
4897 
4898     Expression errorReturn()
4899     {
4900         *pval = ErrorExp.get();
4901         return *pval;
4902     }
4903 
4904     if (ed.inuse)
4905     {
4906         ed.error(loc, "recursive definition of `.%s` property", id.toChars());
4907         return errorReturn();
4908     }
4909     if (*pval)
4910         return pvalToResult(*pval, loc);
4911 
4912     if (ed._scope)
4913         dsymbolSemantic(ed, ed._scope);
4914     if (ed.errors)
4915         return errorReturn();
4916     if (!ed.members)
4917     {
4918         ed.error(loc, "is opaque and has no `.%s`", id.toChars());
4919         return errorReturn();
4920     }
4921     if (!(ed.memtype && ed.memtype.isintegral()))
4922     {
4923         ed.error(loc, "has no `.%s` property because base type `%s` is not an integral type",
4924               id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
4925         return errorReturn();
4926     }
4927 
4928     bool first = true;
4929     for (size_t i = 0; i < ed.members.length; i++)
4930     {
4931         EnumMember em = (*ed.members)[i].isEnumMember();
4932         if (!em)
4933             continue;
4934         if (em.errors)
4935         {
4936             ed.errors = true;
4937             continue;
4938         }
4939 
4940         if (em.semanticRun < PASS.semanticdone)
4941         {
4942             em.error("is forward referenced looking for `.%s`", id.toChars());
4943             ed.errors = true;
4944             continue;
4945         }
4946 
4947         if (first)
4948         {
4949             *pval = em.value;
4950             first = false;
4951         }
4952         else
4953         {
4954             /* In order to work successfully with UDTs,
4955              * build expressions to do the comparisons,
4956              * and let the semantic analyzer and constant
4957              * folder give us the result.
4958              */
4959 
4960             /* Compute:
4961              *   if (e > maxval)
4962              *      maxval = e;
4963              */
4964             Expression e = em.value;
4965             Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
4966             ed.inuse = true;
4967             ec = ec.expressionSemantic(em._scope);
4968             ed.inuse = false;
4969             ec = ec.ctfeInterpret();
4970             if (ec.op == EXP.error)
4971             {
4972                 ed.errors = true;
4973                 continue;
4974             }
4975             if (ec.toInteger())
4976                 *pval = e;
4977         }
4978     }
4979     return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
4980 }
4981 
4982 /******************************************
4983  * Compile the MixinType, returning the type or expression AST.
4984  *
4985  * Doesn't run semantic() on the returned object.
4986  * Params:
4987  *      tm = mixin to compile as a type or expression
4988  *      loc = location for error messages
4989  *      sc = context
4990  * Return:
4991  *      null if error, else RootObject AST as parsed
4992  */
4993 RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
4994 {
4995     OutBuffer buf;
4996     if (expressionsToString(buf, sc, tm.exps))
4997         return null;
4998 
4999     const errors = global.errors;
5000     const len = buf.length;
5001     buf.writeByte(0);
5002     const str = buf.extractSlice()[0 .. len];
5003     const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
5004     auto locm = adjustLocForMixin(str, loc, global.params.mixinOut);
5005     scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
5006     p.transitionIn = global.params.vin;
5007     p.nextToken();
5008     //printf("p.loc.linnum = %d\n", p.loc.linnum);
5009 
5010     auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
5011     if (errors != global.errors)
5012     {
5013         assert(global.errors != errors); // should have caught all these cases
5014         return null;
5015     }
5016     if (p.token.value != TOK.endOfFile)
5017     {
5018         .error(loc, "incomplete mixin type `%s`", str.ptr);
5019         return null;
5020     }
5021 
5022     return o;
5023 }