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