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