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