1 /**
2  * Defines the bulk of the classes which represent the AST at the expression level.
3  *
4  * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5  *
6  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d)
10  * Documentation:  https://dlang.org/phobos/dmd_expression.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d
12  */
13 
14 module dmd.expression;
15 
16 import core.stdc.stdarg;
17 import core.stdc.stdio;
18 import core.stdc.string;
19 
20 import dmd.aggregate;
21 import dmd.aliasthis;
22 import dmd.apply;
23 import dmd.arrayop;
24 import dmd.arraytypes;
25 import dmd.ast_node;
26 import dmd.gluelayer;
27 import dmd.canthrow;
28 import dmd.complex;
29 import dmd.constfold;
30 import dmd.ctfeexpr;
31 import dmd.ctorflow;
32 import dmd.dcast;
33 import dmd.dclass;
34 import dmd.declaration;
35 import dmd.delegatize;
36 import dmd.dimport;
37 import dmd.dinterpret;
38 import dmd.dmodule;
39 import dmd.dscope;
40 import dmd.dstruct;
41 import dmd.dsymbol;
42 import dmd.dsymbolsem;
43 import dmd.dtemplate;
44 import dmd.errors;
45 import dmd.escape;
46 import dmd.expressionsem;
47 import dmd.func;
48 import dmd.globals;
49 import dmd.hdrgen;
50 import dmd.id;
51 import dmd.identifier;
52 import dmd.inline;
53 import dmd.mtype;
54 import dmd.nspace;
55 import dmd.objc;
56 import dmd.opover;
57 import dmd.optimize;
58 import dmd.root.ctfloat;
59 import dmd.root.filename;
60 import dmd.root.outbuffer;
61 import dmd.root.rmem;
62 import dmd.root.rootobject;
63 import dmd.root.string;
64 import dmd.safe;
65 import dmd.sideeffect;
66 import dmd.target;
67 import dmd.tokens;
68 import dmd.typesem;
69 import dmd.utf;
70 import dmd.visitor;
71 
72 enum LOGSEMANTIC = false;
73 void emplaceExp(T : Expression, Args...)(void* p, Args args)
74 {
75     scope tmp = new T(args);
76     memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T));
77 }
78 
79 void emplaceExp(T : UnionExp)(T* p, Expression e)
80 {
81     memcpy(p, cast(void*)e, e.size);
82 }
83 
84 // Return value for `checkModifiable`
85 enum Modifiable
86 {
87     /// Not modifiable
88     no,
89     /// Modifiable (the type is mutable)
90     yes,
91     /// Modifiable because it is initialization
92     initialization,
93 }
94 
95 /****************************************
96  * Find the first non-comma expression.
97  * Params:
98  *      e = Expressions connected by commas
99  * Returns:
100  *      left-most non-comma expression
101  */
102 inout(Expression) firstComma(inout Expression e)
103 {
104     Expression ex = cast()e;
105     while (ex.op == TOK.comma)
106         ex = (cast(CommaExp)ex).e1;
107     return cast(inout)ex;
108 
109 }
110 
111 /****************************************
112  * Find the last non-comma expression.
113  * Params:
114  *      e = Expressions connected by commas
115  * Returns:
116  *      right-most non-comma expression
117  */
118 
119 inout(Expression) lastComma(inout Expression e)
120 {
121     Expression ex = cast()e;
122     while (ex.op == TOK.comma)
123         ex = (cast(CommaExp)ex).e2;
124     return cast(inout)ex;
125 
126 }
127 
128 /*****************************************
129  * Determine if `this` is available by walking up the enclosing
130  * scopes until a function is found.
131  *
132  * Params:
133  *      sc = where to start looking for the enclosing function
134  * Returns:
135  *      Found function if it satisfies `isThis()`, otherwise `null`
136  */
137 FuncDeclaration hasThis(Scope* sc)
138 {
139     //printf("hasThis()\n");
140     Dsymbol p = sc.parent;
141     while (p && p.isTemplateMixin())
142         p = p.parent;
143     FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
144     //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
145 
146     // Go upwards until we find the enclosing member function
147     FuncDeclaration fd = fdthis;
148     while (1)
149     {
150         if (!fd)
151         {
152             return null;
153         }
154         if (!fd.isNested() || fd.isThis() || (fd.isThis2 && fd.isMember2()))
155             break;
156 
157         Dsymbol parent = fd.parent;
158         while (1)
159         {
160             if (!parent)
161                 return null;
162             TemplateInstance ti = parent.isTemplateInstance();
163             if (ti)
164                 parent = ti.parent;
165             else
166                 break;
167         }
168         fd = parent.isFuncDeclaration();
169     }
170 
171     if (!fd.isThis() && !(fd.isThis2 && fd.isMember2()))
172     {
173         return null;
174     }
175 
176     assert(fd.vthis);
177     return fd;
178 
179 }
180 
181 /***********************************
182  * Determine if a `this` is needed to access `d`.
183  * Params:
184  *      sc = context
185  *      d = declaration to check
186  * Returns:
187  *      true means a `this` is needed
188  */
189 bool isNeedThisScope(Scope* sc, Declaration d)
190 {
191     if (sc.intypeof == 1)
192         return false;
193 
194     AggregateDeclaration ad = d.isThis();
195     if (!ad)
196         return false;
197     //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
198 
199     for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
200     {
201         //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
202         if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
203         {
204             if (ad2 == ad)
205                 return false;
206             else if (ad2.isNested())
207                 continue;
208             else
209                 return true;
210         }
211         if (FuncDeclaration f = s.isFuncDeclaration())
212         {
213             if (f.isMemberLocal())
214                 break;
215         }
216     }
217     return true;
218 }
219 
220 /******************************
221  * check e is exp.opDispatch!(tiargs) or not
222  * It's used to switch to UFCS the semantic analysis path
223  */
224 bool isDotOpDispatch(Expression e)
225 {
226     if (auto dtie = e.isDotTemplateInstanceExp())
227         return dtie.ti.name == Id.opDispatch;
228     return false;
229 }
230 
231 /****************************************
232  * Expand tuples.
233  * Input:
234  *      exps    aray of Expressions
235  * Output:
236  *      exps    rewritten in place
237  */
238 extern (C++) void expandTuples(Expressions* exps)
239 {
240     //printf("expandTuples()\n");
241     if (exps is null)
242         return;
243 
244     for (size_t i = 0; i < exps.dim; i++)
245     {
246         Expression arg = (*exps)[i];
247         if (!arg)
248             continue;
249 
250         // Look for tuple with 0 members
251         if (auto e = arg.isTypeExp())
252         {
253             if (auto tt = e.type.toBasetype().isTypeTuple())
254             {
255                 if (!tt.arguments || tt.arguments.dim == 0)
256                 {
257                     exps.remove(i);
258                     if (i == exps.dim)
259                         return;
260                     i--;
261                     continue;
262                 }
263             }
264         }
265 
266         // Inline expand all the tuples
267         while (arg.op == TOK.tuple)
268         {
269             TupleExp te = cast(TupleExp)arg;
270             exps.remove(i); // remove arg
271             exps.insert(i, te.exps); // replace with tuple contents
272             if (i == exps.dim)
273                 return; // empty tuple, no more arguments
274             (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
275             arg = (*exps)[i];
276         }
277     }
278 }
279 
280 /****************************************
281  * Expand alias this tuples.
282  */
283 TupleDeclaration isAliasThisTuple(Expression e)
284 {
285     if (!e.type)
286         return null;
287 
288     Type t = e.type.toBasetype();
289     while (true)
290     {
291         if (Dsymbol s = t.toDsymbol(null))
292         {
293             if (auto ad = s.isAggregateDeclaration())
294             {
295                 s = ad.aliasthis ? ad.aliasthis.sym : null;
296                 if (s && s.isVarDeclaration())
297                 {
298                     TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
299                     if (td && td.isexp)
300                         return td;
301                 }
302                 if (Type att = t.aliasthisOf())
303                 {
304                     t = att;
305                     continue;
306                 }
307             }
308         }
309         return null;
310     }
311 }
312 
313 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
314 {
315     if (!exps || exps.dim == 0)
316         return -1;
317 
318     for (size_t u = starti; u < exps.dim; u++)
319     {
320         Expression exp = (*exps)[u];
321         if (TupleDeclaration td = exp.isAliasThisTuple)
322         {
323             exps.remove(u);
324             foreach (i, o; *td.objects)
325             {
326                 auto d = o.isExpression().isDsymbolExp().s.isDeclaration();
327                 auto e = new DotVarExp(exp.loc, exp, d);
328                 assert(d.type);
329                 e.type = d.type;
330                 exps.insert(u + i, e);
331             }
332             version (none)
333             {
334                 printf("expansion ->\n");
335                 foreach (e; exps)
336                 {
337                     printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars());
338                 }
339             }
340             return cast(int)u;
341         }
342     }
343     return -1;
344 }
345 
346 /****************************************
347  * If `s` is a function template, i.e. the only member of a template
348  * and that member is a function, return that template.
349  * Params:
350  *      s = symbol that might be a function template
351  * Returns:
352  *      template for that function, otherwise null
353  */
354 TemplateDeclaration getFuncTemplateDecl(Dsymbol s)
355 {
356     FuncDeclaration f = s.isFuncDeclaration();
357     if (f && f.parent)
358     {
359         if (auto ti = f.parent.isTemplateInstance())
360         {
361             if (!ti.isTemplateMixin() && ti.tempdecl)
362             {
363                 auto td = ti.tempdecl.isTemplateDeclaration();
364                 if (td.onemember && td.ident == f.ident)
365                 {
366                     return td;
367                 }
368             }
369         }
370     }
371     return null;
372 }
373 
374 /************************************************
375  * If we want the value of this expression, but do not want to call
376  * the destructor on it.
377  */
378 Expression valueNoDtor(Expression e)
379 {
380     auto ex = lastComma(e);
381 
382     if (auto ce = ex.isCallExp())
383     {
384         /* The struct value returned from the function is transferred
385          * so do not call the destructor on it.
386          * Recognize:
387          *       ((S _ctmp = S.init), _ctmp).this(...)
388          * and make sure the destructor is not called on _ctmp
389          * BUG: if ex is a CommaExp, we should go down the right side.
390          */
391         if (auto dve = ce.e1.isDotVarExp())
392         {
393             if (dve.var.isCtorDeclaration())
394             {
395                 // It's a constructor call
396                 if (auto comma = dve.e1.isCommaExp())
397                 {
398                     if (auto ve = comma.e2.isVarExp())
399                     {
400                         VarDeclaration ctmp = ve.var.isVarDeclaration();
401                         if (ctmp)
402                         {
403                             ctmp.storage_class |= STC.nodtor;
404                             assert(!ce.isLvalue());
405                         }
406                     }
407                 }
408             }
409         }
410     }
411     else if (auto ve = ex.isVarExp())
412     {
413         auto vtmp = ve.var.isVarDeclaration();
414         if (vtmp && (vtmp.storage_class & STC.rvalue))
415         {
416             vtmp.storage_class |= STC.nodtor;
417         }
418     }
419     return e;
420 }
421 
422 /*********************************************
423  * If e is an instance of a struct, and that struct has a copy constructor,
424  * rewrite e as:
425  *    (tmp = e),tmp
426  * Input:
427  *      sc = just used to specify the scope of created temporary variable
428  *      destinationType = the type of the object on which the copy constructor is called;
429  *                        may be null if the struct defines a postblit
430  */
431 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
432 {
433     if (auto ts = e.type.baseElemOf().isTypeStruct())
434     {
435         StructDeclaration sd = ts.sym;
436         if (sd.postblit || sd.hasCopyCtor)
437         {
438             /* Create a variable tmp, and replace the argument e with:
439              *      (tmp = e),tmp
440              * and let AssignExp() handle the construction.
441              * This is not the most efficient, ideally tmp would be constructed
442              * directly onto the stack.
443              */
444             auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
445             if (sd.hasCopyCtor && destinationType)
446                 tmp.type = destinationType;
447             tmp.storage_class |= STC.nodtor;
448             tmp.dsymbolSemantic(sc);
449             Expression de = new DeclarationExp(e.loc, tmp);
450             Expression ve = new VarExp(e.loc, tmp);
451             de.type = Type.tvoid;
452             ve.type = e.type;
453             return Expression.combine(de, ve);
454         }
455     }
456     return e;
457 }
458 
459 /************************************************
460  * Handle the postblit call on lvalue, or the move of rvalue.
461  *
462  * Params:
463  *   sc = the scope where the expression is encountered
464  *   e = the expression the needs to be moved or copied (source)
465  *   t = if the struct defines a copy constructor, the type of the destination
466  *
467  * Returns:
468  *  The expression that copy constructs or moves the value.
469  */
470 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
471 {
472     if (auto ce = e.isCondExp())
473     {
474         ce.e1 = doCopyOrMove(sc, ce.e1);
475         ce.e2 = doCopyOrMove(sc, ce.e2);
476     }
477     else
478     {
479         e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
480     }
481     return e;
482 }
483 
484 /****************************************************************/
485 /* A type meant as a union of all the Expression types,
486  * to serve essentially as a Variant that will sit on the stack
487  * during CTFE to reduce memory consumption.
488  */
489 extern (C++) struct UnionExp
490 {
491     // yes, default constructor does nothing
492     extern (D) this(Expression e)
493     {
494         memcpy(&this, cast(void*)e, e.size);
495     }
496 
497     /* Extract pointer to Expression
498      */
499     extern (C++) Expression exp() return
500     {
501         return cast(Expression)&u;
502     }
503 
504     /* Convert to an allocated Expression
505      */
506     extern (C++) Expression copy()
507     {
508         Expression e = exp();
509         //if (e.size > sizeof(u)) printf("%s\n", Token::toChars(e.op));
510         assert(e.size <= u.sizeof);
511         switch (e.op)
512         {
513             case TOK.cantExpression:    return CTFEExp.cantexp;
514             case TOK.voidExpression:    return CTFEExp.voidexp;
515             case TOK.break_:            return CTFEExp.breakexp;
516             case TOK.continue_:         return CTFEExp.continueexp;
517             case TOK.goto_:             return CTFEExp.gotoexp;
518             default:                    return e.copy();
519         }
520     }
521 
522 private:
523     // Ensure that the union is suitably aligned.
524     align(8) union __AnonStruct__u
525     {
526         char[__traits(classInstanceSize, Expression)] exp;
527         char[__traits(classInstanceSize, IntegerExp)] integerexp;
528         char[__traits(classInstanceSize, ErrorExp)] errorexp;
529         char[__traits(classInstanceSize, RealExp)] realexp;
530         char[__traits(classInstanceSize, ComplexExp)] complexexp;
531         char[__traits(classInstanceSize, SymOffExp)] symoffexp;
532         char[__traits(classInstanceSize, StringExp)] stringexp;
533         char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
534         char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
535         char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
536         char[__traits(classInstanceSize, NullExp)] nullexp;
537         char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
538         char[__traits(classInstanceSize, AddrExp)] addrexp;
539         char[__traits(classInstanceSize, IndexExp)] indexexp;
540         char[__traits(classInstanceSize, SliceExp)] sliceexp;
541         char[__traits(classInstanceSize, VectorExp)] vectorexp;
542     }
543 
544     __AnonStruct__u u;
545 }
546 
547 /********************************
548  * Test to see if two reals are the same.
549  * Regard NaN's as equivalent.
550  * Regard +0 and -0 as different.
551  * Params:
552  *      x1 = first operand
553  *      x2 = second operand
554  * Returns:
555  *      true if x1 is x2
556  *      else false
557  */
558 bool RealIdentical(real_t x1, real_t x2)
559 {
560     return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
561 }
562 
563 /************************ TypeDotIdExp ************************************/
564 /* Things like:
565  *      int.size
566  *      foo.size
567  *      (foo).size
568  *      cast(foo).size
569  */
570 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident)
571 {
572     return new DotIdExp(loc, new TypeExp(loc, type), ident);
573 }
574 
575 /***************************************************
576  * Given an Expression, find the variable it really is.
577  *
578  * For example, `a[index]` is really `a`, and `s.f` is really `s`.
579  * Params:
580  *      e = Expression to look at
581  * Returns:
582  *      variable if there is one, null if not
583  */
584 VarDeclaration expToVariable(Expression e)
585 {
586     while (1)
587     {
588         switch (e.op)
589         {
590             case TOK.variable:
591                 return (cast(VarExp)e).var.isVarDeclaration();
592 
593             case TOK.dotVariable:
594                 e = (cast(DotVarExp)e).e1;
595                 continue;
596 
597             case TOK.index:
598             {
599                 IndexExp ei = cast(IndexExp)e;
600                 e = ei.e1;
601                 Type ti = e.type.toBasetype();
602                 if (ti.ty == Tsarray)
603                     continue;
604                 return null;
605             }
606 
607             case TOK.slice:
608             {
609                 SliceExp ei = cast(SliceExp)e;
610                 e = ei.e1;
611                 Type ti = e.type.toBasetype();
612                 if (ti.ty == Tsarray)
613                     continue;
614                 return null;
615             }
616 
617             case TOK.this_:
618             case TOK.super_:
619                 return (cast(ThisExp)e).var.isVarDeclaration();
620 
621             default:
622                 return null;
623         }
624     }
625 }
626 
627 enum OwnedBy : ubyte
628 {
629     code,          // normal code expression in AST
630     ctfe,          // value expression for CTFE
631     cache,         // constant value cached for CTFE
632 }
633 
634 enum WANTvalue  = 0;    // default
635 enum WANTexpand = 1;    // expand const/immutable variables if possible
636 
637 /***********************************************************
638  * http://dlang.org/spec/expression.html#expression
639  */
640 extern (C++) abstract class Expression : ASTNode
641 {
642     const TOK op;   // to minimize use of dynamic_cast
643     ubyte size;     // # of bytes in Expression so we can copy() it
644     ubyte parens;   // if this is a parenthesized expression
645     Type type;      // !=null means that semantic() has been run
646     Loc loc;        // file location
647 
648     extern (D) this(const ref Loc loc, TOK op, int size)
649     {
650         //printf("Expression::Expression(op = %d) this = %p\n", op, this);
651         this.loc = loc;
652         this.op = op;
653         this.size = cast(ubyte)size;
654     }
655 
656     static void _init()
657     {
658         CTFEExp.cantexp = new CTFEExp(TOK.cantExpression);
659         CTFEExp.voidexp = new CTFEExp(TOK.voidExpression);
660         CTFEExp.breakexp = new CTFEExp(TOK.break_);
661         CTFEExp.continueexp = new CTFEExp(TOK.continue_);
662         CTFEExp.gotoexp = new CTFEExp(TOK.goto_);
663         CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
664     }
665 
666     /**
667      * Deinitializes the global state of the compiler.
668      *
669      * This can be used to restore the state set by `_init` to its original
670      * state.
671      */
672     static void deinitialize()
673     {
674         CTFEExp.cantexp = CTFEExp.cantexp.init;
675         CTFEExp.voidexp = CTFEExp.voidexp.init;
676         CTFEExp.breakexp = CTFEExp.breakexp.init;
677         CTFEExp.continueexp = CTFEExp.continueexp.init;
678         CTFEExp.gotoexp = CTFEExp.gotoexp.init;
679         CTFEExp.showcontext = CTFEExp.showcontext.init;
680     }
681 
682     /*********************************
683      * Does *not* do a deep copy.
684      */
685     final Expression copy()
686     {
687         Expression e;
688         if (!size)
689         {
690             debug
691             {
692                 fprintf(stderr, "No expression copy for: %s\n", toChars());
693                 printf("op = %d\n", op);
694             }
695             assert(0);
696         }
697 
698         // memory never freed, so can use the faster bump-pointer-allocation
699         e = cast(Expression)_d_allocmemory(size);
700         //printf("Expression::copy(op = %d) e = %p\n", op, e);
701         return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
702     }
703 
704     Expression syntaxCopy()
705     {
706         //printf("Expression::syntaxCopy()\n");
707         //print();
708         return copy();
709     }
710 
711     // kludge for template.isExpression()
712     override final DYNCAST dyncast() const
713     {
714         return DYNCAST.expression;
715     }
716 
717     override const(char)* toChars() const
718     {
719         OutBuffer buf;
720         HdrGenState hgs;
721         toCBuffer(this, &buf, &hgs);
722         return buf.extractChars();
723     }
724 
725     final void error(const(char)* format, ...) const
726     {
727         if (type != Type.terror)
728         {
729             va_list ap;
730             va_start(ap, format);
731             .verror(loc, format, ap);
732             va_end(ap);
733         }
734     }
735 
736     final void errorSupplemental(const(char)* format, ...)
737     {
738         if (type == Type.terror)
739             return;
740 
741         va_list ap;
742         va_start(ap, format);
743         .verrorSupplemental(loc, format, ap);
744         va_end(ap);
745     }
746 
747     final void warning(const(char)* format, ...) const
748     {
749         if (type != Type.terror)
750         {
751             va_list ap;
752             va_start(ap, format);
753             .vwarning(loc, format, ap);
754             va_end(ap);
755         }
756     }
757 
758     final void deprecation(const(char)* format, ...) const
759     {
760         if (type != Type.terror)
761         {
762             va_list ap;
763             va_start(ap, format);
764             .vdeprecation(loc, format, ap);
765             va_end(ap);
766         }
767     }
768 
769     /**********************************
770      * Combine e1 and e2 by CommaExp if both are not NULL.
771      */
772     extern (D) static Expression combine(Expression e1, Expression e2)
773     {
774         if (e1)
775         {
776             if (e2)
777             {
778                 e1 = new CommaExp(e1.loc, e1, e2);
779                 e1.type = e2.type;
780             }
781         }
782         else
783             e1 = e2;
784         return e1;
785     }
786 
787     extern (D) static Expression combine(Expression e1, Expression e2, Expression e3)
788     {
789         return combine(combine(e1, e2), e3);
790     }
791 
792     extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4)
793     {
794         return combine(combine(e1, e2), combine(e3, e4));
795     }
796 
797     /**********************************
798      * If 'e' is a tree of commas, returns the rightmost expression
799      * by stripping off it from the tree. The remained part of the tree
800      * is returned via e0.
801      * Otherwise 'e' is directly returned and e0 is set to NULL.
802      */
803     extern (D) static Expression extractLast(Expression e, out Expression e0)
804     {
805         if (e.op != TOK.comma)
806         {
807             return e;
808         }
809 
810         CommaExp ce = cast(CommaExp)e;
811         if (ce.e2.op != TOK.comma)
812         {
813             e0 = ce.e1;
814             return ce.e2;
815         }
816         else
817         {
818             e0 = e;
819 
820             Expression* pce = &ce.e2;
821             while ((cast(CommaExp)(*pce)).e2.op == TOK.comma)
822             {
823                 pce = &(cast(CommaExp)(*pce)).e2;
824             }
825             assert((*pce).op == TOK.comma);
826             ce = cast(CommaExp)(*pce);
827             *pce = ce.e1;
828 
829             return ce.e2;
830         }
831     }
832 
833     extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
834     {
835         Expressions* a = null;
836         if (exps)
837         {
838             a = new Expressions(exps.dim);
839             foreach (i, e; *exps)
840             {
841                 (*a)[i] = e ? e.syntaxCopy() : null;
842             }
843         }
844         return a;
845     }
846 
847     dinteger_t toInteger()
848     {
849         //printf("Expression %s\n", Token::toChars(op));
850         error("integer constant expression expected instead of `%s`", toChars());
851         return 0;
852     }
853 
854     uinteger_t toUInteger()
855     {
856         //printf("Expression %s\n", Token::toChars(op));
857         return cast(uinteger_t)toInteger();
858     }
859 
860     real_t toReal()
861     {
862         error("floating point constant expression expected instead of `%s`", toChars());
863         return CTFloat.zero;
864     }
865 
866     real_t toImaginary()
867     {
868         error("floating point constant expression expected instead of `%s`", toChars());
869         return CTFloat.zero;
870     }
871 
872     complex_t toComplex()
873     {
874         error("floating point constant expression expected instead of `%s`", toChars());
875         return complex_t(CTFloat.zero);
876     }
877 
878     StringExp toStringExp()
879     {
880         return null;
881     }
882 
883     TupleExp toTupleExp()
884     {
885         return null;
886     }
887 
888     /***************************************
889      * Return !=0 if expression is an lvalue.
890      */
891     bool isLvalue()
892     {
893         return false;
894     }
895 
896     /*******************************
897      * Give error if we're not an lvalue.
898      * If we can, convert expression to be an lvalue.
899      */
900     Expression toLvalue(Scope* sc, Expression e)
901     {
902         if (!e)
903             e = this;
904         else if (!loc.isValid())
905             loc = e.loc;
906 
907         if (e.op == TOK.type)
908             error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
909         else
910             error("`%s` is not an lvalue and cannot be modified", e.toChars());
911 
912         return new ErrorExp();
913     }
914 
915     Expression modifiableLvalue(Scope* sc, Expression e)
916     {
917         //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars());
918         // See if this expression is a modifiable lvalue (i.e. not const)
919         if (checkModifiable(sc) == Modifiable.yes)
920         {
921             assert(type);
922             if (!type.isMutable())
923             {
924                 if (auto dve = this.isDotVarExp())
925                 {
926                     if (isNeedThisScope(sc, dve.var))
927                         for (Dsymbol s = sc.func; s; s = s.toParentLocal())
928                     {
929                         FuncDeclaration ff = s.isFuncDeclaration();
930                         if (!ff)
931                             break;
932                         if (!ff.type.isMutable)
933                         {
934                             error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod));
935                             return new ErrorExp();
936                         }
937                     }
938                 }
939                 error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars());
940                 return new ErrorExp();
941             }
942             else if (!type.isAssignable())
943             {
944                 error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
945                     toChars(), type.toChars());
946                 return new ErrorExp();
947             }
948         }
949         return toLvalue(sc, e);
950     }
951 
952     final Expression implicitCastTo(Scope* sc, Type t)
953     {
954         return .implicitCastTo(this, sc, t);
955     }
956 
957     final MATCH implicitConvTo(Type t)
958     {
959         return .implicitConvTo(this, t);
960     }
961 
962     final Expression castTo(Scope* sc, Type t)
963     {
964         return .castTo(this, sc, t);
965     }
966 
967     /****************************************
968      * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
969      */
970     Expression resolveLoc(const ref Loc loc, Scope* sc)
971     {
972         this.loc = loc;
973         return this;
974     }
975 
976     /****************************************
977      * Check that the expression has a valid type.
978      * If not, generates an error "... has no type".
979      * Returns:
980      *      true if the expression is not valid.
981      * Note:
982      *      When this function returns true, `checkValue()` should also return true.
983      */
984     bool checkType()
985     {
986         return false;
987     }
988 
989     /****************************************
990      * Check that the expression has a valid value.
991      * If not, generates an error "... has no value".
992      * Returns:
993      *      true if the expression is not valid or has void type.
994      */
995     bool checkValue()
996     {
997         if (type && type.toBasetype().ty == Tvoid)
998         {
999             error("expression `%s` is `void` and has no value", toChars());
1000             //print(); assert(0);
1001             if (!global.gag)
1002                 type = Type.terror;
1003             return true;
1004         }
1005         return false;
1006     }
1007 
1008     extern (D) final bool checkScalar()
1009     {
1010         if (op == TOK.error)
1011             return true;
1012         if (type.toBasetype().ty == Terror)
1013             return true;
1014         if (!type.isscalar())
1015         {
1016             error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
1017             return true;
1018         }
1019         return checkValue();
1020     }
1021 
1022     extern (D) final bool checkNoBool()
1023     {
1024         if (op == TOK.error)
1025             return true;
1026         if (type.toBasetype().ty == Terror)
1027             return true;
1028         if (type.toBasetype().ty == Tbool)
1029         {
1030             error("operation not allowed on `bool` `%s`", toChars());
1031             return true;
1032         }
1033         return false;
1034     }
1035 
1036     extern (D) final bool checkIntegral()
1037     {
1038         if (op == TOK.error)
1039             return true;
1040         if (type.toBasetype().ty == Terror)
1041             return true;
1042         if (!type.isintegral())
1043         {
1044             error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
1045             return true;
1046         }
1047         return checkValue();
1048     }
1049 
1050     extern (D) final bool checkArithmetic()
1051     {
1052         if (op == TOK.error)
1053             return true;
1054         if (type.toBasetype().ty == Terror)
1055             return true;
1056         if (!type.isintegral() && !type.isfloating())
1057         {
1058             error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars());
1059             return true;
1060         }
1061         return checkValue();
1062     }
1063 
1064     final bool checkDeprecated(Scope* sc, Dsymbol s)
1065     {
1066         return s.checkDeprecated(loc, sc);
1067     }
1068 
1069     extern (D) final bool checkDisabled(Scope* sc, Dsymbol s)
1070     {
1071         if (auto d = s.isDeclaration())
1072         {
1073             return d.checkDisabled(loc, sc);
1074         }
1075 
1076         return false;
1077     }
1078 
1079     /*********************************************
1080      * Calling function f.
1081      * Check the purity, i.e. if we're in a pure function
1082      * we can only call other pure functions.
1083      * Returns true if error occurs.
1084      */
1085     extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f)
1086     {
1087         if (!sc.func)
1088             return false;
1089         if (sc.func == f)
1090             return false;
1091         if (sc.intypeof == 1)
1092             return false;
1093         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1094             return false;
1095 
1096         // If the call has a pure parent, then the called func must be pure.
1097         if (!f.isPure() && checkImpure(sc))
1098         {
1099             error("`pure` %s `%s` cannot call impure %s `%s`",
1100                 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1101                 f.toPrettyChars());
1102             return true;
1103         }
1104         return false;
1105     }
1106 
1107     /*******************************************
1108      * Accessing variable v.
1109      * Check for purity and safety violations.
1110      * Returns true if error occurs.
1111      */
1112     extern (D) final bool checkPurity(Scope* sc, VarDeclaration v)
1113     {
1114         //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1115         /* Look for purity and safety violations when accessing variable v
1116          * from current function.
1117          */
1118         if (!sc.func)
1119             return false;
1120         if (sc.intypeof == 1)
1121             return false; // allow violations inside typeof(expression)
1122         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1123             return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1124         if (v.ident == Id.ctfe)
1125             return false; // magic variable never violates pure and safe
1126         if (v.isImmutable())
1127             return false; // always safe and pure to access immutables...
1128         if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
1129             return false; // or const global/parameter values which have no mutable indirections
1130         if (v.storage_class & STC.manifest)
1131             return false; // ...or manifest constants
1132 
1133         if (v.type.ty == Tstruct)
1134         {
1135             StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1136             if (sd.hasNoFields)
1137                 return false;
1138         }
1139 
1140         bool err = false;
1141         if (v.isDataseg())
1142         {
1143             // https://issues.dlang.org/show_bug.cgi?id=7533
1144             // Accessing implicit generated __gate is pure.
1145             if (v.ident == Id.gate)
1146                 return false;
1147 
1148             if (checkImpure(sc))
1149             {
1150                 error("`pure` %s `%s` cannot access mutable static data `%s`",
1151                     sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
1152                 err = true;
1153             }
1154         }
1155         else
1156         {
1157             /* Given:
1158              * void f() {
1159              *   int fx;
1160              *   pure void g() {
1161              *     int gx;
1162              *     /+pure+/ void h() {
1163              *       int hx;
1164              *       /+pure+/ void i() { }
1165              *     }
1166              *   }
1167              * }
1168              * i() can modify hx and gx but not fx
1169              */
1170 
1171             Dsymbol vparent = v.toParent2();
1172             for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
1173             {
1174                 if (s == vparent)
1175                     break;
1176 
1177                 if (AggregateDeclaration ad = s.isAggregateDeclaration())
1178                 {
1179                     if (ad.isNested())
1180                         continue;
1181                     break;
1182                 }
1183                 FuncDeclaration ff = s.isFuncDeclaration();
1184                 if (!ff)
1185                     break;
1186                 if (ff.isNested() || ff.isThis())
1187                 {
1188                     if (ff.type.isImmutable() ||
1189                         ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
1190                     {
1191                         OutBuffer ffbuf;
1192                         OutBuffer vbuf;
1193                         MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
1194                         MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
1195                         error("%s%s `%s` cannot access %sdata `%s`",
1196                             ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
1197                         err = true;
1198                         break;
1199                     }
1200                     continue;
1201                 }
1202                 break;
1203             }
1204         }
1205 
1206         /* Do not allow safe functions to access __gshared data
1207          */
1208         if (v.storage_class & STC.gshared)
1209         {
1210             if (sc.func.setUnsafe())
1211             {
1212                 error("`@safe` %s `%s` cannot access `__gshared` data `%s`",
1213                     sc.func.kind(), sc.func.toChars(), v.toChars());
1214                 err = true;
1215             }
1216         }
1217 
1218         return err;
1219     }
1220 
1221     /*
1222     Check if sc.func is impure or can be made impure.
1223     Returns true on error, i.e. if sc.func is pure and cannot be made impure.
1224     */
1225     private static bool checkImpure(Scope* sc)
1226     {
1227         return sc.func && (sc.flags & SCOPE.compile
1228                 ? sc.func.isPureBypassingInference() >= PURE.weak
1229                 : sc.func.setImpure());
1230     }
1231 
1232     /*********************************************
1233      * Calling function f.
1234      * Check the safety, i.e. if we're in a @safe function
1235      * we can only call @safe or @trusted functions.
1236      * Returns true if error occurs.
1237      */
1238     extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f)
1239     {
1240         if (!sc.func)
1241             return false;
1242         if (sc.func == f)
1243             return false;
1244         if (sc.intypeof == 1)
1245             return false;
1246         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1247             return false;
1248 
1249         if (!f.isSafe() && !f.isTrusted())
1250         {
1251             if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe())
1252             {
1253                 if (!loc.isValid()) // e.g. implicitly generated dtor
1254                     loc = sc.func.loc;
1255 
1256                 const prettyChars = f.toPrettyChars();
1257                 error("`@safe` %s `%s` cannot call `@system` %s `%s`",
1258                     sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1259                     prettyChars);
1260                 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
1261                 return true;
1262             }
1263         }
1264         return false;
1265     }
1266 
1267     /*********************************************
1268      * Calling function f.
1269      * Check the @nogc-ness, i.e. if we're in a @nogc function
1270      * we can only call other @nogc functions.
1271      * Returns true if error occurs.
1272      */
1273     extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f)
1274     {
1275         if (!sc.func)
1276             return false;
1277         if (sc.func == f)
1278             return false;
1279         if (sc.intypeof == 1)
1280             return false;
1281         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1282             return false;
1283 
1284         if (!f.isNogc())
1285         {
1286             if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC())
1287             {
1288                 if (loc.linnum == 0) // e.g. implicitly generated dtor
1289                     loc = sc.func.loc;
1290 
1291                 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
1292                 // so don't print anything to avoid double error messages.
1293                 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT))
1294                     error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
1295                         sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
1296                 return true;
1297             }
1298         }
1299         return false;
1300     }
1301 
1302     /********************************************
1303      * Check that the postblit is callable if t is an array of structs.
1304      * Returns true if error happens.
1305      */
1306     extern (D) final bool checkPostblit(Scope* sc, Type t)
1307     {
1308         if (auto ts = t.baseElemOf().isTypeStruct())
1309         {
1310             if (global.params.useTypeInfo)
1311             {
1312                 // https://issues.dlang.org/show_bug.cgi?id=11395
1313                 // Require TypeInfo generation for array concatenation
1314                 semanticTypeInfo(sc, t);
1315             }
1316 
1317             StructDeclaration sd = ts.sym;
1318             if (sd.postblit)
1319             {
1320                 if (sd.postblit.checkDisabled(loc, sc))
1321                     return true;
1322 
1323                 //checkDeprecated(sc, sd.postblit);        // necessary?
1324                 checkPurity(sc, sd.postblit);
1325                 checkSafety(sc, sd.postblit);
1326                 checkNogc(sc, sd.postblit);
1327                 //checkAccess(sd, loc, sc, sd.postblit);   // necessary?
1328                 return false;
1329             }
1330         }
1331         return false;
1332     }
1333 
1334     extern (D) final bool checkRightThis(Scope* sc)
1335     {
1336         if (op == TOK.error)
1337             return true;
1338         if (op == TOK.variable && type.ty != Terror)
1339         {
1340             VarExp ve = cast(VarExp)this;
1341             if (isNeedThisScope(sc, ve.var))
1342             {
1343                 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
1344                 //        sc.intypeof, sc.getStructClassScope(), func, fdthis);
1345                 error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars());
1346                 return true;
1347             }
1348         }
1349         return false;
1350     }
1351 
1352     /*******************************
1353      * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
1354      * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
1355      * Returns true if error occurs.
1356      */
1357     extern (D) final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null)
1358     {
1359         //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
1360         if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
1361             return false;
1362 
1363         // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
1364         switch (rmwOp)
1365         {
1366         case TOK.plusPlus:
1367         case TOK.prePlusPlus:
1368             rmwOp = TOK.addAssign;
1369             break;
1370         case TOK.minusMinus:
1371         case TOK.preMinusMinus:
1372             rmwOp = TOK.minAssign;
1373             break;
1374         default:
1375             break;
1376         }
1377 
1378         error("read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead.", Token.toChars(rmwOp), toChars(), ex ? ex.toChars() : "1");
1379 
1380          return true;
1381     }
1382 
1383     /***************************************
1384      * Parameters:
1385      *      sc:     scope
1386      *      flag:   1: do not issue error message for invalid modification
1387      * Returns:
1388      *      Whether the type is modifiable
1389      */
1390     Modifiable checkModifiable(Scope* sc, int flag = 0)
1391     {
1392         return type ? Modifiable.yes : Modifiable.no; // default modifiable
1393     }
1394 
1395     /*****************************
1396      * If expression can be tested for true or false,
1397      * returns the modified expression.
1398      * Otherwise returns ErrorExp.
1399      */
1400     Expression toBoolean(Scope* sc)
1401     {
1402         // Default is 'yes' - do nothing
1403         Expression e = this;
1404         Type t = type;
1405         Type tb = type.toBasetype();
1406         Type att = null;
1407 
1408         while (1)
1409         {
1410             // Structs can be converted to bool using opCast(bool)()
1411             if (auto ts = tb.isTypeStruct())
1412             {
1413                 AggregateDeclaration ad = ts.sym;
1414                 /* Don't really need to check for opCast first, but by doing so we
1415                  * get better error messages if it isn't there.
1416                  */
1417                 if (Dsymbol fd = search_function(ad, Id._cast))
1418                 {
1419                     e = new CastExp(loc, e, Type.tbool);
1420                     e = e.expressionSemantic(sc);
1421                     return e;
1422                 }
1423 
1424                 // Forward to aliasthis.
1425                 if (ad.aliasthis && tb != att)
1426                 {
1427                     if (!att && tb.checkAliasThisRec())
1428                         att = tb;
1429                     e = resolveAliasThis(sc, e);
1430                     t = e.type;
1431                     tb = e.type.toBasetype();
1432                     continue;
1433                 }
1434             }
1435             break;
1436         }
1437 
1438         if (!t.isBoolean())
1439         {
1440             if (tb != Type.terror)
1441                 error("expression `%s` of type `%s` does not have a boolean value", toChars(), t.toChars());
1442             return new ErrorExp();
1443         }
1444         return e;
1445     }
1446 
1447     /************************************************
1448      * Destructors are attached to VarDeclarations.
1449      * Hence, if expression returns a temp that needs a destructor,
1450      * make sure and create a VarDeclaration for that temp.
1451      */
1452     Expression addDtorHook(Scope* sc)
1453     {
1454         return this;
1455     }
1456 
1457     /******************************
1458      * Take address of expression.
1459      */
1460     final Expression addressOf()
1461     {
1462         //printf("Expression::addressOf()\n");
1463         debug
1464         {
1465             assert(op == TOK.error || isLvalue());
1466         }
1467         Expression e = new AddrExp(loc, this, type.pointerTo());
1468         return e;
1469     }
1470 
1471     /******************************
1472      * If this is a reference, dereference it.
1473      */
1474     final Expression deref()
1475     {
1476         //printf("Expression::deref()\n");
1477         // type could be null if forward referencing an 'auto' variable
1478         if (type)
1479             if (auto tr = type.isTypeReference())
1480             {
1481                 Expression e = new PtrExp(loc, this, tr.next);
1482                 return e;
1483             }
1484         return this;
1485     }
1486 
1487     final Expression optimize(int result, bool keepLvalue = false)
1488     {
1489         return Expression_optimize(this, result, keepLvalue);
1490     }
1491 
1492     // Entry point for CTFE.
1493     // A compile-time result is required. Give an error if not possible
1494     final Expression ctfeInterpret()
1495     {
1496         return .ctfeInterpret(this);
1497     }
1498 
1499     final int isConst()
1500     {
1501         return .isConst(this);
1502     }
1503 
1504     /********************************
1505      * Does this expression statically evaluate to a boolean 'result' (true or false)?
1506      */
1507     bool isBool(bool result)
1508     {
1509         return false;
1510     }
1511 
1512     bool hasCode()
1513     {
1514         return true;
1515     }
1516 
1517     final pure inout nothrow @nogc
1518     {
1519         inout(IntegerExp)   isIntegerExp() { return op == TOK.int64 ? cast(typeof(return))this : null; }
1520         inout(ErrorExp)     isErrorExp() { return op == TOK.error ? cast(typeof(return))this : null; }
1521         inout(VoidInitExp)  isVoidInitExp() { return op == TOK.void_ ? cast(typeof(return))this : null; }
1522         inout(RealExp)      isRealExp() { return op == TOK.float64 ? cast(typeof(return))this : null; }
1523         inout(ComplexExp)   isComplexExp() { return op == TOK.complex80 ? cast(typeof(return))this : null; }
1524         inout(IdentifierExp) isIdentifierExp() { return op == TOK.identifier ? cast(typeof(return))this : null; }
1525         inout(DollarExp)    isDollarExp() { return op == TOK.dollar ? cast(typeof(return))this : null; }
1526         inout(DsymbolExp)   isDsymbolExp() { return op == TOK.dSymbol ? cast(typeof(return))this : null; }
1527         inout(ThisExp)      isThisExp() { return op == TOK.this_ ? cast(typeof(return))this : null; }
1528         inout(SuperExp)     isSuperExp() { return op == TOK.super_ ? cast(typeof(return))this : null; }
1529         inout(NullExp)      isNullExp() { return op == TOK.null_ ? cast(typeof(return))this : null; }
1530         inout(StringExp)    isStringExp() { return op == TOK.string_ ? cast(typeof(return))this : null; }
1531         inout(TupleExp)     isTupleExp() { return op == TOK.tuple ? cast(typeof(return))this : null; }
1532         inout(ArrayLiteralExp) isArrayLiteralExp() { return op == TOK.arrayLiteral ? cast(typeof(return))this : null; }
1533         inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == TOK.assocArrayLiteral ? cast(typeof(return))this : null; }
1534         inout(StructLiteralExp) isStructLiteralExp() { return op == TOK.structLiteral ? cast(typeof(return))this : null; }
1535         inout(TypeExp)      isTypeExp() { return op == TOK.type ? cast(typeof(return))this : null; }
1536         inout(ScopeExp)     isScopeExp() { return op == TOK.scope_ ? cast(typeof(return))this : null; }
1537         inout(TemplateExp)  isTemplateExp() { return op == TOK.template_ ? cast(typeof(return))this : null; }
1538         inout(NewExp) isNewExp() { return op == TOK.new_ ? cast(typeof(return))this : null; }
1539         inout(NewAnonClassExp) isNewAnonClassExp() { return op == TOK.newAnonymousClass ? cast(typeof(return))this : null; }
1540         inout(SymOffExp)    isSymOffExp() { return op == TOK.symbolOffset ? cast(typeof(return))this : null; }
1541         inout(VarExp)       isVarExp() { return op == TOK.variable ? cast(typeof(return))this : null; }
1542         inout(OverExp)      isOverExp() { return op == TOK.overloadSet ? cast(typeof(return))this : null; }
1543         inout(FuncExp)      isFuncExp() { return op == TOK.function_ ? cast(typeof(return))this : null; }
1544         inout(DeclarationExp) isDeclarationExp() { return op == TOK.declaration ? cast(typeof(return))this : null; }
1545         inout(TypeidExp)    isTypeidExp() { return op == TOK.typeid_ ? cast(typeof(return))this : null; }
1546         inout(TraitsExp)    isTraitsExp() { return op == TOK.traits ? cast(typeof(return))this : null; }
1547         inout(HaltExp)      isHaltExp() { return op == TOK.halt ? cast(typeof(return))this : null; }
1548         inout(IsExp)        isExp() { return op == TOK.is_ ? cast(typeof(return))this : null; }
1549         inout(CompileExp)   isCompileExp() { return op == TOK.mixin_ ? cast(typeof(return))this : null; }
1550         inout(ImportExp)    isImportExp() { return op == TOK.import_ ? cast(typeof(return))this : null; }
1551         inout(AssertExp)    isAssertExp() { return op == TOK.assert_ ? cast(typeof(return))this : null; }
1552         inout(DotIdExp)     isDotIdExp() { return op == TOK.dotIdentifier ? cast(typeof(return))this : null; }
1553         inout(DotTemplateExp) isDotTemplateExp() { return op == TOK.dotTemplateDeclaration ? cast(typeof(return))this : null; }
1554         inout(DotVarExp)    isDotVarExp() { return op == TOK.dotVariable ? cast(typeof(return))this : null; }
1555         inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == TOK.dotTemplateInstance ? cast(typeof(return))this : null; }
1556         inout(DelegateExp)  isDelegateExp() { return op == TOK.delegate_ ? cast(typeof(return))this : null; }
1557         inout(DotTypeExp)   isDotTypeExp() { return op == TOK.dotType ? cast(typeof(return))this : null; }
1558         inout(CallExp)      isCallExp() { return op == TOK.call ? cast(typeof(return))this : null; }
1559         inout(AddrExp)      isAddrExp() { return op == TOK.address ? cast(typeof(return))this : null; }
1560         inout(PtrExp)       isPtrExp() { return op == TOK.star ? cast(typeof(return))this : null; }
1561         inout(NegExp)       isNegExp() { return op == TOK.negate ? cast(typeof(return))this : null; }
1562         inout(UAddExp)      isUAddExp() { return op == TOK.uadd ? cast(typeof(return))this : null; }
1563         inout(ComExp)       isComExp() { return op == TOK.tilde ? cast(typeof(return))this : null; }
1564         inout(NotExp)       isNotExp() { return op == TOK.not ? cast(typeof(return))this : null; }
1565         inout(DeleteExp)    isDeleteExp() { return op == TOK.delete_ ? cast(typeof(return))this : null; }
1566         inout(CastExp)      isCastExp() { return op == TOK.cast_ ? cast(typeof(return))this : null; }
1567         inout(VectorExp)    isVectorExp() { return op == TOK.vector ? cast(typeof(return))this : null; }
1568         inout(VectorArrayExp) isVectorArrayExp() { return op == TOK.vectorArray ? cast(typeof(return))this : null; }
1569         inout(SliceExp)     isSliceExp() { return op == TOK.slice ? cast(typeof(return))this : null; }
1570         inout(ArrayLengthExp) isArrayLengthExp() { return op == TOK.arrayLength ? cast(typeof(return))this : null; }
1571         inout(ArrayExp)     isArrayExp() { return op == TOK.array ? cast(typeof(return))this : null; }
1572         inout(DotExp)       isDotExp() { return op == TOK.dot ? cast(typeof(return))this : null; }
1573         inout(CommaExp)     isCommaExp() { return op == TOK.comma ? cast(typeof(return))this : null; }
1574         inout(IntervalExp)  isIntervalExp() { return op == TOK.interval ? cast(typeof(return))this : null; }
1575         inout(DelegatePtrExp)     isDelegatePtrExp() { return op == TOK.delegatePointer ? cast(typeof(return))this : null; }
1576         inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == TOK.delegateFunctionPointer ? cast(typeof(return))this : null; }
1577         inout(IndexExp)     isIndexExp() { return op == TOK.index ? cast(typeof(return))this : null; }
1578         inout(PostExp)      isPostExp()  { return (op == TOK.plusPlus || op == TOK.minusMinus) ? cast(typeof(return))this : null; }
1579         inout(PreExp)       isPreExp()   { return (op == TOK.prePlusPlus || op == TOK.preMinusMinus) ? cast(typeof(return))this : null; }
1580         inout(AssignExp)    isAssignExp()    { return op == TOK.assign ? cast(typeof(return))this : null; }
1581         inout(ConstructExp) isConstructExp() { return op == TOK.construct ? cast(typeof(return))this : null; }
1582         inout(BlitExp)      isBlitExp()      { return op == TOK.blit ? cast(typeof(return))this : null; }
1583         inout(AddAssignExp) isAddAssignExp() { return op == TOK.addAssign ? cast(typeof(return))this : null; }
1584         inout(MinAssignExp) isMinAssignExp() { return op == TOK.minAssign ? cast(typeof(return))this : null; }
1585         inout(MulAssignExp) isMulAssignExp() { return op == TOK.mulAssign ? cast(typeof(return))this : null; }
1586 
1587         inout(DivAssignExp) isDivAssignExp() { return op == TOK.divAssign ? cast(typeof(return))this : null; }
1588         inout(ModAssignExp) isModAssignExp() { return op == TOK.modAssign ? cast(typeof(return))this : null; }
1589         inout(AndAssignExp) isAndAssignExp() { return op == TOK.andAssign ? cast(typeof(return))this : null; }
1590         inout(OrAssignExp)  isOrAssignExp()  { return op == TOK.orAssign ? cast(typeof(return))this : null; }
1591         inout(XorAssignExp) isXorAssignExp() { return op == TOK.xorAssign ? cast(typeof(return))this : null; }
1592         inout(PowAssignExp) isPowAssignExp() { return op == TOK.powAssign ? cast(typeof(return))this : null; }
1593 
1594         inout(ShlAssignExp)  isShlAssignExp()  { return op == TOK.leftShiftAssign ? cast(typeof(return))this : null; }
1595         inout(ShrAssignExp)  isShrAssignExp()  { return op == TOK.rightShiftAssign ? cast(typeof(return))this : null; }
1596         inout(UshrAssignExp) isUshrAssignExp() { return op == TOK.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
1597 
1598         inout(CatAssignExp) isCatAssignExp() { return op == TOK.concatenateAssign
1599                                                 ? cast(typeof(return))this
1600                                                 : null; }
1601 
1602         inout(CatElemAssignExp) isCatElemAssignExp() { return op == TOK.concatenateElemAssign
1603                                                 ? cast(typeof(return))this
1604                                                 : null; }
1605 
1606         inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == TOK.concatenateDcharAssign
1607                                                 ? cast(typeof(return))this
1608                                                 : null; }
1609 
1610         inout(AddExp)      isAddExp() { return op == TOK.add ? cast(typeof(return))this : null; }
1611         inout(MinExp)      isMinExp() { return op == TOK.min ? cast(typeof(return))this : null; }
1612         inout(CatExp)      isCatExp() { return op == TOK.concatenate ? cast(typeof(return))this : null; }
1613         inout(MulExp)      isMulExp() { return op == TOK.mul ? cast(typeof(return))this : null; }
1614         inout(DivExp)      isDivExp() { return op == TOK.div ? cast(typeof(return))this : null; }
1615         inout(ModExp)      isModExp() { return op == TOK.mod ? cast(typeof(return))this : null; }
1616         inout(PowExp)      isPowExp() { return op == TOK.pow ? cast(typeof(return))this : null; }
1617         inout(ShlExp)      isShlExp() { return op == TOK.leftShift ? cast(typeof(return))this : null; }
1618         inout(ShrExp)      isShrExp() { return op == TOK.rightShift ? cast(typeof(return))this : null; }
1619         inout(UshrExp)     isUshrExp() { return op == TOK.unsignedRightShift ? cast(typeof(return))this : null; }
1620         inout(AndExp)      isAndExp() { return op == TOK.and ? cast(typeof(return))this : null; }
1621         inout(OrExp)       isOrExp() { return op == TOK.or ? cast(typeof(return))this : null; }
1622         inout(XorExp)      isXorExp() { return op == TOK.xor ? cast(typeof(return))this : null; }
1623         inout(LogicalExp)  isLogicalExp() { return (op == TOK.andAnd || op == TOK.orOr) ? cast(typeof(return))this : null; }
1624         //inout(CmpExp)    isCmpExp() { return op == TOK. ? cast(typeof(return))this : null; }
1625         inout(InExp)       isInExp() { return op == TOK.in_ ? cast(typeof(return))this : null; }
1626         inout(RemoveExp)   isRemoveExp() { return op == TOK.remove ? cast(typeof(return))this : null; }
1627         inout(EqualExp)    isEqualExp() { return (op == TOK.equal || op == TOK.notEqual) ? cast(typeof(return))this : null; }
1628         inout(IdentityExp) isIdentityExp() { return (op == TOK.identity || op == TOK.notIdentity) ? cast(typeof(return))this : null; }
1629         inout(CondExp)     isCondExp() { return op == TOK.question ? cast(typeof(return))this : null; }
1630 
1631         inout(DefaultInitExp)    isDefaultInitExp() { return op == TOK.default_ ? cast(typeof(return))this : null; }
1632         inout(FileInitExp)       isFileInitExp() { return (op == TOK.file || op == TOK.fileFullPath) ? cast(typeof(return))this : null; }
1633         inout(LineInitExp)       isLineInitExp() { return op == TOK.line ? cast(typeof(return))this : null; }
1634         inout(ModuleInitExp)     isModuleInitExp() { return op == TOK.moduleString ? cast(typeof(return))this : null; }
1635         inout(FuncInitExp)       isFuncInitExp() { return op == TOK.functionString ? cast(typeof(return))this : null; }
1636         inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == TOK.prettyFunction ? cast(typeof(return))this : null; }
1637         inout(ClassReferenceExp) isClassReferenceExp() { return op == TOK.classReference ? cast(typeof(return))this : null; }
1638     }
1639 
1640     override void accept(Visitor v)
1641     {
1642         v.visit(this);
1643     }
1644 }
1645 
1646 /***********************************************************
1647  */
1648 extern (C++) final class IntegerExp : Expression
1649 {
1650     private dinteger_t value;
1651 
1652     extern (D) this(const ref Loc loc, dinteger_t value, Type type)
1653     {
1654         super(loc, TOK.int64, __traits(classInstanceSize, IntegerExp));
1655         //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
1656         assert(type);
1657         if (!type.isscalar())
1658         {
1659             //printf("%s, loc = %d\n", toChars(), loc.linnum);
1660             if (type.ty != Terror)
1661                 error("integral constant must be scalar type, not `%s`", type.toChars());
1662             type = Type.terror;
1663         }
1664         this.type = type;
1665         this.value = normalize(type.toBasetype().ty, value);
1666     }
1667 
1668     extern (D) this(dinteger_t value)
1669     {
1670         super(Loc.initial, TOK.int64, __traits(classInstanceSize, IntegerExp));
1671         this.type = Type.tint32;
1672         this.value = cast(d_int32)value;
1673     }
1674 
1675     static IntegerExp create(Loc loc, dinteger_t value, Type type)
1676     {
1677         return new IntegerExp(loc, value, type);
1678     }
1679 
1680     // Same as create, but doesn't allocate memory.
1681     static void emplace(UnionExp* pue, Loc loc, dinteger_t value, Type type)
1682     {
1683         emplaceExp!(IntegerExp)(pue, loc, value, type);
1684     }
1685 
1686     override bool equals(const RootObject o) const
1687     {
1688         if (this == o)
1689             return true;
1690         if (auto ne = (cast(Expression)o).isIntegerExp())
1691         {
1692             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
1693             {
1694                 return true;
1695             }
1696         }
1697         return false;
1698     }
1699 
1700     override dinteger_t toInteger()
1701     {
1702         // normalize() is necessary until we fix all the paints of 'type'
1703         return value = normalize(type.toBasetype().ty, value);
1704     }
1705 
1706     override real_t toReal()
1707     {
1708         // normalize() is necessary until we fix all the paints of 'type'
1709         const ty = type.toBasetype().ty;
1710         const val = normalize(ty, value);
1711         value = val;
1712         return (ty == Tuns64)
1713             ? real_t(cast(d_uns64)val)
1714             : real_t(cast(d_int64)val);
1715     }
1716 
1717     override real_t toImaginary()
1718     {
1719         return CTFloat.zero;
1720     }
1721 
1722     override complex_t toComplex()
1723     {
1724         return complex_t(toReal());
1725     }
1726 
1727     override bool isBool(bool result)
1728     {
1729         bool r = toInteger() != 0;
1730         return result ? r : !r;
1731     }
1732 
1733     override Expression toLvalue(Scope* sc, Expression e)
1734     {
1735         if (!e)
1736             e = this;
1737         else if (!loc.isValid())
1738             loc = e.loc;
1739         e.error("cannot modify constant `%s`", e.toChars());
1740         return new ErrorExp();
1741     }
1742 
1743     override void accept(Visitor v)
1744     {
1745         v.visit(this);
1746     }
1747 
1748     dinteger_t getInteger()
1749     {
1750         return value;
1751     }
1752 
1753     void setInteger(dinteger_t value)
1754     {
1755         this.value = normalize(type.toBasetype().ty, value);
1756     }
1757 
1758     extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
1759     {
1760         /* 'Normalize' the value of the integer to be in range of the type
1761          */
1762         dinteger_t result;
1763         switch (ty)
1764         {
1765         case Tbool:
1766             result = (value != 0);
1767             break;
1768 
1769         case Tint8:
1770             result = cast(d_int8)value;
1771             break;
1772 
1773         case Tchar:
1774         case Tuns8:
1775             result = cast(d_uns8)value;
1776             break;
1777 
1778         case Tint16:
1779             result = cast(d_int16)value;
1780             break;
1781 
1782         case Twchar:
1783         case Tuns16:
1784             result = cast(d_uns16)value;
1785             break;
1786 
1787         case Tint32:
1788             result = cast(d_int32)value;
1789             break;
1790 
1791         case Tdchar:
1792         case Tuns32:
1793             result = cast(d_uns32)value;
1794             break;
1795 
1796         case Tint64:
1797             result = cast(d_int64)value;
1798             break;
1799 
1800         case Tuns64:
1801             result = cast(d_uns64)value;
1802             break;
1803 
1804         case Tpointer:
1805             if (target.ptrsize == 8)
1806                 goto case Tuns64;
1807             if (target.ptrsize == 4)
1808                 goto case Tuns32;
1809             if (target.ptrsize == 2)
1810                 goto case Tuns16;
1811             assert(0);
1812 
1813         default:
1814             break;
1815         }
1816         return result;
1817     }
1818 
1819     override Expression syntaxCopy()
1820     {
1821         return this;
1822     }
1823 
1824     /**
1825      * Use this instead of creating new instances for commonly used literals
1826      * such as 0 or 1.
1827      *
1828      * Parameters:
1829      *      v = The value of the expression
1830      * Returns:
1831      *      A static instance of the expression, typed as `Tint32`.
1832      */
1833     static IntegerExp literal(int v)()
1834     {
1835         __gshared IntegerExp theConstant;
1836         if (!theConstant)
1837             theConstant = new IntegerExp(v);
1838         return theConstant;
1839     }
1840 
1841     /**
1842      * Use this instead of creating new instances for commonly used bools.
1843      *
1844      * Parameters:
1845      *      b = The value of the expression
1846      * Returns:
1847      *      A static instance of the expression, typed as `Type.tbool`.
1848      */
1849     static IntegerExp createBool(bool b)
1850     {
1851         __gshared IntegerExp trueExp, falseExp;
1852         if (!trueExp)
1853         {
1854             trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
1855             falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
1856         }
1857         return b ? trueExp : falseExp;
1858     }
1859 }
1860 
1861 /***********************************************************
1862  * Use this expression for error recovery.
1863  * It should behave as a 'sink' to prevent further cascaded error messages.
1864  */
1865 extern (C++) final class ErrorExp : Expression
1866 {
1867     extern (D) this()
1868     {
1869         if (global.errors == 0 && global.gaggedErrors == 0)
1870         {
1871              /* Unfortunately, errors can still leak out of gagged errors,
1872               * and we need to set the error count to prevent bogus code
1873               * generation. At least give a message.
1874               */
1875              error("unknown, please file report on issues.dlang.org");
1876         }
1877 
1878         super(Loc.initial, TOK.error, __traits(classInstanceSize, ErrorExp));
1879         type = Type.terror;
1880     }
1881 
1882     override Expression toLvalue(Scope* sc, Expression e)
1883     {
1884         return this;
1885     }
1886 
1887     override void accept(Visitor v)
1888     {
1889         v.visit(this);
1890     }
1891 
1892     extern (C++) __gshared ErrorExp errorexp; // handy shared value
1893 }
1894 
1895 
1896 /***********************************************************
1897  * An uninitialized value,
1898  * generated from void initializers.
1899  */
1900 extern (C++) final class VoidInitExp : Expression
1901 {
1902     VarDeclaration var; /// the variable from where the void value came from, null if not known
1903                         /// Useful for error messages
1904 
1905     extern (D) this(VarDeclaration var)
1906     {
1907         super(var.loc, TOK.void_, __traits(classInstanceSize, VoidInitExp));
1908         this.var = var;
1909         this.type = var.type;
1910     }
1911 
1912     override const(char)* toChars() const
1913     {
1914         return "void";
1915     }
1916 
1917     override void accept(Visitor v)
1918     {
1919         v.visit(this);
1920     }
1921 }
1922 
1923 
1924 /***********************************************************
1925  */
1926 extern (C++) final class RealExp : Expression
1927 {
1928     real_t value;
1929 
1930     extern (D) this(const ref Loc loc, real_t value, Type type)
1931     {
1932         super(loc, TOK.float64, __traits(classInstanceSize, RealExp));
1933         //printf("RealExp::RealExp(%Lg)\n", value);
1934         this.value = value;
1935         this.type = type;
1936     }
1937 
1938     static RealExp create(Loc loc, real_t value, Type type)
1939     {
1940         return new RealExp(loc, value, type);
1941     }
1942 
1943     // Same as create, but doesn't allocate memory.
1944     static void emplace(UnionExp* pue, Loc loc, real_t value, Type type)
1945     {
1946         emplaceExp!(RealExp)(pue, loc, value, type);
1947     }
1948 
1949     override bool equals(const RootObject o) const
1950     {
1951         if (this == o)
1952             return true;
1953         if (auto ne = (cast(Expression)o).isRealExp())
1954         {
1955             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
1956             {
1957                 return true;
1958             }
1959         }
1960         return false;
1961     }
1962 
1963     override dinteger_t toInteger()
1964     {
1965         return cast(sinteger_t)toReal();
1966     }
1967 
1968     override uinteger_t toUInteger()
1969     {
1970         return cast(uinteger_t)toReal();
1971     }
1972 
1973     override real_t toReal()
1974     {
1975         return type.isreal() ? value : CTFloat.zero;
1976     }
1977 
1978     override real_t toImaginary()
1979     {
1980         return type.isreal() ? CTFloat.zero : value;
1981     }
1982 
1983     override complex_t toComplex()
1984     {
1985         return complex_t(toReal(), toImaginary());
1986     }
1987 
1988     override bool isBool(bool result)
1989     {
1990         return result ? cast(bool)value : !cast(bool)value;
1991     }
1992 
1993     override void accept(Visitor v)
1994     {
1995         v.visit(this);
1996     }
1997 }
1998 
1999 /***********************************************************
2000  */
2001 extern (C++) final class ComplexExp : Expression
2002 {
2003     complex_t value;
2004 
2005     extern (D) this(const ref Loc loc, complex_t value, Type type)
2006     {
2007         super(loc, TOK.complex80, __traits(classInstanceSize, ComplexExp));
2008         this.value = value;
2009         this.type = type;
2010         //printf("ComplexExp::ComplexExp(%s)\n", toChars());
2011     }
2012 
2013     static ComplexExp create(Loc loc, complex_t value, Type type)
2014     {
2015         return new ComplexExp(loc, value, type);
2016     }
2017 
2018     // Same as create, but doesn't allocate memory.
2019     static void emplace(UnionExp* pue, Loc loc, complex_t value, Type type)
2020     {
2021         emplaceExp!(ComplexExp)(pue, loc, value, type);
2022     }
2023 
2024     override bool equals(const RootObject o) const
2025     {
2026         if (this == o)
2027             return true;
2028         if (auto ne = (cast(Expression)o).isComplexExp())
2029         {
2030             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(creall(value), creall(ne.value)) && RealIdentical(cimagl(value), cimagl(ne.value)))
2031             {
2032                 return true;
2033             }
2034         }
2035         return false;
2036     }
2037 
2038     override dinteger_t toInteger()
2039     {
2040         return cast(sinteger_t)toReal();
2041     }
2042 
2043     override uinteger_t toUInteger()
2044     {
2045         return cast(uinteger_t)toReal();
2046     }
2047 
2048     override real_t toReal()
2049     {
2050         return creall(value);
2051     }
2052 
2053     override real_t toImaginary()
2054     {
2055         return cimagl(value);
2056     }
2057 
2058     override complex_t toComplex()
2059     {
2060         return value;
2061     }
2062 
2063     override bool isBool(bool result)
2064     {
2065         if (result)
2066             return cast(bool)value;
2067         else
2068             return !value;
2069     }
2070 
2071     override void accept(Visitor v)
2072     {
2073         v.visit(this);
2074     }
2075 }
2076 
2077 /***********************************************************
2078  */
2079 extern (C++) class IdentifierExp : Expression
2080 {
2081     Identifier ident;
2082 
2083     extern (D) this(const ref Loc loc, Identifier ident)
2084     {
2085         super(loc, TOK.identifier, __traits(classInstanceSize, IdentifierExp));
2086         this.ident = ident;
2087     }
2088 
2089     static IdentifierExp create(Loc loc, Identifier ident)
2090     {
2091         return new IdentifierExp(loc, ident);
2092     }
2093 
2094     override final bool isLvalue()
2095     {
2096         return true;
2097     }
2098 
2099     override final Expression toLvalue(Scope* sc, Expression e)
2100     {
2101         return this;
2102     }
2103 
2104     override void accept(Visitor v)
2105     {
2106         v.visit(this);
2107     }
2108 }
2109 
2110 /***********************************************************
2111  */
2112 extern (C++) final class DollarExp : IdentifierExp
2113 {
2114     extern (D) this(const ref Loc loc)
2115     {
2116         super(loc, Id.dollar);
2117     }
2118 
2119     override void accept(Visitor v)
2120     {
2121         v.visit(this);
2122     }
2123 }
2124 
2125 /***********************************************************
2126  * Won't be generated by parser.
2127  */
2128 extern (C++) final class DsymbolExp : Expression
2129 {
2130     Dsymbol s;
2131     bool hasOverloads;
2132 
2133     extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
2134     {
2135         super(loc, TOK.dSymbol, __traits(classInstanceSize, DsymbolExp));
2136         this.s = s;
2137         this.hasOverloads = hasOverloads;
2138     }
2139 
2140     override bool isLvalue()
2141     {
2142         return true;
2143     }
2144 
2145     override Expression toLvalue(Scope* sc, Expression e)
2146     {
2147         return this;
2148     }
2149 
2150     override void accept(Visitor v)
2151     {
2152         v.visit(this);
2153     }
2154 }
2155 
2156 /***********************************************************
2157  * http://dlang.org/spec/expression.html#this
2158  */
2159 extern (C++) class ThisExp : Expression
2160 {
2161     VarDeclaration var;
2162 
2163     extern (D) this(const ref Loc loc)
2164     {
2165         super(loc, TOK.this_, __traits(classInstanceSize, ThisExp));
2166         //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2167     }
2168 
2169     this(const ref Loc loc, const TOK tok)
2170     {
2171         super(loc, tok, __traits(classInstanceSize, ThisExp));
2172         //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2173     }
2174 
2175     override Expression syntaxCopy()
2176     {
2177         auto r = cast(ThisExp) super.syntaxCopy();
2178         // require new semantic (possibly new `var` etc.)
2179         r.type = null;
2180         r.var = null;
2181         return r;
2182     }
2183 
2184     override final bool isBool(bool result)
2185     {
2186         return result;
2187     }
2188 
2189     override final bool isLvalue()
2190     {
2191         // Class `this` should be an rvalue; struct `this` should be an lvalue.
2192         return type.toBasetype().ty != Tclass;
2193     }
2194 
2195     override final Expression toLvalue(Scope* sc, Expression e)
2196     {
2197         if (type.toBasetype().ty == Tclass)
2198         {
2199             // Class `this` is an rvalue; struct `this` is an lvalue.
2200             return Expression.toLvalue(sc, e);
2201         }
2202         return this;
2203     }
2204 
2205     override void accept(Visitor v)
2206     {
2207         v.visit(this);
2208     }
2209 }
2210 
2211 /***********************************************************
2212  * http://dlang.org/spec/expression.html#super
2213  */
2214 extern (C++) final class SuperExp : ThisExp
2215 {
2216     extern (D) this(const ref Loc loc)
2217     {
2218         super(loc, TOK.super_);
2219     }
2220 
2221     override void accept(Visitor v)
2222     {
2223         v.visit(this);
2224     }
2225 }
2226 
2227 /***********************************************************
2228  * http://dlang.org/spec/expression.html#null
2229  */
2230 extern (C++) final class NullExp : Expression
2231 {
2232     ubyte committed;    // !=0 if type is committed
2233 
2234     extern (D) this(const ref Loc loc, Type type = null)
2235     {
2236         super(loc, TOK.null_, __traits(classInstanceSize, NullExp));
2237         this.type = type;
2238     }
2239 
2240     override bool equals(const RootObject o) const
2241     {
2242         if (auto e = o.isExpression())
2243         {
2244             if (e.op == TOK.null_ && type.equals(e.type))
2245             {
2246                 return true;
2247             }
2248         }
2249         return false;
2250     }
2251 
2252     override bool isBool(bool result)
2253     {
2254         return result ? false : true;
2255     }
2256 
2257     override StringExp toStringExp()
2258     {
2259         if (implicitConvTo(Type.tstring))
2260         {
2261             auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
2262             se.type = Type.tstring;
2263             return se;
2264         }
2265         return null;
2266     }
2267 
2268     override void accept(Visitor v)
2269     {
2270         v.visit(this);
2271     }
2272 }
2273 
2274 /***********************************************************
2275  * http://dlang.org/spec/expression.html#string_literals
2276  */
2277 extern (C++) final class StringExp : Expression
2278 {
2279     private union
2280     {
2281         char* string;   // if sz == 1
2282         wchar* wstring; // if sz == 2
2283         dchar* dstring; // if sz == 4
2284     }                   // (const if ownedByCtfe == OwnedBy.code)
2285     size_t len;         // number of code units
2286     ubyte sz = 1;       // 1: char, 2: wchar, 4: dchar
2287     ubyte committed;    // !=0 if type is committed
2288     enum char NoPostfix = 0;
2289     char postfix = NoPostfix;   // 'c', 'w', 'd'
2290     OwnedBy ownedByCtfe = OwnedBy.code;
2291 
2292     extern (D) this(const ref Loc loc, const(void)[] string)
2293     {
2294         super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
2295         this.string = cast(char*)string.ptr; // note that this.string should be const
2296         this.len = string.length;
2297         this.sz = 1;                    // work around LDC bug #1286
2298     }
2299 
2300     extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
2301     {
2302         super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
2303         this.string = cast(char*)string.ptr; // note that this.string should be const
2304         this.len = len;
2305         this.sz = sz;
2306         this.postfix = postfix;
2307     }
2308 
2309     static StringExp create(Loc loc, char* s)
2310     {
2311         return new StringExp(loc, s.toDString());
2312     }
2313 
2314     static StringExp create(Loc loc, void* string, size_t len)
2315     {
2316         return new StringExp(loc, string[0 .. len]);
2317     }
2318 
2319     // Same as create, but doesn't allocate memory.
2320     static void emplace(UnionExp* pue, Loc loc, char* s)
2321     {
2322         emplaceExp!(StringExp)(pue, loc, s.toDString());
2323     }
2324 
2325     extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string)
2326     {
2327         emplaceExp!(StringExp)(pue, loc, string);
2328     }
2329 
2330     extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
2331     {
2332         emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
2333     }
2334 
2335     override bool equals(const RootObject o) const
2336     {
2337         //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
2338         if (auto e = o.isExpression())
2339         {
2340             if (auto se = e.isStringExp())
2341             {
2342                 return compare(se) == 0;
2343             }
2344         }
2345         return false;
2346     }
2347 
2348     /**********************************
2349      * Return the number of code units the string would be if it were re-encoded
2350      * as tynto.
2351      * Params:
2352      *      tynto = code unit type of the target encoding
2353      * Returns:
2354      *      number of code units
2355      */
2356     size_t numberOfCodeUnits(int tynto = 0) const
2357     {
2358         int encSize;
2359         switch (tynto)
2360         {
2361             case 0:      return len;
2362             case Tchar:  encSize = 1; break;
2363             case Twchar: encSize = 2; break;
2364             case Tdchar: encSize = 4; break;
2365             default:
2366                 assert(0);
2367         }
2368         if (sz == encSize)
2369             return len;
2370 
2371         size_t result = 0;
2372         dchar c;
2373 
2374         switch (sz)
2375         {
2376         case 1:
2377             for (size_t u = 0; u < len;)
2378             {
2379                 if (const s = utf_decodeChar(string[0 .. len], u, c))
2380                 {
2381                     error("%.*s", cast(int)s.length, s.ptr);
2382                     return 0;
2383                 }
2384                 result += utf_codeLength(encSize, c);
2385             }
2386             break;
2387 
2388         case 2:
2389             for (size_t u = 0; u < len;)
2390             {
2391                 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
2392                 {
2393                     error("%.*s", cast(int)s.length, s.ptr);
2394                     return 0;
2395                 }
2396                 result += utf_codeLength(encSize, c);
2397             }
2398             break;
2399 
2400         case 4:
2401             foreach (u; 0 .. len)
2402             {
2403                 result += utf_codeLength(encSize, dstring[u]);
2404             }
2405             break;
2406 
2407         default:
2408             assert(0);
2409         }
2410         return result;
2411     }
2412 
2413     /**********************************************
2414      * Write the contents of the string to dest.
2415      * Use numberOfCodeUnits() to determine size of result.
2416      * Params:
2417      *  dest = destination
2418      *  tyto = encoding type of the result
2419      *  zero = add terminating 0
2420      */
2421     void writeTo(void* dest, bool zero, int tyto = 0) const
2422     {
2423         int encSize;
2424         switch (tyto)
2425         {
2426             case 0:      encSize = sz; break;
2427             case Tchar:  encSize = 1; break;
2428             case Twchar: encSize = 2; break;
2429             case Tdchar: encSize = 4; break;
2430             default:
2431                 assert(0);
2432         }
2433         if (sz == encSize)
2434         {
2435             memcpy(dest, string, len * sz);
2436             if (zero)
2437                 memset(dest + len * sz, 0, sz);
2438         }
2439         else
2440             assert(0);
2441     }
2442 
2443     /*********************************************
2444      * Get the code unit at index i
2445      * Params:
2446      *  i = index
2447      * Returns:
2448      *  code unit at index i
2449      */
2450     dchar getCodeUnit(size_t i) const pure
2451     {
2452         assert(i < len);
2453         final switch (sz)
2454         {
2455         case 1:
2456             return string[i];
2457         case 2:
2458             return wstring[i];
2459         case 4:
2460             return dstring[i];
2461         }
2462     }
2463 
2464     /*********************************************
2465      * Set the code unit at index i to c
2466      * Params:
2467      *  i = index
2468      *  c = code unit to set it to
2469      */
2470     void setCodeUnit(size_t i, dchar c)
2471     {
2472         assert(i < len);
2473         final switch (sz)
2474         {
2475         case 1:
2476             string[i] = cast(char)c;
2477             break;
2478         case 2:
2479             wstring[i] = cast(wchar)c;
2480             break;
2481         case 4:
2482             dstring[i] = c;
2483             break;
2484         }
2485     }
2486 
2487     override StringExp toStringExp()
2488     {
2489         return this;
2490     }
2491 
2492     /****************************************
2493      * Convert string to char[].
2494      */
2495     StringExp toUTF8(Scope* sc)
2496     {
2497         if (sz != 1)
2498         {
2499             // Convert to UTF-8 string
2500             committed = 0;
2501             Expression e = castTo(sc, Type.tchar.arrayOf());
2502             e = e.optimize(WANTvalue);
2503             auto se = e.isStringExp();
2504             assert(se.sz == 1);
2505             return se;
2506         }
2507         return this;
2508     }
2509 
2510     /**
2511      * Compare two `StringExp` by length, then value
2512      *
2513      * The comparison is not the usual C-style comparison as seen with
2514      * `strcmp` or `memcmp`, but instead first compare based on the length.
2515      * This allows both faster lookup and sorting when comparing sparse data.
2516      *
2517      * This ordering scheme is relied on by the string-switching feature.
2518      * Code in Druntime's `core.internal.switch_` relies on this ordering
2519      * when doing a binary search among case statements.
2520      *
2521      * Both `StringExp` should be of the same encoding.
2522      *
2523      * Params:
2524      *   se2 = String expression to compare `this` to
2525      *
2526      * Returns:
2527      *   `0` when `this` is equal to se2, a value greater than `0` if
2528      *   `this` should be considered greater than `se2`,
2529      *   and a value less than `0` if `this` is lesser than `se2`.
2530      */
2531     int compare(const StringExp se2) const nothrow pure @nogc
2532     {
2533         //printf("StringExp::compare()\n");
2534         const len1 = len;
2535         const len2 = se2.len;
2536 
2537         assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
2538         //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
2539         if (len1 == len2)
2540         {
2541             switch (sz)
2542             {
2543             case 1:
2544                 return memcmp(string, se2..string, len1);
2545 
2546             case 2:
2547                 {
2548                     wchar* s1 = cast(wchar*)string;
2549                     wchar* s2 = cast(wchar*)se2..string;
2550                     foreach (u; 0 .. len)
2551                     {
2552                         if (s1[u] != s2[u])
2553                             return s1[u] - s2[u];
2554                     }
2555                 }
2556                 break;
2557             case 4:
2558                 {
2559                     dchar* s1 = cast(dchar*)string;
2560                     dchar* s2 = cast(dchar*)se2..string;
2561                     foreach (u; 0 .. len)
2562                     {
2563                         if (s1[u] != s2[u])
2564                             return s1[u] - s2[u];
2565                     }
2566                 }
2567                 break;
2568             default:
2569                 assert(0);
2570             }
2571         }
2572         return cast(int)(len1 - len2);
2573     }
2574 
2575     override bool isBool(bool result)
2576     {
2577         return result;
2578     }
2579 
2580     override bool isLvalue()
2581     {
2582         /* string literal is rvalue in default, but
2583          * conversion to reference of static array is only allowed.
2584          */
2585         return (type && type.toBasetype().ty == Tsarray);
2586     }
2587 
2588     override Expression toLvalue(Scope* sc, Expression e)
2589     {
2590         //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
2591         return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
2592     }
2593 
2594     override Expression modifiableLvalue(Scope* sc, Expression e)
2595     {
2596         error("cannot modify string literal `%s`", toChars());
2597         return new ErrorExp();
2598     }
2599 
2600     uint charAt(uinteger_t i) const
2601     {
2602         uint value;
2603         switch (sz)
2604         {
2605         case 1:
2606             value = (cast(char*)string)[cast(size_t)i];
2607             break;
2608 
2609         case 2:
2610             value = (cast(ushort*)string)[cast(size_t)i];
2611             break;
2612 
2613         case 4:
2614             value = (cast(uint*)string)[cast(size_t)i];
2615             break;
2616 
2617         default:
2618             assert(0);
2619         }
2620         return value;
2621     }
2622 
2623     /********************************
2624      * Convert string contents to a 0 terminated string,
2625      * allocated by mem.xmalloc().
2626      */
2627     extern (D) const(char)[] toStringz() const
2628     {
2629         auto nbytes = len * sz;
2630         char* s = cast(char*)mem.xmalloc(nbytes + sz);
2631         writeTo(s, true);
2632         return s[0 .. nbytes];
2633     }
2634 
2635     extern (D) const(char)[] peekString() const
2636     {
2637         assert(sz == 1);
2638         return this.string[0 .. len];
2639     }
2640 
2641     extern (D) const(wchar)[] peekWstring() const
2642     {
2643         assert(sz == 2);
2644         return this.wstring[0 .. len];
2645     }
2646 
2647     extern (D) const(dchar)[] peekDstring() const
2648     {
2649         assert(sz == 4);
2650         return this.dstring[0 .. len];
2651     }
2652 
2653     /*******************
2654      * Get a slice of the data.
2655      */
2656     extern (D) const(ubyte)[] peekData() const
2657     {
2658         return cast(const(ubyte)[])this.string[0 .. len * sz];
2659     }
2660 
2661     /*******************
2662      * Borrow a slice of the data, so the caller can modify
2663      * it in-place (!)
2664      */
2665     extern (D) ubyte[] borrowData()
2666     {
2667         return cast(ubyte[])this.string[0 .. len * sz];
2668     }
2669 
2670     /***********************
2671      * Set new string data.
2672      * `this` becomes the new owner of the data.
2673      */
2674     extern (D) void setData(void* s, size_t len, ubyte sz)
2675     {
2676         this.string = cast(char*)s;
2677         this.len = len;
2678         this.sz = sz;
2679     }
2680 
2681     override void accept(Visitor v)
2682     {
2683         v.visit(this);
2684     }
2685 }
2686 
2687 /***********************************************************
2688  */
2689 extern (C++) final class TupleExp : Expression
2690 {
2691     /* Tuple-field access may need to take out its side effect part.
2692      * For example:
2693      *      foo().tupleof
2694      * is rewritten as:
2695      *      (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
2696      * The declaration of temporary variable __tup will be stored in TupleExp.e0.
2697      */
2698     Expression e0;
2699 
2700     Expressions* exps;
2701 
2702     extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
2703     {
2704         super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
2705         //printf("TupleExp(this = %p)\n", this);
2706         this.e0 = e0;
2707         this.exps = exps;
2708     }
2709 
2710     extern (D) this(const ref Loc loc, Expressions* exps)
2711     {
2712         super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
2713         //printf("TupleExp(this = %p)\n", this);
2714         this.exps = exps;
2715     }
2716 
2717     extern (D) this(const ref Loc loc, TupleDeclaration tup)
2718     {
2719         super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
2720         this.exps = new Expressions();
2721 
2722         this.exps.reserve(tup.objects.dim);
2723         foreach (o; *tup.objects)
2724         {
2725             if (Dsymbol s = getDsymbol(o))
2726             {
2727                 /* If tuple element represents a symbol, translate to DsymbolExp
2728                  * to supply implicit 'this' if needed later.
2729                  */
2730                 Expression e = new DsymbolExp(loc, s);
2731                 this.exps.push(e);
2732             }
2733             else if (auto eo = o.isExpression())
2734             {
2735                 auto e = eo.copy();
2736                 e.loc = loc;    // https://issues.dlang.org/show_bug.cgi?id=15669
2737                 this.exps.push(e);
2738             }
2739             else if (auto t = o.isType())
2740             {
2741                 Expression e = new TypeExp(loc, t);
2742                 this.exps.push(e);
2743             }
2744             else
2745             {
2746                 error("`%s` is not an expression", o.toChars());
2747             }
2748         }
2749     }
2750 
2751     static TupleExp create(Loc loc, Expressions* exps)
2752     {
2753         return new TupleExp(loc, exps);
2754     }
2755 
2756     override TupleExp toTupleExp()
2757     {
2758         return this;
2759     }
2760 
2761     override Expression syntaxCopy()
2762     {
2763         return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
2764     }
2765 
2766     override bool equals(const RootObject o) const
2767     {
2768         if (this == o)
2769             return true;
2770         if (auto e = o.isExpression())
2771             if (auto te = e.isTupleExp())
2772             {
2773                 if (exps.dim != te.exps.dim)
2774                     return false;
2775                 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
2776                     return false;
2777                 foreach (i, e1; *exps)
2778                 {
2779                     auto e2 = (*te.exps)[i];
2780                     if (!e1.equals(e2))
2781                         return false;
2782                 }
2783                 return true;
2784             }
2785         return false;
2786     }
2787 
2788     override void accept(Visitor v)
2789     {
2790         v.visit(this);
2791     }
2792 }
2793 
2794 /***********************************************************
2795  * [ e1, e2, e3, ... ]
2796  *
2797  * http://dlang.org/spec/expression.html#array_literals
2798  */
2799 extern (C++) final class ArrayLiteralExp : Expression
2800 {
2801     /** If !is null, elements[] can be sparse and basis is used for the
2802      * "default" element value. In other words, non-null elements[i] overrides
2803      * this 'basis' value.
2804      */
2805     Expression basis;
2806 
2807     Expressions* elements;
2808     OwnedBy ownedByCtfe = OwnedBy.code;
2809 
2810 
2811     extern (D) this(const ref Loc loc, Type type, Expressions* elements)
2812     {
2813         super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2814         this.type = type;
2815         this.elements = elements;
2816     }
2817 
2818     extern (D) this(const ref Loc loc, Type type, Expression e)
2819     {
2820         super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2821         this.type = type;
2822         elements = new Expressions();
2823         elements.push(e);
2824     }
2825 
2826     extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
2827     {
2828         super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2829         this.type = type;
2830         this.basis = basis;
2831         this.elements = elements;
2832     }
2833 
2834     static ArrayLiteralExp create(Loc loc, Expressions* elements)
2835     {
2836         return new ArrayLiteralExp(loc, null, elements);
2837     }
2838 
2839     // Same as create, but doesn't allocate memory.
2840     static void emplace(UnionExp* pue, Loc loc, Expressions* elements)
2841     {
2842         emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
2843     }
2844 
2845     override Expression syntaxCopy()
2846     {
2847         return new ArrayLiteralExp(loc,
2848             null,
2849             basis ? basis.syntaxCopy() : null,
2850             arraySyntaxCopy(elements));
2851     }
2852 
2853     override bool equals(const RootObject o) const
2854     {
2855         if (this == o)
2856             return true;
2857         auto e = o.isExpression();
2858         if (!e)
2859             return false;
2860         if (auto ae = e.isArrayLiteralExp())
2861         {
2862             if (elements.dim != ae.elements.dim)
2863                 return false;
2864             if (elements.dim == 0 && !type.equals(ae.type))
2865             {
2866                 return false;
2867             }
2868 
2869             foreach (i, e1; *elements)
2870             {
2871                 auto e2 = (*ae.elements)[i];
2872                 auto e1x = e1 ? e1 : basis;
2873                 auto e2x = e2 ? e2 : ae.basis;
2874 
2875                 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
2876                     return false;
2877             }
2878             return true;
2879         }
2880         return false;
2881     }
2882 
2883     Expression getElement(size_t i)
2884     {
2885         return this[i];
2886     }
2887 
2888     Expression opIndex(size_t i)
2889     {
2890         auto el = (*elements)[i];
2891         return el ? el : basis;
2892     }
2893 
2894     override bool isBool(bool result)
2895     {
2896         size_t dim = elements ? elements.dim : 0;
2897         return result ? (dim != 0) : (dim == 0);
2898     }
2899 
2900     override StringExp toStringExp()
2901     {
2902         TY telem = type.nextOf().toBasetype().ty;
2903         if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.dim == 0)))
2904         {
2905             ubyte sz = 1;
2906             if (telem == Twchar)
2907                 sz = 2;
2908             else if (telem == Tdchar)
2909                 sz = 4;
2910 
2911             OutBuffer buf;
2912             if (elements)
2913             {
2914                 foreach (i; 0 .. elements.dim)
2915                 {
2916                     auto ch = this[i];
2917                     if (ch.op != TOK.int64)
2918                         return null;
2919                     if (sz == 1)
2920                         buf.writeByte(cast(uint)ch.toInteger());
2921                     else if (sz == 2)
2922                         buf.writeword(cast(uint)ch.toInteger());
2923                     else
2924                         buf.write4(cast(uint)ch.toInteger());
2925                 }
2926             }
2927             char prefix;
2928             if (sz == 1)
2929             {
2930                 prefix = 'c';
2931                 buf.writeByte(0);
2932             }
2933             else if (sz == 2)
2934             {
2935                 prefix = 'w';
2936                 buf.writeword(0);
2937             }
2938             else
2939             {
2940                 prefix = 'd';
2941                 buf.write4(0);
2942             }
2943 
2944             const size_t len = buf.length / sz - 1;
2945             auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
2946             se.sz = sz;
2947             se.type = type;
2948             return se;
2949         }
2950         return null;
2951     }
2952 
2953     override void accept(Visitor v)
2954     {
2955         v.visit(this);
2956     }
2957 }
2958 
2959 /***********************************************************
2960  * [ key0 : value0, key1 : value1, ... ]
2961  *
2962  * http://dlang.org/spec/expression.html#associative_array_literals
2963  */
2964 extern (C++) final class AssocArrayLiteralExp : Expression
2965 {
2966     Expressions* keys;
2967     Expressions* values;
2968 
2969     OwnedBy ownedByCtfe = OwnedBy.code;
2970 
2971     extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
2972     {
2973         super(loc, TOK.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
2974         assert(keys.dim == values.dim);
2975         this.keys = keys;
2976         this.values = values;
2977     }
2978 
2979     override bool equals(const RootObject o) const
2980     {
2981         if (this == o)
2982             return true;
2983         auto e = o.isExpression();
2984         if (!e)
2985             return false;
2986         if (auto ae = e.isAssocArrayLiteralExp())
2987         {
2988             if (keys.dim != ae.keys.dim)
2989                 return false;
2990             size_t count = 0;
2991             foreach (i, key; *keys)
2992             {
2993                 foreach (j, akey; *ae.keys)
2994                 {
2995                     if (key.equals(akey))
2996                     {
2997                         if (!(*values)[i].equals((*ae.values)[j]))
2998                             return false;
2999                         ++count;
3000                     }
3001                 }
3002             }
3003             return count == keys.dim;
3004         }
3005         return false;
3006     }
3007 
3008     override Expression syntaxCopy()
3009     {
3010         return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
3011     }
3012 
3013     override bool isBool(bool result)
3014     {
3015         size_t dim = keys.dim;
3016         return result ? (dim != 0) : (dim == 0);
3017     }
3018 
3019     override void accept(Visitor v)
3020     {
3021         v.visit(this);
3022     }
3023 }
3024 
3025 enum stageScrub             = 0x1;  /// scrubReturnValue is running
3026 enum stageSearchPointers    = 0x2;  /// hasNonConstPointers is running
3027 enum stageOptimize          = 0x4;  /// optimize is running
3028 enum stageApply             = 0x8;  /// apply is running
3029 enum stageInlineScan        = 0x10; /// inlineScan is running
3030 enum stageToCBuffer         = 0x20; /// toCBuffer is running
3031 
3032 /***********************************************************
3033  * sd( e1, e2, e3, ... )
3034  */
3035 extern (C++) final class StructLiteralExp : Expression
3036 {
3037     StructDeclaration sd;   /// which aggregate this is for
3038     Expressions* elements;  /// parallels sd.fields[] with null entries for fields to skip
3039     Type stype;             /// final type of result (can be different from sd's type)
3040 
3041     Symbol* sym;            /// back end symbol to initialize with literal
3042 
3043     /** pointer to the origin instance of the expression.
3044      * once a new expression is created, origin is set to 'this'.
3045      * anytime when an expression copy is created, 'origin' pointer is set to
3046      * 'origin' pointer value of the original expression.
3047      */
3048     StructLiteralExp origin;
3049 
3050     /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
3051     StructLiteralExp inlinecopy;
3052 
3053     /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
3054      * current stage and unmarks before return from this function.
3055      * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
3056      * (with infinite recursion) of this expression.
3057      */
3058     int stageflags;
3059 
3060     bool useStaticInit;     /// if this is true, use the StructDeclaration's init symbol
3061     bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
3062     OwnedBy ownedByCtfe = OwnedBy.code;
3063 
3064     extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
3065     {
3066         super(loc, TOK.structLiteral, __traits(classInstanceSize, StructLiteralExp));
3067         this.sd = sd;
3068         if (!elements)
3069             elements = new Expressions();
3070         this.elements = elements;
3071         this.stype = stype;
3072         this.origin = this;
3073         //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
3074     }
3075 
3076     static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null)
3077     {
3078         return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
3079     }
3080 
3081     override bool equals(const RootObject o) const
3082     {
3083         if (this == o)
3084             return true;
3085         auto e = o.isExpression();
3086         if (!e)
3087             return false;
3088         if (auto se = e.isStructLiteralExp())
3089         {
3090             if (!type.equals(se.type))
3091                 return false;
3092             if (elements.dim != se.elements.dim)
3093                 return false;
3094             foreach (i, e1; *elements)
3095             {
3096                 auto e2 = (*se.elements)[i];
3097                 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3098                     return false;
3099             }
3100             return true;
3101         }
3102         return false;
3103     }
3104 
3105     override Expression syntaxCopy()
3106     {
3107         auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
3108         exp.origin = this;
3109         return exp;
3110     }
3111 
3112     /**************************************
3113      * Gets expression at offset of type.
3114      * Returns NULL if not found.
3115      */
3116     Expression getField(Type type, uint offset)
3117     {
3118         //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
3119         //  /*toChars()*/"", type.toChars(), offset);
3120         Expression e = null;
3121         int i = getFieldIndex(type, offset);
3122 
3123         if (i != -1)
3124         {
3125             //printf("\ti = %d\n", i);
3126             if (i >= sd.nonHiddenFields())
3127                 return null;
3128 
3129             assert(i < elements.dim);
3130             e = (*elements)[i];
3131             if (e)
3132             {
3133                 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
3134 
3135                 /* If type is a static array, and e is an initializer for that array,
3136                  * then the field initializer should be an array literal of e.
3137                  */
3138                 auto tsa = type.isTypeSArray();
3139                 if (tsa && e.type.castMod(0) != type.castMod(0))
3140                 {
3141                     const length = cast(size_t)tsa.dim.toInteger();
3142                     auto z = new Expressions(length);
3143                     foreach (ref q; *z)
3144                         q = e.copy();
3145                     e = new ArrayLiteralExp(loc, type, z);
3146                 }
3147                 else
3148                 {
3149                     e = e.copy();
3150                     e.type = type;
3151                 }
3152                 if (useStaticInit && e.type.needsNested())
3153                     if (auto se = e.isStructLiteralExp())
3154                     {
3155                         se.useStaticInit = true;
3156                     }
3157             }
3158         }
3159         return e;
3160     }
3161 
3162     /************************************
3163      * Get index of field.
3164      * Returns -1 if not found.
3165      */
3166     int getFieldIndex(Type type, uint offset)
3167     {
3168         /* Find which field offset is by looking at the field offsets
3169          */
3170         if (elements.dim)
3171         {
3172             foreach (i, v; sd.fields)
3173             {
3174                 if (offset == v.offset && type.size() == v.type.size())
3175                 {
3176                     /* context fields might not be filled. */
3177                     if (i >= sd.nonHiddenFields())
3178                         return cast(int)i;
3179                     if (auto e = (*elements)[i])
3180                     {
3181                         return cast(int)i;
3182                     }
3183                     break;
3184                 }
3185             }
3186         }
3187         return -1;
3188     }
3189 
3190     override Expression addDtorHook(Scope* sc)
3191     {
3192         /* If struct requires a destructor, rewrite as:
3193          *    (S tmp = S()),tmp
3194          * so that the destructor can be hung on tmp.
3195          */
3196         if (sd.dtor && sc.func)
3197         {
3198             /* Make an identifier for the temporary of the form:
3199              *   __sl%s%d, where %s is the struct name
3200              */
3201             const size_t len = 10;
3202             char[len] buf = void;
3203 
3204             const ident = sd.ident.toString;
3205             const prefix = "__sl";
3206             const charsToUse = ident.length > len - prefix.length ? len - prefix.length : ident.length;
3207             buf[0 .. prefix.length] = prefix;
3208             buf[prefix.length .. prefix.length + charsToUse] = ident[0 .. charsToUse];
3209 
3210             auto tmp = copyToTemp(0, buf, this);
3211             Expression ae = new DeclarationExp(loc, tmp);
3212             Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
3213             e = e.expressionSemantic(sc);
3214             return e;
3215         }
3216         return this;
3217     }
3218 
3219     override void accept(Visitor v)
3220     {
3221         v.visit(this);
3222     }
3223 }
3224 
3225 /***********************************************************
3226  * Mainly just a placeholder
3227  */
3228 extern (C++) final class TypeExp : Expression
3229 {
3230     extern (D) this(const ref Loc loc, Type type)
3231     {
3232         super(loc, TOK.type, __traits(classInstanceSize, TypeExp));
3233         //printf("TypeExp::TypeExp(%s)\n", type.toChars());
3234         this.type = type;
3235     }
3236 
3237     override Expression syntaxCopy()
3238     {
3239         return new TypeExp(loc, type.syntaxCopy());
3240     }
3241 
3242     override bool checkType()
3243     {
3244         error("type `%s` is not an expression", toChars());
3245         return true;
3246     }
3247 
3248     override bool checkValue()
3249     {
3250         error("type `%s` has no value", toChars());
3251         return true;
3252     }
3253 
3254     override void accept(Visitor v)
3255     {
3256         v.visit(this);
3257     }
3258 }
3259 
3260 /***********************************************************
3261  * Mainly just a placeholder of
3262  *  Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
3263  *
3264  * A template instance that requires IFTI:
3265  *      foo!tiargs(fargs)       // foo!tiargs
3266  * is left until CallExp::semantic() or resolveProperties()
3267  */
3268 extern (C++) final class ScopeExp : Expression
3269 {
3270     ScopeDsymbol sds;
3271 
3272     extern (D) this(const ref Loc loc, ScopeDsymbol sds)
3273     {
3274         super(loc, TOK.scope_, __traits(classInstanceSize, ScopeExp));
3275         //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
3276         //static int count; if (++count == 38) *(char*)0=0;
3277         this.sds = sds;
3278         assert(!sds.isTemplateDeclaration());   // instead, you should use TemplateExp
3279     }
3280 
3281     override Expression syntaxCopy()
3282     {
3283         return new ScopeExp(loc, cast(ScopeDsymbol)sds.syntaxCopy(null));
3284     }
3285 
3286     override bool checkType()
3287     {
3288         if (sds.isPackage())
3289         {
3290             error("%s `%s` has no type", sds.kind(), sds.toChars());
3291             return true;
3292         }
3293         if (auto ti = sds.isTemplateInstance())
3294         {
3295             //assert(ti.needsTypeInference(sc));
3296             if (ti.tempdecl &&
3297                 ti.semantictiargsdone &&
3298                 ti.semanticRun == PASS.init)
3299             {
3300                 error("partial %s `%s` has no type", sds.kind(), toChars());
3301                 return true;
3302             }
3303         }
3304         return false;
3305     }
3306 
3307     override bool checkValue()
3308     {
3309         error("%s `%s` has no value", sds.kind(), sds.toChars());
3310         return true;
3311     }
3312 
3313     override void accept(Visitor v)
3314     {
3315         v.visit(this);
3316     }
3317 }
3318 
3319 /***********************************************************
3320  * Mainly just a placeholder
3321  */
3322 extern (C++) final class TemplateExp : Expression
3323 {
3324     TemplateDeclaration td;
3325     FuncDeclaration fd;
3326 
3327     extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
3328     {
3329         super(loc, TOK.template_, __traits(classInstanceSize, TemplateExp));
3330         //printf("TemplateExp(): %s\n", td.toChars());
3331         this.td = td;
3332         this.fd = fd;
3333     }
3334 
3335     override bool isLvalue()
3336     {
3337         return fd !is null;
3338     }
3339 
3340     override Expression toLvalue(Scope* sc, Expression e)
3341     {
3342         if (!fd)
3343             return Expression.toLvalue(sc, e);
3344 
3345         assert(sc);
3346         return symbolToExp(fd, loc, sc, true);
3347     }
3348 
3349     override bool checkType()
3350     {
3351         error("%s `%s` has no type", td.kind(), toChars());
3352         return true;
3353     }
3354 
3355     override bool checkValue()
3356     {
3357         error("%s `%s` has no value", td.kind(), toChars());
3358         return true;
3359     }
3360 
3361     override void accept(Visitor v)
3362     {
3363         v.visit(this);
3364     }
3365 }
3366 
3367 /***********************************************************
3368  * thisexp.new(newargs) newtype(arguments)
3369  */
3370 extern (C++) final class NewExp : Expression
3371 {
3372     Expression thisexp;         // if !=null, 'this' for class being allocated
3373     Expressions* newargs;       // Array of Expression's to call new operator
3374     Type newtype;
3375     Expressions* arguments;     // Array of Expression's
3376 
3377     Expression argprefix;       // expression to be evaluated just before arguments[]
3378     CtorDeclaration member;     // constructor function
3379     NewDeclaration allocator;   // allocator function
3380     bool onstack;               // allocate on stack
3381     bool thrownew;              // this NewExp is the expression of a ThrowStatement
3382 
3383     extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
3384     {
3385         super(loc, TOK.new_, __traits(classInstanceSize, NewExp));
3386         this.thisexp = thisexp;
3387         this.newargs = newargs;
3388         this.newtype = newtype;
3389         this.arguments = arguments;
3390     }
3391 
3392     static NewExp create(Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
3393     {
3394         return new NewExp(loc, thisexp, newargs, newtype, arguments);
3395     }
3396 
3397     override Expression syntaxCopy()
3398     {
3399         return new NewExp(loc,
3400             thisexp ? thisexp.syntaxCopy() : null,
3401             arraySyntaxCopy(newargs),
3402             newtype.syntaxCopy(),
3403             arraySyntaxCopy(arguments));
3404     }
3405 
3406     override void accept(Visitor v)
3407     {
3408         v.visit(this);
3409     }
3410 }
3411 
3412 /***********************************************************
3413  * thisexp.new(newargs) class baseclasses { } (arguments)
3414  */
3415 extern (C++) final class NewAnonClassExp : Expression
3416 {
3417     Expression thisexp;     // if !=null, 'this' for class being allocated
3418     Expressions* newargs;   // Array of Expression's to call new operator
3419     ClassDeclaration cd;    // class being instantiated
3420     Expressions* arguments; // Array of Expression's to call class constructor
3421 
3422     extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments)
3423     {
3424         super(loc, TOK.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
3425         this.thisexp = thisexp;
3426         this.newargs = newargs;
3427         this.cd = cd;
3428         this.arguments = arguments;
3429     }
3430 
3431     override Expression syntaxCopy()
3432     {
3433         return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cast(ClassDeclaration)cd.syntaxCopy(null), arraySyntaxCopy(arguments));
3434     }
3435 
3436     override void accept(Visitor v)
3437     {
3438         v.visit(this);
3439     }
3440 }
3441 
3442 /***********************************************************
3443  */
3444 extern (C++) class SymbolExp : Expression
3445 {
3446     Declaration var;
3447     bool hasOverloads;
3448     Dsymbol originalScope; // original scope before inlining
3449 
3450     extern (D) this(const ref Loc loc, TOK op, int size, Declaration var, bool hasOverloads)
3451     {
3452         super(loc, op, size);
3453         assert(var);
3454         this.var = var;
3455         this.hasOverloads = hasOverloads;
3456     }
3457 
3458     override void accept(Visitor v)
3459     {
3460         v.visit(this);
3461     }
3462 }
3463 
3464 /***********************************************************
3465  * Offset from symbol
3466  */
3467 extern (C++) final class SymOffExp : SymbolExp
3468 {
3469     dinteger_t offset;
3470 
3471     extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
3472     {
3473         if (auto v = var.isVarDeclaration())
3474         {
3475             // FIXME: This error report will never be handled anyone.
3476             // It should be done before the SymOffExp construction.
3477             if (v.needThis())
3478                 .error(loc, "need `this` for address of `%s`", v.toChars());
3479             hasOverloads = false;
3480         }
3481         super(loc, TOK.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
3482         this.offset = offset;
3483     }
3484 
3485     override bool isBool(bool result)
3486     {
3487         return result ? true : false;
3488     }
3489 
3490     override void accept(Visitor v)
3491     {
3492         v.visit(this);
3493     }
3494 }
3495 
3496 /***********************************************************
3497  * Variable
3498  */
3499 extern (C++) final class VarExp : SymbolExp
3500 {
3501     bool delegateWasExtracted;
3502     extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true)
3503     {
3504         if (var.isVarDeclaration())
3505             hasOverloads = false;
3506 
3507         super(loc, TOK.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
3508         //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
3509         //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
3510         this.type = var.type;
3511     }
3512 
3513     static VarExp create(Loc loc, Declaration var, bool hasOverloads = true)
3514     {
3515         return new VarExp(loc, var, hasOverloads);
3516     }
3517 
3518     override bool equals(const RootObject o) const
3519     {
3520         if (this == o)
3521             return true;
3522         if (auto ne = o.isExpression().isVarExp())
3523         {
3524             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
3525             {
3526                 return true;
3527             }
3528         }
3529         return false;
3530     }
3531 
3532     override Modifiable checkModifiable(Scope* sc, int flag)
3533     {
3534         //printf("VarExp::checkModifiable %s", toChars());
3535         assert(type);
3536         return var.checkModify(loc, sc, null, flag);
3537     }
3538 
3539     override bool isLvalue()
3540     {
3541         if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
3542             return false;
3543         return true;
3544     }
3545 
3546     override Expression toLvalue(Scope* sc, Expression e)
3547     {
3548         if (var.storage_class & STC.manifest)
3549         {
3550             error("manifest constant `%s` cannot be modified", var.toChars());
3551             return new ErrorExp();
3552         }
3553         if (var.storage_class & STC.lazy_ && !delegateWasExtracted)
3554         {
3555             error("lazy variable `%s` cannot be modified", var.toChars());
3556             return new ErrorExp();
3557         }
3558         if (var.ident == Id.ctfe)
3559         {
3560             error("cannot modify compiler-generated variable `__ctfe`");
3561             return new ErrorExp();
3562         }
3563         if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
3564         {
3565             error("cannot modify operator `$`");
3566             return new ErrorExp();
3567         }
3568         return this;
3569     }
3570 
3571     override Expression modifiableLvalue(Scope* sc, Expression e)
3572     {
3573         //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
3574         if (var.storage_class & STC.manifest)
3575         {
3576             error("cannot modify manifest constant `%s`", toChars());
3577             return new ErrorExp();
3578         }
3579         // See if this expression is a modifiable lvalue (i.e. not const)
3580         return Expression.modifiableLvalue(sc, e);
3581     }
3582 
3583     override void accept(Visitor v)
3584     {
3585         v.visit(this);
3586     }
3587 
3588     override Expression syntaxCopy()
3589     {
3590         auto ret = super.syntaxCopy();
3591         return ret;
3592     }
3593 }
3594 
3595 /***********************************************************
3596  * Overload Set
3597  */
3598 extern (C++) final class OverExp : Expression
3599 {
3600     OverloadSet vars;
3601 
3602     extern (D) this(const ref Loc loc, OverloadSet s)
3603     {
3604         super(loc, TOK.overloadSet, __traits(classInstanceSize, OverExp));
3605         //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
3606         vars = s;
3607         type = Type.tvoid;
3608     }
3609 
3610     override bool isLvalue()
3611     {
3612         return true;
3613     }
3614 
3615     override Expression toLvalue(Scope* sc, Expression e)
3616     {
3617         return this;
3618     }
3619 
3620     override void accept(Visitor v)
3621     {
3622         v.visit(this);
3623     }
3624 }
3625 
3626 /***********************************************************
3627  * Function/Delegate literal
3628  */
3629 
3630 extern (C++) final class FuncExp : Expression
3631 {
3632     FuncLiteralDeclaration fd;
3633     TemplateDeclaration td;
3634     TOK tok;
3635 
3636     extern (D) this(const ref Loc loc, Dsymbol s)
3637     {
3638         super(loc, TOK.function_, __traits(classInstanceSize, FuncExp));
3639         this.td = s.isTemplateDeclaration();
3640         this.fd = s.isFuncLiteralDeclaration();
3641         if (td)
3642         {
3643             assert(td.literal);
3644             assert(td.members && td.members.dim == 1);
3645             fd = (*td.members)[0].isFuncLiteralDeclaration();
3646         }
3647         tok = fd.tok; // save original kind of function/delegate/(infer)
3648         assert(fd.fbody);
3649     }
3650 
3651     override bool equals(const RootObject o) const
3652     {
3653         if (this == o)
3654             return true;
3655         auto e = o.isExpression();
3656         if (!e)
3657             return false;
3658         if (auto fe = e.isFuncExp())
3659         {
3660             return fd == fe.fd;
3661         }
3662         return false;
3663     }
3664 
3665     extern (D) void genIdent(Scope* sc)
3666     {
3667         if (fd.ident == Id.empty)
3668         {
3669             const(char)[] s;
3670             if (fd.fes)
3671                 s = "__foreachbody";
3672             else if (fd.tok == TOK.reserved)
3673                 s = "__lambda";
3674             else if (fd.tok == TOK.delegate_)
3675                 s = "__dgliteral";
3676             else
3677                 s = "__funcliteral";
3678 
3679             DsymbolTable symtab;
3680             if (FuncDeclaration func = sc.parent.isFuncDeclaration())
3681             {
3682                 if (func.localsymtab is null)
3683                 {
3684                     // Inside template constraint, symtab is not set yet.
3685                     // Initialize it lazily.
3686                     func.localsymtab = new DsymbolTable();
3687                 }
3688                 symtab = func.localsymtab;
3689             }
3690             else
3691             {
3692                 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
3693                 if (!sds.symtab)
3694                 {
3695                     // Inside template constraint, symtab may not be set yet.
3696                     // Initialize it lazily.
3697                     assert(sds.isTemplateInstance());
3698                     sds.symtab = new DsymbolTable();
3699                 }
3700                 symtab = sds.symtab;
3701             }
3702             assert(symtab);
3703             Identifier id = Identifier.generateId(s, symtab.length() + 1);
3704             fd.ident = id;
3705             if (td)
3706                 td.ident = id;
3707             symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd);
3708         }
3709     }
3710 
3711     override Expression syntaxCopy()
3712     {
3713         if (td)
3714             return new FuncExp(loc, td.syntaxCopy(null));
3715         else if (fd.semanticRun == PASS.init)
3716             return new FuncExp(loc, fd.syntaxCopy(null));
3717         else // https://issues.dlang.org/show_bug.cgi?id=13481
3718              // Prevent multiple semantic analysis of lambda body.
3719             return new FuncExp(loc, fd);
3720     }
3721 
3722     extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0)
3723     {
3724 
3725         static MATCH cannotInfer(Expression e, Type to, int flag)
3726         {
3727             if (!flag)
3728                 e.error("cannot infer parameter types from `%s`", to.toChars());
3729             return MATCH.nomatch;
3730         }
3731 
3732         //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
3733         if (presult)
3734             *presult = null;
3735 
3736         TypeFunction tof = null;
3737         if (to.ty == Tdelegate)
3738         {
3739             if (tok == TOK.function_)
3740             {
3741                 if (!flag)
3742                     error("cannot match function literal to delegate type `%s`", to.toChars());
3743                 return MATCH.nomatch;
3744             }
3745             tof = cast(TypeFunction)to.nextOf();
3746         }
3747         else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
3748         {
3749             if (tok == TOK.delegate_)
3750             {
3751                 if (!flag)
3752                     error("cannot match delegate literal to function pointer type `%s`", to.toChars());
3753                 return MATCH.nomatch;
3754             }
3755         }
3756 
3757         if (td)
3758         {
3759             if (!tof)
3760             {
3761                 return cannotInfer(this, to, flag);
3762             }
3763 
3764             // Parameter types inference from 'tof'
3765             assert(td._scope);
3766             TypeFunction tf = fd.type.isTypeFunction();
3767             //printf("\ttof = %s\n", tof.toChars());
3768             //printf("\ttf  = %s\n", tf.toChars());
3769             size_t dim = tf.parameterList.length;
3770 
3771             if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
3772                 return cannotInfer(this, to, flag);
3773 
3774             auto tiargs = new Objects();
3775             tiargs.reserve(td.parameters.dim);
3776 
3777             foreach (tp; *td.parameters)
3778             {
3779                 size_t u = 0;
3780                 for (; u < dim; u++)
3781                 {
3782                     Parameter p = tf.parameterList[u];
3783                     if (auto ti = p.type.isTypeIdentifier())
3784                         if (ti && ti.ident == tp.ident)
3785                         {
3786                             break;
3787                         }
3788                 }
3789                 assert(u < dim);
3790                 Parameter pto = tof.parameterList[u];
3791                 Type t = pto.type;
3792                 if (t.ty == Terror)
3793                     return cannotInfer(this, to, flag);
3794                 tiargs.push(t);
3795             }
3796 
3797             // Set target of return type inference
3798             if (!tf.next && tof.next)
3799                 fd.treq = to;
3800 
3801             auto ti = new TemplateInstance(loc, td, tiargs);
3802             Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
3803 
3804             // Reset inference target for the later re-semantic
3805             fd.treq = null;
3806 
3807             if (ex.op == TOK.error)
3808                 return MATCH.nomatch;
3809             if (auto ef = ex.isFuncExp())
3810                 return ef.matchType(to, sc, presult, flag);
3811             else
3812                 return cannotInfer(this, to, flag);
3813         }
3814 
3815         if (!tof || !tof.next)
3816             return MATCH.nomatch;
3817 
3818         assert(type && type != Type.tvoid);
3819         if (fd.type.ty == Terror)
3820             return MATCH.nomatch;
3821         auto tfx = fd.type.isTypeFunction();
3822         bool convertMatch = (type.ty != to.ty);
3823 
3824         if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
3825         {
3826             /* If return type is inferred and covariant return,
3827              * tweak return statements to required return type.
3828              *
3829              * interface I {}
3830              * class C : Object, I{}
3831              *
3832              * I delegate() dg = delegate() { return new class C(); }
3833              */
3834             convertMatch = true;
3835 
3836             auto tfy = new TypeFunction(tfx.parameterList, tof.next,
3837                         tfx.linkage, STC.undefined_);
3838             tfy.mod = tfx.mod;
3839             tfy.isnothrow = tfx.isnothrow;
3840             tfy.isnogc = tfx.isnogc;
3841             tfy.purity = tfx.purity;
3842             tfy.isproperty = tfx.isproperty;
3843             tfy.isref = tfx.isref;
3844             tfy.iswild = tfx.iswild;
3845             tfy.deco = tfy.merge().deco;
3846 
3847             tfx = tfy;
3848         }
3849         Type tx;
3850         if (tok == TOK.delegate_ ||
3851             tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
3852         {
3853             // Allow conversion from implicit function pointer to delegate
3854             tx = new TypeDelegate(tfx);
3855             tx.deco = tx.merge().deco;
3856         }
3857         else
3858         {
3859             assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer);
3860             tx = tfx.pointerTo();
3861         }
3862         //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
3863 
3864         MATCH m = tx.implicitConvTo(to);
3865         if (m > MATCH.nomatch)
3866         {
3867             // MATCH.exact:      exact type match
3868             // MATCH.constant:      covairiant type match (eg. attributes difference)
3869             // MATCH.convert:    context conversion
3870             m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
3871 
3872             if (presult)
3873             {
3874                 (*presult) = cast(FuncExp)copy();
3875                 (*presult).type = to;
3876 
3877                 // https://issues.dlang.org/show_bug.cgi?id=12508
3878                 // Tweak function body for covariant returns.
3879                 (*presult).fd.modifyReturns(sc, tof.next);
3880             }
3881         }
3882         else if (!flag)
3883         {
3884             auto ts = toAutoQualChars(tx, to);
3885             error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
3886                 toChars(), ts[0], ts[1]);
3887         }
3888         return m;
3889     }
3890 
3891     override const(char)* toChars() const
3892     {
3893         return fd.toChars();
3894     }
3895 
3896     override bool checkType()
3897     {
3898         if (td)
3899         {
3900             error("template lambda has no type");
3901             return true;
3902         }
3903         return false;
3904     }
3905 
3906     override bool checkValue()
3907     {
3908         if (td)
3909         {
3910             error("template lambda has no value");
3911             return true;
3912         }
3913         return false;
3914     }
3915 
3916     override void accept(Visitor v)
3917     {
3918         v.visit(this);
3919     }
3920 }
3921 
3922 /***********************************************************
3923  * Declaration of a symbol
3924  *
3925  * D grammar allows declarations only as statements. However in AST representation
3926  * it can be part of any expression. This is used, for example, during internal
3927  * syntax re-writes to inject hidden symbols.
3928  */
3929 extern (C++) final class DeclarationExp : Expression
3930 {
3931     Dsymbol declaration;
3932 
3933     extern (D) this(const ref Loc loc, Dsymbol declaration)
3934     {
3935         super(loc, TOK.declaration, __traits(classInstanceSize, DeclarationExp));
3936         this.declaration = declaration;
3937     }
3938 
3939     override Expression syntaxCopy()
3940     {
3941         return new DeclarationExp(loc, declaration.syntaxCopy(null));
3942     }
3943 
3944     override bool hasCode()
3945     {
3946         if (auto vd = declaration.isVarDeclaration())
3947         {
3948             return !(vd.storage_class & (STC.manifest | STC.static_));
3949         }
3950         return false;
3951     }
3952 
3953     override void accept(Visitor v)
3954     {
3955         v.visit(this);
3956     }
3957 }
3958 
3959 /***********************************************************
3960  * typeid(int)
3961  */
3962 extern (C++) final class TypeidExp : Expression
3963 {
3964     RootObject obj;
3965 
3966     extern (D) this(const ref Loc loc, RootObject o)
3967     {
3968         super(loc, TOK.typeid_, __traits(classInstanceSize, TypeidExp));
3969         this.obj = o;
3970     }
3971 
3972     override Expression syntaxCopy()
3973     {
3974         return new TypeidExp(loc, objectSyntaxCopy(obj));
3975     }
3976 
3977     override void accept(Visitor v)
3978     {
3979         v.visit(this);
3980     }
3981 }
3982 
3983 /***********************************************************
3984  * __traits(identifier, args...)
3985  */
3986 extern (C++) final class TraitsExp : Expression
3987 {
3988     Identifier ident;
3989     Objects* args;
3990 
3991     extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
3992     {
3993         super(loc, TOK.traits, __traits(classInstanceSize, TraitsExp));
3994         this.ident = ident;
3995         this.args = args;
3996     }
3997 
3998     override Expression syntaxCopy()
3999     {
4000         return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
4001     }
4002 
4003     override void accept(Visitor v)
4004     {
4005         v.visit(this);
4006     }
4007 }
4008 
4009 /***********************************************************
4010  */
4011 extern (C++) final class HaltExp : Expression
4012 {
4013     extern (D) this(const ref Loc loc)
4014     {
4015         super(loc, TOK.halt, __traits(classInstanceSize, HaltExp));
4016     }
4017 
4018     override void accept(Visitor v)
4019     {
4020         v.visit(this);
4021     }
4022 }
4023 
4024 /***********************************************************
4025  * is(targ id tok tspec)
4026  * is(targ id == tok2)
4027  */
4028 extern (C++) final class IsExp : Expression
4029 {
4030     Type targ;
4031     Identifier id;      // can be null
4032     Type tspec;         // can be null
4033     TemplateParameters* parameters;
4034     TOK tok;            // ':' or '=='
4035     TOK tok2;           // 'struct', 'union', etc.
4036 
4037     extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
4038     {
4039         super(loc, TOK.is_, __traits(classInstanceSize, IsExp));
4040         this.targ = targ;
4041         this.id = id;
4042         this.tok = tok;
4043         this.tspec = tspec;
4044         this.tok2 = tok2;
4045         this.parameters = parameters;
4046     }
4047 
4048     override Expression syntaxCopy()
4049     {
4050         // This section is identical to that in TemplateDeclaration::syntaxCopy()
4051         TemplateParameters* p = null;
4052         if (parameters)
4053         {
4054             p = new TemplateParameters(parameters.dim);
4055             foreach (i, el; *parameters)
4056                 (*p)[i] = el.syntaxCopy();
4057         }
4058         return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
4059     }
4060 
4061     override void accept(Visitor v)
4062     {
4063         v.visit(this);
4064     }
4065 }
4066 
4067 /***********************************************************
4068  */
4069 extern (C++) abstract class UnaExp : Expression
4070 {
4071     Expression e1;
4072     Type att1;      // Save alias this type to detect recursion
4073 
4074     extern (D) this(const ref Loc loc, TOK op, int size, Expression e1)
4075     {
4076         super(loc, op, size);
4077         this.e1 = e1;
4078     }
4079 
4080     override Expression syntaxCopy()
4081     {
4082         UnaExp e = cast(UnaExp)copy();
4083         e.type = null;
4084         e.e1 = e.e1.syntaxCopy();
4085         return e;
4086     }
4087 
4088     /********************************
4089      * The type for a unary expression is incompatible.
4090      * Print error message.
4091      * Returns:
4092      *  ErrorExp
4093      */
4094     final Expression incompatibleTypes()
4095     {
4096         if (e1.type.toBasetype() == Type.terror)
4097             return e1;
4098 
4099         if (e1.op == TOK.type)
4100         {
4101             error("incompatible type for `%s(%s)`: cannot use `%s` with types", Token.toChars(op), e1.toChars(), Token.toChars(op));
4102         }
4103         else
4104         {
4105             error("incompatible type for `%s(%s)`: `%s`", Token.toChars(op), e1.toChars(), e1.type.toChars());
4106         }
4107         return new ErrorExp();
4108     }
4109 
4110     /*********************
4111      * Mark the operand as will never be dereferenced,
4112      * which is useful info for @safe checks.
4113      * Do before semantic() on operands rewrites them.
4114      */
4115     final void setNoderefOperand()
4116     {
4117         if (auto edi = e1.isDotIdExp())
4118             edi.noderef = true;
4119 
4120     }
4121 
4122     override final Expression resolveLoc(const ref Loc loc, Scope* sc)
4123     {
4124         e1 = e1.resolveLoc(loc, sc);
4125         return this;
4126     }
4127 
4128     override void accept(Visitor v)
4129     {
4130         v.visit(this);
4131     }
4132 }
4133 
4134 alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
4135 alias fp2_t = bool function(const ref Loc loc, TOK, Expression, Expression);
4136 
4137 /***********************************************************
4138  */
4139 extern (C++) abstract class BinExp : Expression
4140 {
4141     Expression e1;
4142     Expression e2;
4143     Type att1;      // Save alias this type to detect recursion
4144     Type att2;      // Save alias this type to detect recursion
4145 
4146     extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
4147     {
4148         super(loc, op, size);
4149         this.e1 = e1;
4150         this.e2 = e2;
4151     }
4152 
4153     override Expression syntaxCopy()
4154     {
4155         BinExp e = cast(BinExp)copy();
4156         e.type = null;
4157         e.e1 = e.e1.syntaxCopy();
4158         e.e2 = e.e2.syntaxCopy();
4159         return e;
4160     }
4161 
4162     /********************************
4163      * The types for a binary expression are incompatible.
4164      * Print error message.
4165      * Returns:
4166      *  ErrorExp
4167      */
4168     final Expression incompatibleTypes()
4169     {
4170         if (e1.type.toBasetype() == Type.terror)
4171             return e1;
4172         if (e2.type.toBasetype() == Type.terror)
4173             return e2;
4174 
4175         // CondExp uses 'a ? b : c' but we're comparing 'b : c'
4176         TOK thisOp = (op == TOK.question) ? TOK.colon : op;
4177         if (e1.op == TOK.type || e2.op == TOK.type)
4178         {
4179             error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
4180                 e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op));
4181         }
4182         else if (e1.type.equals(e2.type))
4183         {
4184             error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
4185                 e1.toChars(), Token.toChars(thisOp), e2.toChars(), e1.type.toChars());
4186         }
4187         else
4188         {
4189             auto ts = toAutoQualChars(e1.type, e2.type);
4190             error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
4191                 e1.toChars(), Token.toChars(thisOp), e2.toChars(), ts[0], ts[1]);
4192         }
4193         return new ErrorExp();
4194     }
4195 
4196     extern (D) final Expression checkOpAssignTypes(Scope* sc)
4197     {
4198         // At that point t1 and t2 are the merged types. type is the original type of the lhs.
4199         Type t1 = e1.type;
4200         Type t2 = e2.type;
4201 
4202         // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
4203         // See issue 3841.
4204         // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
4205         if (op == TOK.addAssign || op == TOK.minAssign ||
4206             op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign ||
4207             op == TOK.powAssign)
4208         {
4209             if ((type.isintegral() && t2.isfloating()))
4210             {
4211                 warning("`%s %s %s` is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars());
4212             }
4213         }
4214 
4215         // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
4216         if (op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign)
4217         {
4218             // Any multiplication by an imaginary or complex number yields a complex result.
4219             // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
4220             const(char)* opstr = Token.toChars(op);
4221             if (t1.isreal() && t2.iscomplex())
4222             {
4223                 error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4224                 return new ErrorExp();
4225             }
4226             else if (t1.isimaginary() && t2.iscomplex())
4227             {
4228                 error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4229                 return new ErrorExp();
4230             }
4231             else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
4232             {
4233                 error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
4234                 return new ErrorExp();
4235             }
4236         }
4237 
4238         // generate an error if this is a nonsensical += or -=, eg real += imaginary
4239         if (op == TOK.addAssign || op == TOK.minAssign)
4240         {
4241             // Addition or subtraction of a real and an imaginary is a complex result.
4242             // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
4243             if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
4244             {
4245                 error("`%s %s %s` is undefined (result is complex)", t1.toChars(), Token.toChars(op), t2.toChars());
4246                 return new ErrorExp();
4247             }
4248             if (type.isreal() || type.isimaginary())
4249             {
4250                 assert(global.errors || t2.isfloating());
4251                 e2 = e2.castTo(sc, t1);
4252             }
4253         }
4254         if (op == TOK.mulAssign)
4255         {
4256             if (t2.isfloating())
4257             {
4258                 if (t1.isreal())
4259                 {
4260                     if (t2.isimaginary() || t2.iscomplex())
4261                     {
4262                         e2 = e2.castTo(sc, t1);
4263                     }
4264                 }
4265                 else if (t1.isimaginary())
4266                 {
4267                     if (t2.isimaginary() || t2.iscomplex())
4268                     {
4269                         switch (t1.ty)
4270                         {
4271                         case Timaginary32:
4272                             t2 = Type.tfloat32;
4273                             break;
4274 
4275                         case Timaginary64:
4276                             t2 = Type.tfloat64;
4277                             break;
4278 
4279                         case Timaginary80:
4280                             t2 = Type.tfloat80;
4281                             break;
4282 
4283                         default:
4284                             assert(0);
4285                         }
4286                         e2 = e2.castTo(sc, t2);
4287                     }
4288                 }
4289             }
4290         }
4291         else if (op == TOK.divAssign)
4292         {
4293             if (t2.isimaginary())
4294             {
4295                 if (t1.isreal())
4296                 {
4297                     // x/iv = i(-x/v)
4298                     // Therefore, the result is 0
4299                     e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
4300                     e2.type = t1;
4301                     Expression e = new AssignExp(loc, e1, e2);
4302                     e.type = t1;
4303                     return e;
4304                 }
4305                 else if (t1.isimaginary())
4306                 {
4307                     Type t3;
4308                     switch (t1.ty)
4309                     {
4310                     case Timaginary32:
4311                         t3 = Type.tfloat32;
4312                         break;
4313 
4314                     case Timaginary64:
4315                         t3 = Type.tfloat64;
4316                         break;
4317 
4318                     case Timaginary80:
4319                         t3 = Type.tfloat80;
4320                         break;
4321 
4322                     default:
4323                         assert(0);
4324                     }
4325                     e2 = e2.castTo(sc, t3);
4326                     Expression e = new AssignExp(loc, e1, e2);
4327                     e.type = t1;
4328                     return e;
4329                 }
4330             }
4331         }
4332         else if (op == TOK.modAssign)
4333         {
4334             if (t2.iscomplex())
4335             {
4336                 error("cannot perform modulo complex arithmetic");
4337                 return new ErrorExp();
4338             }
4339         }
4340         return this;
4341     }
4342 
4343     extern (D) final bool checkIntegralBin()
4344     {
4345         bool r1 = e1.checkIntegral();
4346         bool r2 = e2.checkIntegral();
4347         return (r1 || r2);
4348     }
4349 
4350     extern (D) final bool checkArithmeticBin()
4351     {
4352         bool r1 = e1.checkArithmetic();
4353         bool r2 = e2.checkArithmetic();
4354         return (r1 || r2);
4355     }
4356 
4357     extern (D) final bool checkSharedAccessBin(Scope* sc)
4358     {
4359         const r1 = e1.checkSharedAccess(sc);
4360         const r2 = e2.checkSharedAccess(sc);
4361         return (r1 || r2);
4362     }
4363 
4364     /*********************
4365      * Mark the operands as will never be dereferenced,
4366      * which is useful info for @safe checks.
4367      * Do before semantic() on operands rewrites them.
4368      */
4369     final void setNoderefOperands()
4370     {
4371         if (auto edi = e1.isDotIdExp())
4372             edi.noderef = true;
4373         if (auto edi = e2.isDotIdExp())
4374             edi.noderef = true;
4375 
4376     }
4377 
4378     final Expression reorderSettingAAElem(Scope* sc)
4379     {
4380         BinExp be = this;
4381 
4382         auto ie = be.e1.isIndexExp();
4383         if (!ie)
4384             return be;
4385         if (ie.e1.type.toBasetype().ty != Taarray)
4386             return be;
4387 
4388         /* Fix evaluation order of setting AA element
4389          * https://issues.dlang.org/show_bug.cgi?id=3825
4390          * Rewrite:
4391          *     aa[k1][k2][k3] op= val;
4392          * as:
4393          *     auto ref __aatmp = aa;
4394          *     auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
4395          *     auto ref __aaval = val;
4396          *     __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval;  // assignment
4397          */
4398 
4399         Expression e0;
4400         while (1)
4401         {
4402             Expression de;
4403             ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
4404             e0 = Expression.combine(de, e0);
4405 
4406             auto ie1 = ie.e1.isIndexExp();
4407             if (!ie1 ||
4408                 ie1.e1.type.toBasetype().ty != Taarray)
4409             {
4410                 break;
4411             }
4412             ie = ie1;
4413         }
4414         assert(ie.e1.type.toBasetype().ty == Taarray);
4415 
4416         Expression de;
4417         ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
4418         e0 = Expression.combine(de, e0);
4419 
4420         be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
4421 
4422         //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
4423         return Expression.combine(e0, be);
4424     }
4425 
4426     override void accept(Visitor v)
4427     {
4428         v.visit(this);
4429     }
4430 }
4431 
4432 /***********************************************************
4433  */
4434 extern (C++) class BinAssignExp : BinExp
4435 {
4436     extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
4437     {
4438         super(loc, op, size, e1, e2);
4439     }
4440 
4441     override final bool isLvalue()
4442     {
4443         return true;
4444     }
4445 
4446     override final Expression toLvalue(Scope* sc, Expression ex)
4447     {
4448         // Lvalue-ness will be handled in glue layer.
4449         return this;
4450     }
4451 
4452     override final Expression modifiableLvalue(Scope* sc, Expression e)
4453     {
4454         // should check e1.checkModifiable() ?
4455         return toLvalue(sc, this);
4456     }
4457 
4458     override void accept(Visitor v)
4459     {
4460         v.visit(this);
4461     }
4462 }
4463 
4464 /***********************************************************
4465  * https://dlang.org/spec/expression.html#mixin_expressions
4466  */
4467 extern (C++) final class CompileExp : Expression
4468 {
4469     Expressions* exps;
4470 
4471     extern (D) this(const ref Loc loc, Expressions* exps)
4472     {
4473         super(loc, TOK.mixin_, __traits(classInstanceSize, CompileExp));
4474         this.exps = exps;
4475     }
4476 
4477     override Expression syntaxCopy()
4478     {
4479         return new CompileExp(loc, arraySyntaxCopy(exps));
4480     }
4481 
4482     override bool equals(const RootObject o) const
4483     {
4484         if (this == o)
4485             return true;
4486         auto e = o.isExpression();
4487         if (!e)
4488             return false;
4489         if (auto ce = e.isCompileExp())
4490         {
4491             if (exps.dim != ce.exps.dim)
4492                 return false;
4493             foreach (i, e1; *exps)
4494             {
4495                 auto e2 = (*ce.exps)[i];
4496                 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
4497                     return false;
4498             }
4499             return true;
4500         }
4501         return false;
4502     }
4503 
4504     override void accept(Visitor v)
4505     {
4506         v.visit(this);
4507     }
4508 }
4509 
4510 /***********************************************************
4511  */
4512 extern (C++) final class ImportExp : UnaExp
4513 {
4514     extern (D) this(const ref Loc loc, Expression e)
4515     {
4516         super(loc, TOK.import_, __traits(classInstanceSize, ImportExp), e);
4517     }
4518 
4519     override void accept(Visitor v)
4520     {
4521         v.visit(this);
4522     }
4523 }
4524 
4525 /***********************************************************
4526  * https://dlang.org/spec/expression.html#assert_expressions
4527  */
4528 extern (C++) final class AssertExp : UnaExp
4529 {
4530     Expression msg;
4531 
4532     extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
4533     {
4534         super(loc, TOK.assert_, __traits(classInstanceSize, AssertExp), e);
4535         this.msg = msg;
4536     }
4537 
4538     override Expression syntaxCopy()
4539     {
4540         return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
4541     }
4542 
4543     override void accept(Visitor v)
4544     {
4545         v.visit(this);
4546     }
4547 }
4548 
4549 /***********************************************************
4550  */
4551 extern (C++) final class DotIdExp : UnaExp
4552 {
4553     Identifier ident;
4554     bool noderef;       // true if the result of the expression will never be dereferenced
4555     bool wantsym;       // do not replace Symbol with its initializer during semantic()
4556 
4557     extern (D) this(const ref Loc loc, Expression e, Identifier ident)
4558     {
4559         super(loc, TOK.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
4560         this.ident = ident;
4561     }
4562 
4563     static DotIdExp create(Loc loc, Expression e, Identifier ident)
4564     {
4565         return new DotIdExp(loc, e, ident);
4566     }
4567 
4568     override void accept(Visitor v)
4569     {
4570         v.visit(this);
4571     }
4572 }
4573 
4574 /***********************************************************
4575  * Mainly just a placeholder
4576  */
4577 extern (C++) final class DotTemplateExp : UnaExp
4578 {
4579     TemplateDeclaration td;
4580 
4581     extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
4582     {
4583         super(loc, TOK.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
4584         this.td = td;
4585     }
4586 
4587     override void accept(Visitor v)
4588     {
4589         v.visit(this);
4590     }
4591 }
4592 
4593 /***********************************************************
4594  */
4595 extern (C++) final class DotVarExp : UnaExp
4596 {
4597     Declaration var;
4598     bool hasOverloads;
4599 
4600     extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true)
4601     {
4602         if (var.isVarDeclaration())
4603             hasOverloads = false;
4604 
4605         super(loc, TOK.dotVariable, __traits(classInstanceSize, DotVarExp), e);
4606         //printf("DotVarExp()\n");
4607         this.var = var;
4608         this.hasOverloads = hasOverloads;
4609     }
4610 
4611     override Modifiable checkModifiable(Scope* sc, int flag)
4612     {
4613         //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type.toChars());
4614         if (checkUnsafeAccess(sc, this, false, !flag))
4615             return Modifiable.initialization;
4616 
4617         if (e1.op == TOK.this_)
4618             return var.checkModify(loc, sc, e1, flag);
4619 
4620         /* https://issues.dlang.org/show_bug.cgi?id=12764
4621          * If inside a constructor and an expression of type `this.field.var`
4622          * is encountered, where `field` is a struct declaration with
4623          * default construction disabled, we must make sure that
4624          * assigning to `var` does not imply that `field` was initialized
4625          */
4626         if (sc.func && sc.func.isCtorDeclaration())
4627         {
4628             // if inside a constructor scope and e1 of this DotVarExp
4629             // is a DotVarExp, then check if e1.e1 is a `this` identifier
4630             if (auto dve = e1.isDotVarExp())
4631             {
4632                 if (dve.e1.op == TOK.this_)
4633                 {
4634                     scope v = dve.var.isVarDeclaration();
4635                     /* if v is a struct member field with no initializer, no default construction
4636                      * and v wasn't intialized before
4637                      */
4638                     if (v && v.isField() && !v._init && !v.ctorinit)
4639                     {
4640                         if (auto ts = v.type.isTypeStruct())
4641                         {
4642                             if (ts.sym.noDefaultCtor)
4643                             {
4644                                 /* checkModify will consider that this is an initialization
4645                                  * of v while it is actually an assignment of a field of v
4646                                  */
4647                                 scope modifyLevel = v.checkModify(loc, sc, dve.e1, flag);
4648                                 // reflect that assigning a field of v is not initialization of v
4649                                 v.ctorinit = false;
4650                                 if (modifyLevel == Modifiable.initialization)
4651                                     return Modifiable.yes;
4652                                 return modifyLevel;
4653                             }
4654                         }
4655                     }
4656                 }
4657             }
4658         }
4659 
4660         //printf("\te1 = %s\n", e1.toChars());
4661         return e1.checkModifiable(sc, flag);
4662     }
4663 
4664     override bool isLvalue()
4665     {
4666         return true;
4667     }
4668 
4669     override Expression toLvalue(Scope* sc, Expression e)
4670     {
4671         //printf("DotVarExp::toLvalue(%s)\n", toChars());
4672         if (e1.op == TOK.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
4673         {
4674             if (VarDeclaration vd = var.isVarDeclaration())
4675             {
4676                 auto ad = vd.isMember2();
4677                 if (ad && ad.fields.dim == sc.ctorflow.fieldinit.length)
4678                 {
4679                     foreach (i, f; ad.fields)
4680                     {
4681                         if (f == vd)
4682                         {
4683                             if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
4684                             {
4685                                 /* If the address of vd is taken, assume it is thereby initialized
4686                                  * https://issues.dlang.org/show_bug.cgi?id=15869
4687                                  */
4688                                 modifyFieldVar(loc, sc, vd, e1);
4689                             }
4690                             break;
4691                         }
4692                     }
4693                 }
4694             }
4695         }
4696         return this;
4697     }
4698 
4699     override Expression modifiableLvalue(Scope* sc, Expression e)
4700     {
4701         version (none)
4702         {
4703             printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
4704             printf("e1.type = %s\n", e1.type.toChars());
4705             printf("var.type = %s\n", var.type.toChars());
4706         }
4707 
4708         return Expression.modifiableLvalue(sc, e);
4709     }
4710 
4711     override void accept(Visitor v)
4712     {
4713         v.visit(this);
4714     }
4715 }
4716 
4717 /***********************************************************
4718  * foo.bar!(args)
4719  */
4720 extern (C++) final class DotTemplateInstanceExp : UnaExp
4721 {
4722     TemplateInstance ti;
4723 
4724     extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
4725     {
4726         super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
4727         //printf("DotTemplateInstanceExp()\n");
4728         this.ti = new TemplateInstance(loc, name, tiargs);
4729     }
4730 
4731     extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
4732     {
4733         super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
4734         this.ti = ti;
4735     }
4736 
4737     override Expression syntaxCopy()
4738     {
4739         return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
4740     }
4741 
4742     bool findTempDecl(Scope* sc)
4743     {
4744         static if (LOGSEMANTIC)
4745         {
4746             printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
4747         }
4748         if (ti.tempdecl)
4749             return true;
4750 
4751         Expression e = new DotIdExp(loc, e1, ti.name);
4752         e = e.expressionSemantic(sc);
4753         if (e.op == TOK.dot)
4754             e = (cast(DotExp)e).e2;
4755 
4756         Dsymbol s = null;
4757         switch (e.op)
4758         {
4759         case TOK.overloadSet:
4760             s = (cast(OverExp)e).vars;
4761             break;
4762 
4763         case TOK.dotTemplateDeclaration:
4764             s = (cast(DotTemplateExp)e).td;
4765             break;
4766 
4767         case TOK.scope_:
4768             s = (cast(ScopeExp)e).sds;
4769             break;
4770 
4771         case TOK.dotVariable:
4772             s = (cast(DotVarExp)e).var;
4773             break;
4774 
4775         case TOK.variable:
4776             s = (cast(VarExp)e).var;
4777             break;
4778 
4779         default:
4780             return false;
4781         }
4782         return ti.updateTempDecl(sc, s);
4783     }
4784 
4785     override void accept(Visitor v)
4786     {
4787         v.visit(this);
4788     }
4789 }
4790 
4791 /***********************************************************
4792  */
4793 extern (C++) final class DelegateExp : UnaExp
4794 {
4795     FuncDeclaration func;
4796     bool hasOverloads;
4797     VarDeclaration vthis2;  // container for multi-context
4798 
4799     extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
4800     {
4801         super(loc, TOK.delegate_, __traits(classInstanceSize, DelegateExp), e);
4802         this.func = f;
4803         this.hasOverloads = hasOverloads;
4804         this.vthis2 = vthis2;
4805     }
4806 
4807     override void accept(Visitor v)
4808     {
4809         v.visit(this);
4810     }
4811 }
4812 
4813 /***********************************************************
4814  */
4815 extern (C++) final class DotTypeExp : UnaExp
4816 {
4817     Dsymbol sym;        // symbol that represents a type
4818 
4819     extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
4820     {
4821         super(loc, TOK.dotType, __traits(classInstanceSize, DotTypeExp), e);
4822         this.sym = s;
4823     }
4824 
4825     override void accept(Visitor v)
4826     {
4827         v.visit(this);
4828     }
4829 }
4830 
4831 /***********************************************************
4832  */
4833 extern (C++) final class CallExp : UnaExp
4834 {
4835     Expressions* arguments; // function arguments
4836     FuncDeclaration f;      // symbol to call
4837     bool directcall;        // true if a virtual call is devirtualized
4838     VarDeclaration vthis2;  // container for multi-context
4839 
4840     extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
4841     {
4842         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
4843         this.arguments = exps;
4844     }
4845 
4846     extern (D) this(const ref Loc loc, Expression e)
4847     {
4848         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
4849     }
4850 
4851     extern (D) this(const ref Loc loc, Expression e, Expression earg1)
4852     {
4853         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
4854         this.arguments = new Expressions();
4855         if (earg1)
4856             this.arguments.push(earg1);
4857     }
4858 
4859     extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
4860     {
4861         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
4862         auto arguments = new Expressions(2);
4863         (*arguments)[0] = earg1;
4864         (*arguments)[1] = earg2;
4865         this.arguments = arguments;
4866     }
4867 
4868     /***********************************************************
4869     * Instatiates a new function call expression
4870     * Params:
4871     *       loc   = location
4872     *       fd    = the declaration of the function to call
4873     *       earg1 = the function argument
4874     */
4875     extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
4876     {
4877         this(loc, new VarExp(loc, fd, false), earg1);
4878         this.f = fd;
4879     }
4880 
4881     static CallExp create(Loc loc, Expression e, Expressions* exps)
4882     {
4883         return new CallExp(loc, e, exps);
4884     }
4885 
4886     static CallExp create(Loc loc, Expression e)
4887     {
4888         return new CallExp(loc, e);
4889     }
4890 
4891     static CallExp create(Loc loc, Expression e, Expression earg1)
4892     {
4893         return new CallExp(loc, e, earg1);
4894     }
4895 
4896     /***********************************************************
4897     * Creates a new function call expression
4898     * Params:
4899     *       loc   = location
4900     *       fd    = the declaration of the function to call
4901     *       earg1 = the function argument
4902     */
4903     static CallExp create(Loc loc, FuncDeclaration fd, Expression earg1)
4904     {
4905         return new CallExp(loc, fd, earg1);
4906     }
4907 
4908     override Expression syntaxCopy()
4909     {
4910         return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
4911     }
4912 
4913     override bool isLvalue()
4914     {
4915         Type tb = e1.type.toBasetype();
4916         if (tb.ty == Tdelegate || tb.ty == Tpointer)
4917             tb = tb.nextOf();
4918         auto tf = tb.isTypeFunction();
4919         if (tf && tf.isref)
4920         {
4921             if (auto dve = e1.isDotVarExp())
4922                 if (dve.var.isCtorDeclaration())
4923                     return false;
4924             return true; // function returns a reference
4925         }
4926         return false;
4927     }
4928 
4929     override Expression toLvalue(Scope* sc, Expression e)
4930     {
4931         if (isLvalue())
4932             return this;
4933         return Expression.toLvalue(sc, e);
4934     }
4935 
4936     override Expression addDtorHook(Scope* sc)
4937     {
4938         /* Only need to add dtor hook if it's a type that needs destruction.
4939          * Use same logic as VarDeclaration::callScopeDtor()
4940          */
4941 
4942         if (auto tf = e1.type.isTypeFunction())
4943         {
4944             if (tf.isref)
4945                 return this;
4946         }
4947 
4948         Type tv = type.baseElemOf();
4949         if (auto ts = tv.isTypeStruct())
4950         {
4951             StructDeclaration sd = ts.sym;
4952             if (sd.dtor)
4953             {
4954                 /* Type needs destruction, so declare a tmp
4955                  * which the back end will recognize and call dtor on
4956                  */
4957                 auto tmp = copyToTemp(0, "__tmpfordtor", this);
4958                 auto de = new DeclarationExp(loc, tmp);
4959                 auto ve = new VarExp(loc, tmp);
4960                 Expression e = new CommaExp(loc, de, ve);
4961                 e = e.expressionSemantic(sc);
4962                 return e;
4963             }
4964         }
4965         return this;
4966     }
4967 
4968     override void accept(Visitor v)
4969     {
4970         v.visit(this);
4971     }
4972 }
4973 
4974 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null)
4975 {
4976     if (auto ae = e.isAddrExp())
4977     {
4978         auto ae1 = ae.e1;
4979         if (auto ve = ae1.isVarExp())
4980         {
4981             if (hasOverloads)
4982                 *hasOverloads = ve.hasOverloads;
4983             return ve.var.isFuncDeclaration();
4984         }
4985         if (auto dve = ae1.isDotVarExp())
4986         {
4987             if (hasOverloads)
4988                 *hasOverloads = dve.hasOverloads;
4989             return dve.var.isFuncDeclaration();
4990         }
4991     }
4992     else
4993     {
4994         if (auto soe = e.isSymOffExp())
4995         {
4996             if (hasOverloads)
4997                 *hasOverloads = soe.hasOverloads;
4998             return soe.var.isFuncDeclaration();
4999         }
5000         if (auto dge = e.isDelegateExp())
5001         {
5002             if (hasOverloads)
5003                 *hasOverloads = dge.hasOverloads;
5004             return dge.func.isFuncDeclaration();
5005         }
5006     }
5007     return null;
5008 }
5009 
5010 /***********************************************************
5011  */
5012 extern (C++) final class AddrExp : UnaExp
5013 {
5014     extern (D) this(const ref Loc loc, Expression e)
5015     {
5016         super(loc, TOK.address, __traits(classInstanceSize, AddrExp), e);
5017     }
5018 
5019     extern (D) this(const ref Loc loc, Expression e, Type t)
5020     {
5021         this(loc, e);
5022         type = t;
5023     }
5024 
5025     override void accept(Visitor v)
5026     {
5027         v.visit(this);
5028     }
5029 }
5030 
5031 /***********************************************************
5032  */
5033 extern (C++) final class PtrExp : UnaExp
5034 {
5035     extern (D) this(const ref Loc loc, Expression e)
5036     {
5037         super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
5038         //if (e.type)
5039         //  type = ((TypePointer *)e.type).next;
5040     }
5041 
5042     extern (D) this(const ref Loc loc, Expression e, Type t)
5043     {
5044         super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
5045         type = t;
5046     }
5047 
5048     override Modifiable checkModifiable(Scope* sc, int flag)
5049     {
5050         if (auto se = e1.isSymOffExp())
5051         {
5052             return se.var.checkModify(loc, sc, null, flag);
5053         }
5054         else if (auto ae = e1.isAddrExp())
5055         {
5056             return ae.e1.checkModifiable(sc, flag);
5057         }
5058         return Modifiable.yes;
5059     }
5060 
5061     override bool isLvalue()
5062     {
5063         return true;
5064     }
5065 
5066     override Expression toLvalue(Scope* sc, Expression e)
5067     {
5068         return this;
5069     }
5070 
5071     override Expression modifiableLvalue(Scope* sc, Expression e)
5072     {
5073         //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
5074         return Expression.modifiableLvalue(sc, e);
5075     }
5076 
5077     override void accept(Visitor v)
5078     {
5079         v.visit(this);
5080     }
5081 }
5082 
5083 /***********************************************************
5084  */
5085 extern (C++) final class NegExp : UnaExp
5086 {
5087     extern (D) this(const ref Loc loc, Expression e)
5088     {
5089         super(loc, TOK.negate, __traits(classInstanceSize, NegExp), e);
5090     }
5091 
5092     override void accept(Visitor v)
5093     {
5094         v.visit(this);
5095     }
5096 }
5097 
5098 /***********************************************************
5099  */
5100 extern (C++) final class UAddExp : UnaExp
5101 {
5102     extern (D) this(const ref Loc loc, Expression e)
5103     {
5104         super(loc, TOK.uadd, __traits(classInstanceSize, UAddExp), e);
5105     }
5106 
5107     override void accept(Visitor v)
5108     {
5109         v.visit(this);
5110     }
5111 }
5112 
5113 /***********************************************************
5114  */
5115 extern (C++) final class ComExp : UnaExp
5116 {
5117     extern (D) this(const ref Loc loc, Expression e)
5118     {
5119         super(loc, TOK.tilde, __traits(classInstanceSize, ComExp), e);
5120     }
5121 
5122     override void accept(Visitor v)
5123     {
5124         v.visit(this);
5125     }
5126 }
5127 
5128 /***********************************************************
5129  */
5130 extern (C++) final class NotExp : UnaExp
5131 {
5132     extern (D) this(const ref Loc loc, Expression e)
5133     {
5134         super(loc, TOK.not, __traits(classInstanceSize, NotExp), e);
5135     }
5136 
5137     override void accept(Visitor v)
5138     {
5139         v.visit(this);
5140     }
5141 }
5142 
5143 /***********************************************************
5144  */
5145 extern (C++) final class DeleteExp : UnaExp
5146 {
5147     bool isRAII;        // true if called automatically as a result of scoped destruction
5148 
5149     extern (D) this(const ref Loc loc, Expression e, bool isRAII)
5150     {
5151         super(loc, TOK.delete_, __traits(classInstanceSize, DeleteExp), e);
5152         this.isRAII = isRAII;
5153     }
5154 
5155     override Expression toBoolean(Scope* sc)
5156     {
5157         error("`delete` does not give a boolean result");
5158         return new ErrorExp();
5159     }
5160 
5161     override void accept(Visitor v)
5162     {
5163         v.visit(this);
5164     }
5165 }
5166 
5167 /***********************************************************
5168  * Possible to cast to one type while painting to another type
5169  */
5170 extern (C++) final class CastExp : UnaExp
5171 {
5172     Type to;                    // type to cast to
5173     ubyte mod = cast(ubyte)~0;  // MODxxxxx
5174 
5175     extern (D) this(const ref Loc loc, Expression e, Type t)
5176     {
5177         super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
5178         this.to = t;
5179     }
5180 
5181     /* For cast(const) and cast(immutable)
5182      */
5183     extern (D) this(const ref Loc loc, Expression e, ubyte mod)
5184     {
5185         super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
5186         this.mod = mod;
5187     }
5188 
5189     override Expression syntaxCopy()
5190     {
5191         return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
5192     }
5193 
5194     override Expression addDtorHook(Scope* sc)
5195     {
5196         if (to.toBasetype().ty == Tvoid)        // look past the cast(void)
5197             e1 = e1.addDtorHook(sc);
5198         return this;
5199     }
5200 
5201     override void accept(Visitor v)
5202     {
5203         v.visit(this);
5204     }
5205 }
5206 
5207 /***********************************************************
5208  */
5209 extern (C++) final class VectorExp : UnaExp
5210 {
5211     TypeVector to;      // the target vector type before semantic()
5212     uint dim = ~0;      // number of elements in the vector
5213     OwnedBy ownedByCtfe = OwnedBy.code;
5214 
5215     extern (D) this(const ref Loc loc, Expression e, Type t)
5216     {
5217         super(loc, TOK.vector, __traits(classInstanceSize, VectorExp), e);
5218         assert(t.ty == Tvector);
5219         to = cast(TypeVector)t;
5220     }
5221 
5222     static VectorExp create(Loc loc, Expression e, Type t)
5223     {
5224         return new VectorExp(loc, e, t);
5225     }
5226 
5227     // Same as create, but doesn't allocate memory.
5228     static void emplace(UnionExp* pue, Loc loc, Expression e, Type type)
5229     {
5230         emplaceExp!(VectorExp)(pue, loc, e, type);
5231     }
5232 
5233     override Expression syntaxCopy()
5234     {
5235         return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
5236     }
5237 
5238     override void accept(Visitor v)
5239     {
5240         v.visit(this);
5241     }
5242 }
5243 
5244 /***********************************************************
5245  * e1.array property for vectors.
5246  *
5247  * https://dlang.org/spec/simd.html#properties
5248  */
5249 extern (C++) final class VectorArrayExp : UnaExp
5250 {
5251     extern (D) this(const ref Loc loc, Expression e1)
5252     {
5253         super(loc, TOK.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
5254     }
5255 
5256     override bool isLvalue()
5257     {
5258         return e1.isLvalue();
5259     }
5260 
5261     override Expression toLvalue(Scope* sc, Expression e)
5262     {
5263         e1 = e1.toLvalue(sc, e);
5264         return this;
5265     }
5266 
5267     override void accept(Visitor v)
5268     {
5269         v.visit(this);
5270     }
5271 }
5272 
5273 /***********************************************************
5274  * e1 [lwr .. upr]
5275  *
5276  * http://dlang.org/spec/expression.html#slice_expressions
5277  */
5278 extern (C++) final class SliceExp : UnaExp
5279 {
5280     Expression upr;             // null if implicit 0
5281     Expression lwr;             // null if implicit [length - 1]
5282 
5283     VarDeclaration lengthVar;
5284     bool upperIsInBounds;       // true if upr <= e1.length
5285     bool lowerIsLessThanUpper;  // true if lwr <= upr
5286     bool arrayop;               // an array operation, rather than a slice
5287 
5288     /************************************************************/
5289     extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
5290     {
5291         super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
5292         this.upr = ie ? ie.upr : null;
5293         this.lwr = ie ? ie.lwr : null;
5294     }
5295 
5296     extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
5297     {
5298         super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
5299         this.upr = upr;
5300         this.lwr = lwr;
5301     }
5302 
5303     override Expression syntaxCopy()
5304     {
5305         auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
5306         se.lengthVar = this.lengthVar; // bug7871
5307         return se;
5308     }
5309 
5310     override Modifiable checkModifiable(Scope* sc, int flag)
5311     {
5312         //printf("SliceExp::checkModifiable %s\n", toChars());
5313         if (e1.type.ty == Tsarray || (e1.op == TOK.index && e1.type.ty != Tarray) || e1.op == TOK.slice)
5314         {
5315             return e1.checkModifiable(sc, flag);
5316         }
5317         return Modifiable.yes;
5318     }
5319 
5320     override bool isLvalue()
5321     {
5322         /* slice expression is rvalue in default, but
5323          * conversion to reference of static array is only allowed.
5324          */
5325         return (type && type.toBasetype().ty == Tsarray);
5326     }
5327 
5328     override Expression toLvalue(Scope* sc, Expression e)
5329     {
5330         //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
5331         return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
5332     }
5333 
5334     override Expression modifiableLvalue(Scope* sc, Expression e)
5335     {
5336         error("slice expression `%s` is not a modifiable lvalue", toChars());
5337         return this;
5338     }
5339 
5340     override bool isBool(bool result)
5341     {
5342         return e1.isBool(result);
5343     }
5344 
5345     override void accept(Visitor v)
5346     {
5347         v.visit(this);
5348     }
5349 }
5350 
5351 /***********************************************************
5352  */
5353 extern (C++) final class ArrayLengthExp : UnaExp
5354 {
5355     extern (D) this(const ref Loc loc, Expression e1)
5356     {
5357         super(loc, TOK.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
5358     }
5359 
5360     override void accept(Visitor v)
5361     {
5362         v.visit(this);
5363     }
5364 }
5365 
5366 /***********************************************************
5367  * e1 [ a0, a1, a2, a3 ,... ]
5368  *
5369  * http://dlang.org/spec/expression.html#index_expressions
5370  */
5371 extern (C++) final class ArrayExp : UnaExp
5372 {
5373     Expressions* arguments;     // Array of Expression's a0..an
5374 
5375     size_t currentDimension;    // for opDollar
5376     VarDeclaration lengthVar;
5377 
5378     extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
5379     {
5380         super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
5381         arguments = new Expressions();
5382         if (index)
5383             arguments.push(index);
5384     }
5385 
5386     extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
5387     {
5388         super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
5389         arguments = args;
5390     }
5391 
5392     override Expression syntaxCopy()
5393     {
5394         auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5395         ae.lengthVar = this.lengthVar; // bug7871
5396         return ae;
5397     }
5398 
5399     override bool isLvalue()
5400     {
5401         if (type && type.toBasetype().ty == Tvoid)
5402             return false;
5403         return true;
5404     }
5405 
5406     override Expression toLvalue(Scope* sc, Expression e)
5407     {
5408         if (type && type.toBasetype().ty == Tvoid)
5409             error("`void`s have no value");
5410         return this;
5411     }
5412 
5413     override void accept(Visitor v)
5414     {
5415         v.visit(this);
5416     }
5417 }
5418 
5419 /***********************************************************
5420  */
5421 extern (C++) final class DotExp : BinExp
5422 {
5423     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5424     {
5425         super(loc, TOK.dot, __traits(classInstanceSize, DotExp), e1, e2);
5426     }
5427 
5428     override void accept(Visitor v)
5429     {
5430         v.visit(this);
5431     }
5432 }
5433 
5434 /***********************************************************
5435  */
5436 extern (C++) final class CommaExp : BinExp
5437 {
5438     /// This is needed because AssignExp rewrites CommaExp, hence it needs
5439     /// to trigger the deprecation.
5440     const bool isGenerated;
5441 
5442     /// Temporary variable to enable / disable deprecation of comma expression
5443     /// depending on the context.
5444     /// Since most constructor calls are rewritting, the only place where
5445     /// false will be passed will be from the parser.
5446     bool allowCommaExp;
5447 
5448 
5449     extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
5450     {
5451         super(loc, TOK.comma, __traits(classInstanceSize, CommaExp), e1, e2);
5452         allowCommaExp = isGenerated = generated;
5453     }
5454 
5455     override Modifiable checkModifiable(Scope* sc, int flag)
5456     {
5457         return e2.checkModifiable(sc, flag);
5458     }
5459 
5460     override bool isLvalue()
5461     {
5462         return e2.isLvalue();
5463     }
5464 
5465     override Expression toLvalue(Scope* sc, Expression e)
5466     {
5467         e2 = e2.toLvalue(sc, null);
5468         return this;
5469     }
5470 
5471     override Expression modifiableLvalue(Scope* sc, Expression e)
5472     {
5473         e2 = e2.modifiableLvalue(sc, e);
5474         return this;
5475     }
5476 
5477     override bool isBool(bool result)
5478     {
5479         return e2.isBool(result);
5480     }
5481 
5482     override Expression toBoolean(Scope* sc)
5483     {
5484         auto ex2 = e2.toBoolean(sc);
5485         if (ex2.op == TOK.error)
5486             return ex2;
5487         e2 = ex2;
5488         type = e2.type;
5489         return this;
5490     }
5491 
5492     override Expression addDtorHook(Scope* sc)
5493     {
5494         e2 = e2.addDtorHook(sc);
5495         return this;
5496     }
5497 
5498     override void accept(Visitor v)
5499     {
5500         v.visit(this);
5501     }
5502 
5503     /**
5504      * If the argument is a CommaExp, set a flag to prevent deprecation messages
5505      *
5506      * It's impossible to know from CommaExp.semantic if the result will
5507      * be used, hence when there is a result (type != void), a deprecation
5508      * message is always emitted.
5509      * However, some construct can produce a result but won't use it
5510      * (ExpStatement and for loop increment).  Those should call this function
5511      * to prevent unwanted deprecations to be emitted.
5512      *
5513      * Params:
5514      *   exp = An expression that discards its result.
5515      *         If the argument is null or not a CommaExp, nothing happens.
5516      */
5517     static void allow(Expression exp)
5518     {
5519         if (exp)
5520             if (auto ce = exp.isCommaExp())
5521                 ce.allowCommaExp = true;
5522     }
5523 }
5524 
5525 /***********************************************************
5526  * Mainly just a placeholder
5527  */
5528 extern (C++) final class IntervalExp : Expression
5529 {
5530     Expression lwr;
5531     Expression upr;
5532 
5533     extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
5534     {
5535         super(loc, TOK.interval, __traits(classInstanceSize, IntervalExp));
5536         this.lwr = lwr;
5537         this.upr = upr;
5538     }
5539 
5540     override Expression syntaxCopy()
5541     {
5542         return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
5543     }
5544 
5545     override void accept(Visitor v)
5546     {
5547         v.visit(this);
5548     }
5549 }
5550 
5551 extern (C++) final class DelegatePtrExp : UnaExp
5552 {
5553     extern (D) this(const ref Loc loc, Expression e1)
5554     {
5555         super(loc, TOK.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
5556     }
5557 
5558     override bool isLvalue()
5559     {
5560         return e1.isLvalue();
5561     }
5562 
5563     override Expression toLvalue(Scope* sc, Expression e)
5564     {
5565         e1 = e1.toLvalue(sc, e);
5566         return this;
5567     }
5568 
5569     override Expression modifiableLvalue(Scope* sc, Expression e)
5570     {
5571         if (sc.func.setUnsafe())
5572         {
5573             error("cannot modify delegate pointer in `@safe` code `%s`", toChars());
5574             return new ErrorExp();
5575         }
5576         return Expression.modifiableLvalue(sc, e);
5577     }
5578 
5579     override void accept(Visitor v)
5580     {
5581         v.visit(this);
5582     }
5583 }
5584 
5585 /***********************************************************
5586  */
5587 extern (C++) final class DelegateFuncptrExp : UnaExp
5588 {
5589     extern (D) this(const ref Loc loc, Expression e1)
5590     {
5591         super(loc, TOK.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
5592     }
5593 
5594     override bool isLvalue()
5595     {
5596         return e1.isLvalue();
5597     }
5598 
5599     override Expression toLvalue(Scope* sc, Expression e)
5600     {
5601         e1 = e1.toLvalue(sc, e);
5602         return this;
5603     }
5604 
5605     override Expression modifiableLvalue(Scope* sc, Expression e)
5606     {
5607         if (sc.func.setUnsafe())
5608         {
5609             error("cannot modify delegate function pointer in `@safe` code `%s`", toChars());
5610             return new ErrorExp();
5611         }
5612         return Expression.modifiableLvalue(sc, e);
5613     }
5614 
5615     override void accept(Visitor v)
5616     {
5617         v.visit(this);
5618     }
5619 }
5620 
5621 /***********************************************************
5622  * e1 [ e2 ]
5623  */
5624 extern (C++) final class IndexExp : BinExp
5625 {
5626     VarDeclaration lengthVar;
5627     bool modifiable = false;    // assume it is an rvalue
5628     bool indexIsInBounds;       // true if 0 <= e2 && e2 <= e1.length - 1
5629 
5630     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5631     {
5632         super(loc, TOK.index, __traits(classInstanceSize, IndexExp), e1, e2);
5633         //printf("IndexExp::IndexExp('%s')\n", toChars());
5634     }
5635 
5636     override Expression syntaxCopy()
5637     {
5638         auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
5639         ie.lengthVar = this.lengthVar; // bug7871
5640         return ie;
5641     }
5642 
5643     override Modifiable checkModifiable(Scope* sc, int flag)
5644     {
5645         if (e1.type.ty == Tsarray ||
5646             e1.type.ty == Taarray ||
5647             (e1.op == TOK.index && e1.type.ty != Tarray) ||
5648             e1.op == TOK.slice)
5649         {
5650             return e1.checkModifiable(sc, flag);
5651         }
5652         return Modifiable.yes;
5653     }
5654 
5655     override bool isLvalue()
5656     {
5657         return true;
5658     }
5659 
5660     override Expression toLvalue(Scope* sc, Expression e)
5661     {
5662         return this;
5663     }
5664 
5665     override Expression modifiableLvalue(Scope* sc, Expression e)
5666     {
5667         //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
5668         Expression ex = markSettingAAElem();
5669         if (ex.op == TOK.error)
5670             return ex;
5671 
5672         return Expression.modifiableLvalue(sc, e);
5673     }
5674 
5675     extern (D) Expression markSettingAAElem()
5676     {
5677         if (e1.type.toBasetype().ty == Taarray)
5678         {
5679             Type t2b = e2.type.toBasetype();
5680             if (t2b.ty == Tarray && t2b.nextOf().isMutable())
5681             {
5682                 error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
5683                 return new ErrorExp();
5684             }
5685             modifiable = true;
5686 
5687             if (auto ie = e1.isIndexExp())
5688             {
5689                 Expression ex = ie.markSettingAAElem();
5690                 if (ex.op == TOK.error)
5691                     return ex;
5692                 assert(ex == e1);
5693             }
5694         }
5695         return this;
5696     }
5697 
5698     override void accept(Visitor v)
5699     {
5700         v.visit(this);
5701     }
5702 }
5703 
5704 /***********************************************************
5705  * For both i++ and i--
5706  */
5707 extern (C++) final class PostExp : BinExp
5708 {
5709     extern (D) this(TOK op, const ref Loc loc, Expression e)
5710     {
5711         super(loc, op, __traits(classInstanceSize, PostExp), e, new IntegerExp(loc, 1, Type.tint32));
5712         assert(op == TOK.minusMinus || op == TOK.plusPlus);
5713     }
5714 
5715     override void accept(Visitor v)
5716     {
5717         v.visit(this);
5718     }
5719 }
5720 
5721 /***********************************************************
5722  * For both ++i and --i
5723  */
5724 extern (C++) final class PreExp : UnaExp
5725 {
5726     extern (D) this(TOK op, const ref Loc loc, Expression e)
5727     {
5728         super(loc, op, __traits(classInstanceSize, PreExp), e);
5729         assert(op == TOK.preMinusMinus || op == TOK.prePlusPlus);
5730     }
5731 
5732     override void accept(Visitor v)
5733     {
5734         v.visit(this);
5735     }
5736 }
5737 
5738 enum MemorySet
5739 {
5740     blockAssign     = 1,    // setting the contents of an array
5741     referenceInit   = 2,    // setting the reference of STC.ref_ variable
5742 }
5743 
5744 /***********************************************************
5745  */
5746 extern (C++) class AssignExp : BinExp
5747 {
5748     int memset;         // combination of MemorySet flags
5749 
5750     /************************************************************/
5751     /* op can be TOK.assign, TOK.construct, or TOK.blit */
5752     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5753     {
5754         super(loc, TOK.assign, __traits(classInstanceSize, AssignExp), e1, e2);
5755     }
5756 
5757     this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
5758     {
5759         super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
5760     }
5761 
5762     override final bool isLvalue()
5763     {
5764         // Array-op 'x[] = y[]' should make an rvalue.
5765         // Setting array length 'x.length = v' should make an rvalue.
5766         if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
5767         {
5768             return false;
5769         }
5770         return true;
5771     }
5772 
5773     override final Expression toLvalue(Scope* sc, Expression ex)
5774     {
5775         if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
5776         {
5777             return Expression.toLvalue(sc, ex);
5778         }
5779 
5780         /* In front-end level, AssignExp should make an lvalue of e1.
5781          * Taking the address of e1 will be handled in low level layer,
5782          * so this function does nothing.
5783          */
5784         return this;
5785     }
5786 
5787     override final Expression toBoolean(Scope* sc)
5788     {
5789         // Things like:
5790         //  if (a = b) ...
5791         // are usually mistakes.
5792 
5793         error("assignment cannot be used as a condition, perhaps `==` was meant?");
5794         return new ErrorExp();
5795     }
5796 
5797     override void accept(Visitor v)
5798     {
5799         v.visit(this);
5800     }
5801 }
5802 
5803 /***********************************************************
5804  */
5805 extern (C++) final class ConstructExp : AssignExp
5806 {
5807     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5808     {
5809         super(loc, TOK.construct, e1, e2);
5810     }
5811 
5812     // Internal use only. If `v` is a reference variable, the assignment
5813     // will become a reference initialization automatically.
5814     extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
5815     {
5816         auto ve = new VarExp(loc, v);
5817         assert(v.type && ve.type);
5818 
5819         super(loc, TOK.construct, ve, e2);
5820 
5821         if (v.storage_class & (STC.ref_ | STC.out_))
5822             memset |= MemorySet.referenceInit;
5823     }
5824 
5825     override void accept(Visitor v)
5826     {
5827         v.visit(this);
5828     }
5829 }
5830 
5831 /***********************************************************
5832  */
5833 extern (C++) final class BlitExp : AssignExp
5834 {
5835     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5836     {
5837         super(loc, TOK.blit, e1, e2);
5838     }
5839 
5840     // Internal use only. If `v` is a reference variable, the assinment
5841     // will become a reference rebinding automatically.
5842     extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
5843     {
5844         auto ve = new VarExp(loc, v);
5845         assert(v.type && ve.type);
5846 
5847         super(loc, TOK.blit, ve, e2);
5848 
5849         if (v.storage_class & (STC.ref_ | STC.out_))
5850             memset |= MemorySet.referenceInit;
5851     }
5852 
5853     override void accept(Visitor v)
5854     {
5855         v.visit(this);
5856     }
5857 }
5858 
5859 /***********************************************************
5860  */
5861 extern (C++) final class AddAssignExp : BinAssignExp
5862 {
5863     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5864     {
5865         super(loc, TOK.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
5866     }
5867 
5868     override void accept(Visitor v)
5869     {
5870         v.visit(this);
5871     }
5872 }
5873 
5874 /***********************************************************
5875  */
5876 extern (C++) final class MinAssignExp : BinAssignExp
5877 {
5878     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5879     {
5880         super(loc, TOK.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
5881     }
5882 
5883     override void accept(Visitor v)
5884     {
5885         v.visit(this);
5886     }
5887 }
5888 
5889 /***********************************************************
5890  */
5891 extern (C++) final class MulAssignExp : BinAssignExp
5892 {
5893     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5894     {
5895         super(loc, TOK.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
5896     }
5897 
5898     override void accept(Visitor v)
5899     {
5900         v.visit(this);
5901     }
5902 }
5903 
5904 /***********************************************************
5905  */
5906 extern (C++) final class DivAssignExp : BinAssignExp
5907 {
5908     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5909     {
5910         super(loc, TOK.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
5911     }
5912 
5913     override void accept(Visitor v)
5914     {
5915         v.visit(this);
5916     }
5917 }
5918 
5919 /***********************************************************
5920  */
5921 extern (C++) final class ModAssignExp : BinAssignExp
5922 {
5923     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5924     {
5925         super(loc, TOK.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
5926     }
5927 
5928     override void accept(Visitor v)
5929     {
5930         v.visit(this);
5931     }
5932 }
5933 
5934 /***********************************************************
5935  */
5936 extern (C++) final class AndAssignExp : BinAssignExp
5937 {
5938     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5939     {
5940         super(loc, TOK.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
5941     }
5942 
5943     override void accept(Visitor v)
5944     {
5945         v.visit(this);
5946     }
5947 }
5948 
5949 /***********************************************************
5950  */
5951 extern (C++) final class OrAssignExp : BinAssignExp
5952 {
5953     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5954     {
5955         super(loc, TOK.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
5956     }
5957 
5958     override void accept(Visitor v)
5959     {
5960         v.visit(this);
5961     }
5962 }
5963 
5964 /***********************************************************
5965  */
5966 extern (C++) final class XorAssignExp : BinAssignExp
5967 {
5968     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5969     {
5970         super(loc, TOK.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
5971     }
5972 
5973     override void accept(Visitor v)
5974     {
5975         v.visit(this);
5976     }
5977 }
5978 
5979 /***********************************************************
5980  */
5981 extern (C++) final class PowAssignExp : BinAssignExp
5982 {
5983     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5984     {
5985         super(loc, TOK.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
5986     }
5987 
5988     override void accept(Visitor v)
5989     {
5990         v.visit(this);
5991     }
5992 }
5993 
5994 /***********************************************************
5995  */
5996 extern (C++) final class ShlAssignExp : BinAssignExp
5997 {
5998     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5999     {
6000         super(loc, TOK.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
6001     }
6002 
6003     override void accept(Visitor v)
6004     {
6005         v.visit(this);
6006     }
6007 }
6008 
6009 /***********************************************************
6010  */
6011 extern (C++) final class ShrAssignExp : BinAssignExp
6012 {
6013     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6014     {
6015         super(loc, TOK.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
6016     }
6017 
6018     override void accept(Visitor v)
6019     {
6020         v.visit(this);
6021     }
6022 }
6023 
6024 /***********************************************************
6025  */
6026 extern (C++) final class UshrAssignExp : BinAssignExp
6027 {
6028     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6029     {
6030         super(loc, TOK.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
6031     }
6032 
6033     override void accept(Visitor v)
6034     {
6035         v.visit(this);
6036     }
6037 }
6038 
6039 /***********************************************************
6040  * The ~= operator. It can have one of the following operators:
6041  *
6042  * TOK.concatenateAssign      - appending T[] to T[]
6043  * TOK.concatenateElemAssign  - appending T to T[]
6044  * TOK.concatenateDcharAssign - appending dchar to T[]
6045  *
6046  * The parser initially sets it to TOK.concatenateAssign, and semantic() later decides which
6047  * of the three it will be set to.
6048  */
6049 extern (C++) class CatAssignExp : BinAssignExp
6050 {
6051     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6052     {
6053         super(loc, TOK.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
6054     }
6055 
6056     extern (D) this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
6057     {
6058         super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
6059     }
6060 
6061     override void accept(Visitor v)
6062     {
6063         v.visit(this);
6064     }
6065 }
6066 
6067 ///
6068 extern (C++) final class CatElemAssignExp : CatAssignExp
6069 {
6070     extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6071     {
6072         super(loc, TOK.concatenateElemAssign, e1, e2);
6073         this.type = type;
6074     }
6075 
6076     override void accept(Visitor v)
6077     {
6078         v.visit(this);
6079     }
6080 }
6081 
6082 ///
6083 extern (C++) final class CatDcharAssignExp : CatAssignExp
6084 {
6085     extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6086     {
6087         super(loc, TOK.concatenateDcharAssign, e1, e2);
6088         this.type = type;
6089     }
6090 
6091     override void accept(Visitor v)
6092     {
6093         v.visit(this);
6094     }
6095 }
6096 
6097 /***********************************************************
6098  * http://dlang.org/spec/expression.html#add_expressions
6099  */
6100 extern (C++) final class AddExp : BinExp
6101 {
6102     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6103     {
6104         super(loc, TOK.add, __traits(classInstanceSize, AddExp), e1, e2);
6105     }
6106 
6107     override void accept(Visitor v)
6108     {
6109         v.visit(this);
6110     }
6111 }
6112 
6113 /***********************************************************
6114  */
6115 extern (C++) final class MinExp : BinExp
6116 {
6117     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6118     {
6119         super(loc, TOK.min, __traits(classInstanceSize, MinExp), e1, e2);
6120     }
6121 
6122     override void accept(Visitor v)
6123     {
6124         v.visit(this);
6125     }
6126 }
6127 
6128 /***********************************************************
6129  * http://dlang.org/spec/expression.html#cat_expressions
6130  */
6131 extern (C++) final class CatExp : BinExp
6132 {
6133     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6134     {
6135         super(loc, TOK.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
6136     }
6137 
6138     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6139     {
6140         e1 = e1.resolveLoc(loc, sc);
6141         e2 = e2.resolveLoc(loc, sc);
6142         return this;
6143     }
6144 
6145     override void accept(Visitor v)
6146     {
6147         v.visit(this);
6148     }
6149 }
6150 
6151 /***********************************************************
6152  * http://dlang.org/spec/expression.html#mul_expressions
6153  */
6154 extern (C++) final class MulExp : BinExp
6155 {
6156     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6157     {
6158         super(loc, TOK.mul, __traits(classInstanceSize, MulExp), e1, e2);
6159     }
6160 
6161     override void accept(Visitor v)
6162     {
6163         v.visit(this);
6164     }
6165 }
6166 
6167 /***********************************************************
6168  * http://dlang.org/spec/expression.html#mul_expressions
6169  */
6170 extern (C++) final class DivExp : BinExp
6171 {
6172     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6173     {
6174         super(loc, TOK.div, __traits(classInstanceSize, DivExp), e1, e2);
6175     }
6176 
6177     override void accept(Visitor v)
6178     {
6179         v.visit(this);
6180     }
6181 }
6182 
6183 /***********************************************************
6184  * http://dlang.org/spec/expression.html#mul_expressions
6185  */
6186 extern (C++) final class ModExp : BinExp
6187 {
6188     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6189     {
6190         super(loc, TOK.mod, __traits(classInstanceSize, ModExp), e1, e2);
6191     }
6192 
6193     override void accept(Visitor v)
6194     {
6195         v.visit(this);
6196     }
6197 }
6198 
6199 /***********************************************************
6200  * http://dlang.org/spec/expression.html#pow_expressions
6201  */
6202 extern (C++) final class PowExp : BinExp
6203 {
6204     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6205     {
6206         super(loc, TOK.pow, __traits(classInstanceSize, PowExp), e1, e2);
6207     }
6208 
6209     override void accept(Visitor v)
6210     {
6211         v.visit(this);
6212     }
6213 }
6214 
6215 /***********************************************************
6216  */
6217 extern (C++) final class ShlExp : BinExp
6218 {
6219     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6220     {
6221         super(loc, TOK.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
6222     }
6223 
6224     override void accept(Visitor v)
6225     {
6226         v.visit(this);
6227     }
6228 }
6229 
6230 /***********************************************************
6231  */
6232 extern (C++) final class ShrExp : BinExp
6233 {
6234     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6235     {
6236         super(loc, TOK.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
6237     }
6238 
6239     override void accept(Visitor v)
6240     {
6241         v.visit(this);
6242     }
6243 }
6244 
6245 /***********************************************************
6246  */
6247 extern (C++) final class UshrExp : BinExp
6248 {
6249     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6250     {
6251         super(loc, TOK.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
6252     }
6253 
6254     override void accept(Visitor v)
6255     {
6256         v.visit(this);
6257     }
6258 }
6259 
6260 /***********************************************************
6261  */
6262 extern (C++) final class AndExp : BinExp
6263 {
6264     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6265     {
6266         super(loc, TOK.and, __traits(classInstanceSize, AndExp), e1, e2);
6267     }
6268 
6269     override void accept(Visitor v)
6270     {
6271         v.visit(this);
6272     }
6273 }
6274 
6275 /***********************************************************
6276  */
6277 extern (C++) final class OrExp : BinExp
6278 {
6279     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6280     {
6281         super(loc, TOK.or, __traits(classInstanceSize, OrExp), e1, e2);
6282     }
6283 
6284     override void accept(Visitor v)
6285     {
6286         v.visit(this);
6287     }
6288 }
6289 
6290 /***********************************************************
6291  */
6292 extern (C++) final class XorExp : BinExp
6293 {
6294     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6295     {
6296         super(loc, TOK.xor, __traits(classInstanceSize, XorExp), e1, e2);
6297     }
6298 
6299     override void accept(Visitor v)
6300     {
6301         v.visit(this);
6302     }
6303 }
6304 
6305 /***********************************************************
6306  * http://dlang.org/spec/expression.html#andand_expressions
6307  * http://dlang.org/spec/expression.html#oror_expressions
6308  */
6309 extern (C++) final class LogicalExp : BinExp
6310 {
6311     extern (D) this(const ref Loc loc, TOK op, Expression e1, Expression e2)
6312     {
6313         super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
6314         assert(op == TOK.andAnd || op == TOK.orOr);
6315     }
6316 
6317     override Expression toBoolean(Scope* sc)
6318     {
6319         auto ex2 = e2.toBoolean(sc);
6320         if (ex2.op == TOK.error)
6321             return ex2;
6322         e2 = ex2;
6323         return this;
6324     }
6325 
6326     override void accept(Visitor v)
6327     {
6328         v.visit(this);
6329     }
6330 }
6331 
6332 /***********************************************************
6333  * `op` is one of:
6334  *      TOK.lessThan, TOK.lessOrEqual, TOK.greaterThan, TOK.greaterOrEqual
6335  *
6336  * http://dlang.org/spec/expression.html#relation_expressions
6337  */
6338 extern (C++) final class CmpExp : BinExp
6339 {
6340     extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
6341     {
6342         super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
6343         assert(op == TOK.lessThan || op == TOK.lessOrEqual || op == TOK.greaterThan || op == TOK.greaterOrEqual);
6344     }
6345 
6346     override void accept(Visitor v)
6347     {
6348         v.visit(this);
6349     }
6350 }
6351 
6352 /***********************************************************
6353  */
6354 extern (C++) final class InExp : BinExp
6355 {
6356     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6357     {
6358         super(loc, TOK.in_, __traits(classInstanceSize, InExp), e1, e2);
6359     }
6360 
6361     override void accept(Visitor v)
6362     {
6363         v.visit(this);
6364     }
6365 }
6366 
6367 /***********************************************************
6368  * This deletes the key e1 from the associative array e2
6369  */
6370 extern (C++) final class RemoveExp : BinExp
6371 {
6372     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6373     {
6374         super(loc, TOK.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
6375         type = Type.tbool;
6376     }
6377 
6378     override void accept(Visitor v)
6379     {
6380         v.visit(this);
6381     }
6382 }
6383 
6384 /***********************************************************
6385  * `==` and `!=`
6386  *
6387  * TOK.equal and TOK.notEqual
6388  *
6389  * http://dlang.org/spec/expression.html#equality_expressions
6390  */
6391 extern (C++) final class EqualExp : BinExp
6392 {
6393     extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
6394     {
6395         super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
6396         assert(op == TOK.equal || op == TOK.notEqual);
6397     }
6398 
6399     override void accept(Visitor v)
6400     {
6401         v.visit(this);
6402     }
6403 }
6404 
6405 /***********************************************************
6406  * `is` and `!is`
6407  *
6408  * TOK.identity and TOK.notIdentity
6409  *
6410  *  http://dlang.org/spec/expression.html#identity_expressions
6411  */
6412 extern (C++) final class IdentityExp : BinExp
6413 {
6414     extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
6415     {
6416         super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
6417         assert(op == TOK.identity || op == TOK.notIdentity);
6418     }
6419 
6420     override void accept(Visitor v)
6421     {
6422         v.visit(this);
6423     }
6424 }
6425 
6426 /***********************************************************
6427  * `econd ? e1 : e2`
6428  *
6429  * http://dlang.org/spec/expression.html#conditional_expressions
6430  */
6431 extern (C++) final class CondExp : BinExp
6432 {
6433     Expression econd;
6434 
6435     extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
6436     {
6437         super(loc, TOK.question, __traits(classInstanceSize, CondExp), e1, e2);
6438         this.econd = econd;
6439     }
6440 
6441     override Expression syntaxCopy()
6442     {
6443         return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
6444     }
6445 
6446     override Modifiable checkModifiable(Scope* sc, int flag)
6447     {
6448         if (e1.checkModifiable(sc, flag) != Modifiable.no
6449             && e2.checkModifiable(sc, flag) != Modifiable.no)
6450             return Modifiable.yes;
6451         return Modifiable.no;
6452     }
6453 
6454     override bool isLvalue()
6455     {
6456         return e1.isLvalue() && e2.isLvalue();
6457     }
6458 
6459     override Expression toLvalue(Scope* sc, Expression ex)
6460     {
6461         // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
6462         CondExp e = cast(CondExp)copy();
6463         e.e1 = e1.toLvalue(sc, null).addressOf();
6464         e.e2 = e2.toLvalue(sc, null).addressOf();
6465         e.type = type.pointerTo();
6466         return new PtrExp(loc, e, type);
6467     }
6468 
6469     override Expression modifiableLvalue(Scope* sc, Expression e)
6470     {
6471         //error("conditional expression %s is not a modifiable lvalue", toChars());
6472         e1 = e1.modifiableLvalue(sc, e1);
6473         e2 = e2.modifiableLvalue(sc, e2);
6474         return toLvalue(sc, this);
6475     }
6476 
6477     override Expression toBoolean(Scope* sc)
6478     {
6479         auto ex1 = e1.toBoolean(sc);
6480         auto ex2 = e2.toBoolean(sc);
6481         if (ex1.op == TOK.error)
6482             return ex1;
6483         if (ex2.op == TOK.error)
6484             return ex2;
6485         e1 = ex1;
6486         e2 = ex2;
6487         return this;
6488     }
6489 
6490     void hookDtors(Scope* sc)
6491     {
6492         extern (C++) final class DtorVisitor : StoppableVisitor
6493         {
6494             alias visit = typeof(super).visit;
6495         public:
6496             Scope* sc;
6497             CondExp ce;
6498             VarDeclaration vcond;
6499             bool isThen;
6500 
6501             extern (D) this(Scope* sc, CondExp ce)
6502             {
6503                 this.sc = sc;
6504                 this.ce = ce;
6505             }
6506 
6507             override void visit(Expression e)
6508             {
6509                 //printf("(e = %s)\n", e.toChars());
6510             }
6511 
6512             override void visit(DeclarationExp e)
6513             {
6514                 auto v = e.declaration.isVarDeclaration();
6515                 if (v && !v.isDataseg())
6516                 {
6517                     if (v._init)
6518                     {
6519                         if (auto ei = v._init.isExpInitializer())
6520                             walkPostorder(ei.exp, this);
6521                     }
6522 
6523                     if (v.edtor)
6524                         walkPostorder(v.edtor, this);
6525 
6526                     if (v.needsScopeDtor())
6527                     {
6528                         if (!vcond)
6529                         {
6530                             vcond = copyToTemp(STC.volatile_, "__cond", ce.econd);
6531                             vcond.dsymbolSemantic(sc);
6532 
6533                             Expression de = new DeclarationExp(ce.econd.loc, vcond);
6534                             de = de.expressionSemantic(sc);
6535 
6536                             Expression ve = new VarExp(ce.econd.loc, vcond);
6537                             ce.econd = Expression.combine(de, ve);
6538                         }
6539 
6540                         //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6541                         Expression ve = new VarExp(vcond.loc, vcond);
6542                         if (isThen)
6543                             v.edtor = new LogicalExp(v.edtor.loc, TOK.andAnd, ve, v.edtor);
6544                         else
6545                             v.edtor = new LogicalExp(v.edtor.loc, TOK.orOr, ve, v.edtor);
6546                         v.edtor = v.edtor.expressionSemantic(sc);
6547                         //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6548                     }
6549                 }
6550             }
6551         }
6552 
6553         scope DtorVisitor v = new DtorVisitor(sc, this);
6554         //printf("+%s\n", toChars());
6555         v.isThen = true;
6556         walkPostorder(e1, v);
6557         v.isThen = false;
6558         walkPostorder(e2, v);
6559         //printf("-%s\n", toChars());
6560     }
6561 
6562     override void accept(Visitor v)
6563     {
6564         v.visit(this);
6565     }
6566 }
6567 
6568 /***********************************************************
6569  */
6570 extern (C++) class DefaultInitExp : Expression
6571 {
6572     TOK subop;      // which of the derived classes this is
6573 
6574     extern (D) this(const ref Loc loc, TOK subop, int size)
6575     {
6576         super(loc, TOK.default_, size);
6577         this.subop = subop;
6578     }
6579 
6580     override void accept(Visitor v)
6581     {
6582         v.visit(this);
6583     }
6584 }
6585 
6586 /***********************************************************
6587  */
6588 extern (C++) final class FileInitExp : DefaultInitExp
6589 {
6590     extern (D) this(const ref Loc loc, TOK tok)
6591     {
6592         super(loc, tok, __traits(classInstanceSize, FileInitExp));
6593     }
6594 
6595     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6596     {
6597         //printf("FileInitExp::resolve() %s\n", toChars());
6598         const(char)* s;
6599         if (subop == TOK.fileFullPath)
6600             s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
6601         else
6602             s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
6603 
6604         Expression e = new StringExp(loc, s.toDString());
6605         e = e.expressionSemantic(sc);
6606         e = e.castTo(sc, type);
6607         return e;
6608     }
6609 
6610     override void accept(Visitor v)
6611     {
6612         v.visit(this);
6613     }
6614 }
6615 
6616 /***********************************************************
6617  */
6618 extern (C++) final class LineInitExp : DefaultInitExp
6619 {
6620     extern (D) this(const ref Loc loc)
6621     {
6622         super(loc, TOK.line, __traits(classInstanceSize, LineInitExp));
6623     }
6624 
6625     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6626     {
6627         Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
6628         e = e.castTo(sc, type);
6629         return e;
6630     }
6631 
6632     override void accept(Visitor v)
6633     {
6634         v.visit(this);
6635     }
6636 }
6637 
6638 /***********************************************************
6639  */
6640 extern (C++) final class ModuleInitExp : DefaultInitExp
6641 {
6642     extern (D) this(const ref Loc loc)
6643     {
6644         super(loc, TOK.moduleString, __traits(classInstanceSize, ModuleInitExp));
6645     }
6646 
6647     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6648     {
6649         const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
6650         Expression e = new StringExp(loc, s);
6651         e = e.expressionSemantic(sc);
6652         e = e.castTo(sc, type);
6653         return e;
6654     }
6655 
6656     override void accept(Visitor v)
6657     {
6658         v.visit(this);
6659     }
6660 }
6661 
6662 /***********************************************************
6663  */
6664 extern (C++) final class FuncInitExp : DefaultInitExp
6665 {
6666     extern (D) this(const ref Loc loc)
6667     {
6668         super(loc, TOK.functionString, __traits(classInstanceSize, FuncInitExp));
6669     }
6670 
6671     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6672     {
6673         const(char)* s;
6674         if (sc.callsc && sc.callsc.func)
6675             s = sc.callsc.func.Dsymbol.toPrettyChars();
6676         else if (sc.func)
6677             s = sc.func.Dsymbol.toPrettyChars();
6678         else
6679             s = "";
6680         Expression e = new StringExp(loc, s.toDString());
6681         e = e.expressionSemantic(sc);
6682         e.type = Type.tstring;
6683         return e;
6684     }
6685 
6686     override void accept(Visitor v)
6687     {
6688         v.visit(this);
6689     }
6690 }
6691 
6692 /***********************************************************
6693  */
6694 extern (C++) final class PrettyFuncInitExp : DefaultInitExp
6695 {
6696     extern (D) this(const ref Loc loc)
6697     {
6698         super(loc, TOK.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
6699     }
6700 
6701     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6702     {
6703         FuncDeclaration fd = (sc.callsc && sc.callsc.func)
6704                         ? sc.callsc.func
6705                         : sc.func;
6706 
6707         const(char)* s;
6708         if (fd)
6709         {
6710             const funcStr = fd.Dsymbol.toPrettyChars();
6711             OutBuffer buf;
6712             functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr);
6713             s = buf.extractChars();
6714         }
6715         else
6716         {
6717             s = "";
6718         }
6719 
6720         Expression e = new StringExp(loc, s.toDString());
6721         e = e.expressionSemantic(sc);
6722         e.type = Type.tstring;
6723         return e;
6724     }
6725 
6726     override void accept(Visitor v)
6727     {
6728         v.visit(this);
6729     }
6730 }
6731 
6732 /**
6733  * Objective-C class reference expression.
6734  *
6735  * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
6736  */
6737 extern (C++) final class ObjcClassReferenceExp : Expression
6738 {
6739     ClassDeclaration classDeclaration;
6740 
6741     extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
6742     {
6743         super(loc, TOK.objcClassReference,
6744             __traits(classInstanceSize, ObjcClassReferenceExp));
6745         this.classDeclaration = classDeclaration;
6746         type = objc.getRuntimeMetaclass(classDeclaration).getType();
6747     }
6748 
6749     override void accept(Visitor v)
6750     {
6751         v.visit(this);
6752     }
6753 }