xref: /netbsd/external/gpl3/gcc/dist/gcc/d/dmd/dcast.d (revision f0fbc68b)
1 /**
2  * Semantic analysis for cast-expressions.
3  *
4  * Copyright:   Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d)
8  * Documentation:  https://dlang.org/phobos/dmd_dcast.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dcast.d
10  */
11 
12 module dmd.dcast;
13 
14 import core.stdc.stdio;
15 import core.stdc.string;
16 import dmd.aggregate;
17 import dmd.aliasthis;
18 import dmd.arrayop;
19 import dmd.arraytypes;
20 import dmd.astenums;
21 import dmd.dclass;
22 import dmd.declaration;
23 import dmd.dscope;
24 import dmd.dstruct;
25 import dmd.dsymbol;
26 import dmd.errors;
27 import dmd.escape;
28 import dmd.expression;
29 import dmd.expressionsem;
30 import dmd.func;
31 import dmd.globals;
32 import dmd.hdrgen;
33 import dmd.impcnvtab;
34 import dmd.id;
35 import dmd.importc;
36 import dmd.init;
37 import dmd.intrange;
38 import dmd.mtype;
39 import dmd.opover;
40 import dmd.root.ctfloat;
41 import dmd.common.outbuffer;
42 import dmd.root.rmem;
43 import dmd.root.utf;
44 import dmd.tokens;
45 import dmd.typesem;
46 import dmd.visitor;
47 
48 enum LOG = false;
49 
50 /**
51  * Attempt to implicitly cast the expression into type `t`.
52  *
53  * This routine will change `e`. To check the matching level,
54  * use `implicitConvTo`.
55  *
56  * Params:
57  *   e = Expression that is to be casted
58  *   sc = Current scope
59  *   t = Expected resulting type
60  *
61  * Returns:
62  *   The resulting casted expression (mutating `e`), or `ErrorExp`
63  *    if such an implicit conversion is not possible.
64  */
implicitCastTo(Expression e,Scope * sc,Type t)65 Expression implicitCastTo(Expression e, Scope* sc, Type t)
66 {
67     Expression visit(Expression e)
68     {
69         //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
70 
71         if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
72         {
73             if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t)))
74             {
75                 /* Do not emit CastExp for const conversions and
76                  * unique conversions on rvalue.
77                  */
78                 auto result = e.copy();
79                 result.type = t;
80                 return result;
81             }
82 
83             auto ad = isAggregate(e.type);
84             if (ad && ad.aliasthis)
85             {
86                 auto ts = ad.type.isTypeStruct();
87                 const adMatch = ts
88                     ? ts.implicitConvToWithoutAliasThis(t)
89                     : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t);
90 
91                 if (!adMatch)
92                 {
93                     Type tob = t.toBasetype();
94                     Type t1b = e.type.toBasetype();
95                     if (ad != isAggregate(tob))
96                     {
97                         if (t1b.ty == Tclass && tob.ty == Tclass)
98                         {
99                             ClassDeclaration t1cd = t1b.isClassHandle();
100                             ClassDeclaration tocd = tob.isClassHandle();
101                             int offset;
102                             if (tocd.isBaseOf(t1cd, &offset))
103                             {
104                                 auto result = new CastExp(e.loc, e, t);
105                                 result.type = t;
106                                 return result;
107                             }
108                         }
109 
110                         /* Forward the cast to our alias this member, rewrite to:
111                          *   cast(to)e1.aliasthis
112                          */
113                         auto result = resolveAliasThis(sc, e);
114                         return result.castTo(sc, t);
115                    }
116                 }
117             }
118 
119             return e.castTo(sc, t);
120         }
121 
122         auto result = e.optimize(WANTvalue);
123         if (result != e)
124         {
125             return implicitCastTo(result, sc, t);
126         }
127 
128         if (t.ty != Terror && e.type.ty != Terror)
129         {
130             if (!t.deco)
131             {
132                 e.error("forward reference to type `%s`", t.toChars());
133             }
134             else
135             {
136                 //printf("type %p ty %d deco %p\n", type, type.ty, type.deco);
137                 //type = type.typeSemantic(loc, sc);
138                 //printf("type %s t %s\n", type.deco, t.deco);
139                 auto ts = toAutoQualChars(e.type, t);
140                 e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
141                     e.toChars(), ts[0], ts[1]);
142             }
143         }
144         return ErrorExp.get();
145     }
146 
147     Expression visitString(StringExp e)
148     {
149         //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
150         auto result = visit(e);
151         if (auto se = result.isStringExp())
152         {
153             // Retain polysemous nature if it started out that way
154             se.committed = e.committed;
155         }
156         return result;
157     }
158 
159     Expression visitError(ErrorExp e)
160     {
161         return e;
162     }
163 
164     Expression visitFunc(FuncExp e)
165     {
166         //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
167         FuncExp fe;
168         if (e.matchType(t, sc, &fe) > MATCH.nomatch)
169         {
170             return fe;
171         }
172         return visit(e);
173     }
174 
175     Expression visitArrayLiteral(ArrayLiteralExp e)
176     {
177         auto result = visit(e);
178 
179         Type tb = result.type.toBasetype();
180         if (auto ta = tb.isTypeDArray())
181             if (global.params.useTypeInfo && Type.dtypeinfo)
182                 semanticTypeInfo(sc, ta.next);
183         return result;
184     }
185 
186     Expression visitSlice(SliceExp e)
187     {
188         auto result = visit(e);
189 
190         if (auto se = result.isSliceExp())
191             if (auto ale = se.e1.isArrayLiteralExp())
192             {
193                 Type tb = t.toBasetype();
194                 Type tx = (tb.ty == Tsarray)
195                     ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0)
196                     : tb.nextOf().arrayOf();
197                 se.e1 = ale.implicitCastTo(sc, tx);
198             }
199 
200         return result;
201     }
202 
203     switch (e.op)
204     {
205         default              : return visit            (e);
206         case EXP.string_     : return visitString      (e.isStringExp());
207         case EXP.error       : return visitError       (e.isErrorExp());
208         case EXP.function_   : return visitFunc        (e.isFuncExp());
209         case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp());
210         case EXP.slice       : return visitSlice       (e.isSliceExp());
211     }
212 }
213 
214 /**
215  * Checks whether or not an expression can be implicitly converted
216  * to type `t`.
217  *
218  * Unlike `implicitCastTo`, this routine does not perform the actual cast,
219  * but only checks up to what `MATCH` level the conversion would be possible.
220  *
221  * Params:
222  *   e = Expression that is to be casted
223  *   t = Expected resulting type
224  *
225  * Returns:
226  *   The `MATCH` level between `e.type` and `t`.
227  */
implicitConvTo(Expression e,Type t)228 MATCH implicitConvTo(Expression e, Type t)
229 {
230     MATCH visit(Expression e)
231     {
232         version (none)
233         {
234             printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
235         }
236         //static int nest; if (++nest == 10) assert(0);
237         if (t == Type.terror)
238             return MATCH.nomatch;
239         if (!e.type)
240         {
241             e.error("`%s` is not an expression", e.toChars());
242             e.type = Type.terror;
243         }
244 
245         Expression ex = e.optimize(WANTvalue);
246         if (ex.type.equals(t))
247         {
248             return MATCH.exact;
249         }
250         if (ex != e)
251         {
252             //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars());
253             return ex.implicitConvTo(t);
254         }
255 
256         MATCH match = e.type.implicitConvTo(t);
257         if (match != MATCH.nomatch)
258         {
259             return match;
260         }
261 
262         /* See if we can do integral narrowing conversions
263          */
264         if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic())
265         {
266             IntRange src = getIntRange(e);
267             IntRange target = IntRange.fromType(t);
268             if (target.contains(src))
269             {
270                 return MATCH.convert;
271             }
272         }
273         return MATCH.nomatch;
274     }
275 
276     /******
277      * Given expression e of type t, see if we can implicitly convert e
278      * to type tprime, where tprime is type t with mod bits added.
279      * Returns:
280      *      match level
281      */
282     static MATCH implicitMod(Expression e, Type t, MOD mod)
283     {
284         Type tprime;
285         if (t.ty == Tpointer)
286             tprime = t.nextOf().castMod(mod).pointerTo();
287         else if (t.ty == Tarray)
288             tprime = t.nextOf().castMod(mod).arrayOf();
289         else if (t.ty == Tsarray)
290             tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size());
291         else
292             tprime = t.castMod(mod);
293 
294         return e.implicitConvTo(tprime);
295     }
296 
297     static MATCH implicitConvToAddMin(BinExp e, Type t)
298     {
299         /* Is this (ptr +- offset)? If so, then ask ptr
300          * if the conversion can be done.
301          * This is to support doing things like implicitly converting a mutable unique
302          * pointer to an immutable pointer.
303          */
304 
305         Type tb = t.toBasetype();
306         Type typeb = e.type.toBasetype();
307 
308         if (typeb.ty != Tpointer || tb.ty != Tpointer)
309             return MATCH.nomatch;
310 
311         Type t1b = e.e1.type.toBasetype();
312         Type t2b = e.e2.type.toBasetype();
313         if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb))
314         {
315             // ptr + offset
316             // ptr - offset
317             MATCH m = e.e1.implicitConvTo(t);
318             return (m > MATCH.constant) ? MATCH.constant : m;
319         }
320         if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb))
321         {
322             // offset + ptr
323             MATCH m = e.e2.implicitConvTo(t);
324             return (m > MATCH.constant) ? MATCH.constant : m;
325         }
326 
327         return MATCH.nomatch;
328     }
329 
330     MATCH visitAdd(AddExp e)
331     {
332         version (none)
333         {
334             printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
335         }
336         auto result = visit(e);
337         if (result == MATCH.nomatch)
338             result = implicitConvToAddMin(e, t);
339         return result;
340     }
341 
342     MATCH visitMin(MinExp e)
343     {
344         version (none)
345         {
346             printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
347         }
348         auto result = visit(e);
349         if (result == MATCH.nomatch)
350             result = implicitConvToAddMin(e, t);
351         return result;
352     }
353 
354     MATCH visitInteger(IntegerExp e)
355     {
356         version (none)
357         {
358             printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
359         }
360         MATCH m = e.type.implicitConvTo(t);
361         if (m >= MATCH.constant)
362         {
363             return m;
364         }
365 
366         TY ty = e.type.toBasetype().ty;
367         TY toty = t.toBasetype().ty;
368         TY oldty = ty;
369 
370         if (m == MATCH.nomatch && t.ty == Tenum)
371             return MATCH.nomatch;
372 
373         if (auto tv = t.isTypeVector())
374         {
375             TypeBasic tb = tv.elementType();
376             if (tb.ty == Tvoid)
377                 return MATCH.nomatch;
378             toty = tb.ty;
379         }
380 
381         switch (ty)
382         {
383         case Tbool:
384         case Tint8:
385         case Tchar:
386         case Tuns8:
387         case Tint16:
388         case Tuns16:
389         case Twchar:
390             ty = Tint32;
391             break;
392 
393         case Tdchar:
394             ty = Tuns32;
395             break;
396 
397         default:
398             break;
399         }
400 
401         // Only allow conversion if no change in value
402         immutable dinteger_t value = e.toInteger();
403 
404         bool isLosslesslyConvertibleToFP(T)()
405         {
406             if (e.type.isunsigned())
407             {
408                 const f = cast(T) value;
409                 return cast(dinteger_t) f == value;
410             }
411 
412             const f = cast(T) cast(sinteger_t) value;
413             return cast(sinteger_t) f == cast(sinteger_t) value;
414         }
415 
416         switch (toty)
417         {
418         case Tbool:
419             if ((value & 1) != value)
420                 return MATCH.nomatch;
421             break;
422 
423         case Tint8:
424             if (ty == Tuns64 && value & ~0x7FU)
425                 return MATCH.nomatch;
426             else if (cast(byte)value != value)
427                 return MATCH.nomatch;
428             break;
429 
430         case Tchar:
431             if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
432                 return MATCH.nomatch;
433             goto case Tuns8;
434         case Tuns8:
435             //printf("value = %llu %llu\n", cast(dinteger_t)cast(ubyte)value, value);
436             if (cast(ubyte)value != value)
437                 return MATCH.nomatch;
438             break;
439 
440         case Tint16:
441             if (ty == Tuns64 && value & ~0x7FFFU)
442                 return MATCH.nomatch;
443             else if (cast(short)value != value)
444                 return MATCH.nomatch;
445             break;
446 
447         case Twchar:
448             if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
449                 return MATCH.nomatch;
450             goto case Tuns16;
451         case Tuns16:
452             if (cast(ushort)value != value)
453                 return MATCH.nomatch;
454             break;
455 
456         case Tint32:
457             if (ty == Tuns32)
458             {
459             }
460             else if (ty == Tuns64 && value & ~0x7FFFFFFFU)
461                 return MATCH.nomatch;
462             else if (cast(int)value != value)
463                 return MATCH.nomatch;
464             break;
465 
466         case Tuns32:
467             if (ty == Tint32)
468             {
469             }
470             else if (cast(uint)value != value)
471                 return MATCH.nomatch;
472             break;
473 
474         case Tdchar:
475             if (value > 0x10FFFFU)
476                 return MATCH.nomatch;
477             break;
478 
479         case Tfloat32:
480             if (!isLosslesslyConvertibleToFP!float)
481                 return MATCH.nomatch;
482             break;
483 
484         case Tfloat64:
485             if (!isLosslesslyConvertibleToFP!double)
486                 return MATCH.nomatch;
487             break;
488 
489         case Tfloat80:
490             if (!isLosslesslyConvertibleToFP!real_t)
491                 return MATCH.nomatch;
492             break;
493 
494         case Tpointer:
495             //printf("type = %s\n", type.toBasetype().toChars());
496             //printf("t = %s\n", t.toBasetype().toChars());
497             if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty)
498             {
499                 /* Allow things like:
500                  *      const char* P = cast(char *)3;
501                  *      char* q = P;
502                  */
503                 break;
504             }
505             goto default;
506 
507         default:
508             return visit(e);
509         }
510 
511         //printf("MATCH.convert\n");
512         return MATCH.convert;
513     }
514 
515     MATCH visitError(ErrorExp e)
516     {
517         return MATCH.nomatch;
518     }
519 
520     MATCH visitNull(NullExp e)
521     {
522         version (none)
523         {
524             printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
525         }
526         if (e.type.equals(t))
527         {
528             return MATCH.exact;
529         }
530 
531         /* Allow implicit conversions from immutable to mutable|const,
532          * and mutable to immutable. It works because, after all, a null
533          * doesn't actually point to anything.
534          */
535         if (t.equivalent(e.type))
536         {
537             return MATCH.constant;
538         }
539 
540         return visit(e);
541     }
542 
543     MATCH visitStructLiteral(StructLiteralExp e)
544     {
545         version (none)
546         {
547             printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
548         }
549         auto result = visit(e);
550         if (result != MATCH.nomatch)
551             return result;
552         if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym)
553         {
554             result = MATCH.constant;
555             foreach (i, el; (*e.elements)[])
556             {
557                 if (!el)
558                     continue;
559                 Type te = e.sd.fields[i].type.addMod(t.mod);
560                 MATCH m2 = el.implicitConvTo(te);
561                 //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2);
562                 if (m2 < result)
563                     result = m2;
564             }
565         }
566         return result;
567     }
568 
569     MATCH visitString(StringExp e)
570     {
571         version (none)
572         {
573             printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars());
574         }
575         if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid)
576             return MATCH.nomatch;
577 
578         if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer))
579             return visit(e);
580 
581         TY tyn = e.type.nextOf().ty;
582 
583         if (!tyn.isSomeChar)
584             return visit(e);
585 
586         switch (t.ty)
587         {
588         case Tsarray:
589             if (e.type.ty == Tsarray)
590             {
591                 TY tynto = t.nextOf().ty;
592                 if (tynto == tyn)
593                 {
594                     if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger())
595                     {
596                         return MATCH.exact;
597                     }
598                     return MATCH.nomatch;
599                 }
600                 if (tynto.isSomeChar)
601                 {
602                     if (e.committed && tynto != tyn)
603                         return MATCH.nomatch;
604                     size_t fromlen = e.numberOfCodeUnits(tynto);
605                     size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
606                     if (tolen < fromlen)
607                         return MATCH.nomatch;
608                     if (tolen != fromlen)
609                     {
610                         // implicit length extending
611                         return MATCH.convert;
612                     }
613                 }
614                 if (!e.committed && tynto.isSomeChar)
615                 {
616                     return MATCH.exact;
617                 }
618             }
619             else if (e.type.ty == Tarray)
620             {
621                 TY tynto = t.nextOf().ty;
622                 if (tynto.isSomeChar)
623                 {
624                     if (e.committed && tynto != tyn)
625                         return MATCH.nomatch;
626                     size_t fromlen = e.numberOfCodeUnits(tynto);
627                     size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
628                     if (tolen < fromlen)
629                         return MATCH.nomatch;
630                     if (tolen != fromlen)
631                     {
632                         // implicit length extending
633                         return MATCH.convert;
634                     }
635                 }
636                 if (tynto == tyn)
637                 {
638                     return MATCH.exact;
639                 }
640                 if (!e.committed && tynto.isSomeChar)
641                 {
642                     return MATCH.exact;
643                 }
644             }
645             goto case; /+ fall through +/
646         case Tarray:
647         case Tpointer:
648             Type tn = t.nextOf();
649             MATCH m = MATCH.exact;
650             if (e.type.nextOf().mod != tn.mod)
651             {
652                 // https://issues.dlang.org/show_bug.cgi?id=16183
653                 if (!tn.isConst() && !tn.isImmutable())
654                     return MATCH.nomatch;
655                 m = MATCH.constant;
656             }
657             if (!e.committed)
658             {
659                 switch (tn.ty)
660                 {
661                 case Tchar:
662                     if (e.postfix == 'w' || e.postfix == 'd')
663                         m = MATCH.convert;
664                     return m;
665                 case Twchar:
666                     if (e.postfix != 'w')
667                         m = MATCH.convert;
668                     return m;
669                 case Tdchar:
670                     if (e.postfix != 'd')
671                         m = MATCH.convert;
672                     return m;
673                 case Tenum:
674                     if (tn.isTypeEnum().sym.isSpecial())
675                     {
676                         /* Allow string literal -> const(wchar_t)[]
677                          */
678                         if (TypeBasic tob = tn.toBasetype().isTypeBasic())
679                         return tn.implicitConvTo(tob);
680                     }
681                     break;
682                 default:
683                     break;
684                 }
685             }
686             break;
687 
688         default:
689             break;
690         }
691 
692         return visit(e);
693     }
694 
695     MATCH visitArrayLiteral(ArrayLiteralExp e)
696     {
697         version (none)
698         {
699             printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
700         }
701         Type tb = t.toBasetype();
702         Type typeb = e.type.toBasetype();
703 
704         auto result = MATCH.nomatch;
705         if ((tb.ty == Tarray || tb.ty == Tsarray) &&
706             (typeb.ty == Tarray || typeb.ty == Tsarray))
707         {
708             result = MATCH.exact;
709             Type typen = typeb.nextOf().toBasetype();
710 
711             if (auto tsa = tb.isTypeSArray())
712             {
713                 if (e.elements.dim != tsa.dim.toInteger())
714                     result = MATCH.nomatch;
715             }
716 
717             Type telement = tb.nextOf();
718             if (!e.elements.dim)
719             {
720                 if (typen.ty != Tvoid)
721                     result = typen.implicitConvTo(telement);
722             }
723             else
724             {
725                 if (e.basis)
726                 {
727                     MATCH m = e.basis.implicitConvTo(telement);
728                     if (m < result)
729                         result = m;
730                 }
731                 for (size_t i = 0; i < e.elements.dim; i++)
732                 {
733                     Expression el = (*e.elements)[i];
734                     if (result == MATCH.nomatch)
735                         break;
736                     if (!el)
737                         continue;
738                     MATCH m = el.implicitConvTo(telement);
739                     if (m < result)
740                         result = m; // remember worst match
741                 }
742             }
743 
744             if (!result)
745                 result = e.type.implicitConvTo(t);
746 
747             return result;
748         }
749         else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
750         {
751             result = MATCH.exact;
752             // Convert array literal to vector type
753             TypeVector tv = tb.isTypeVector();
754             TypeSArray tbase = tv.basetype.isTypeSArray();
755             assert(tbase);
756             const edim = e.elements.dim;
757             const tbasedim = tbase.dim.toInteger();
758             if (edim > tbasedim)
759             {
760                 return MATCH.nomatch;
761             }
762 
763             Type telement = tv.elementType();
764             if (edim < tbasedim)
765             {
766                 Expression el = typeb.nextOf.defaultInitLiteral(e.loc);
767                 MATCH m = el.implicitConvTo(telement);
768                 if (m < result)
769                     result = m; // remember worst match
770             }
771             foreach (el; (*e.elements)[])
772             {
773                 MATCH m = el.implicitConvTo(telement);
774                 if (m < result)
775                     result = m; // remember worst match
776                 if (result == MATCH.nomatch)
777                     break; // no need to check for worse
778             }
779             return result;
780         }
781 
782         return visit(e);
783     }
784 
785     MATCH visitAssocArrayLiteral(AssocArrayLiteralExp e)
786     {
787         auto taa = t.toBasetype().isTypeAArray();
788         Type typeb = e.type.toBasetype();
789 
790         if (!(taa && typeb.ty == Taarray))
791             return visit(e);
792 
793         auto result = MATCH.exact;
794         foreach (i, el; (*e.keys)[])
795         {
796             MATCH m = el.implicitConvTo(taa.index);
797             if (m < result)
798                 result = m; // remember worst match
799             if (result == MATCH.nomatch)
800                 break; // no need to check for worse
801             el = (*e.values)[i];
802             m = el.implicitConvTo(taa.nextOf());
803             if (m < result)
804                 result = m; // remember worst match
805             if (result == MATCH.nomatch)
806                 break; // no need to check for worse
807         }
808         return result;
809     }
810 
811     MATCH visitCall(CallExp e)
812     {
813         enum LOG = false;
814         static if (LOG)
815         {
816             printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
817         }
818 
819         auto result = visit(e);
820         if (result != MATCH.nomatch)
821             return result;
822 
823         /* Allow the result of strongly pure functions to
824          * convert to immutable
825          */
826         if (e.f &&
827             // lots of legacy code breaks with the following purity check
828             (global.params.useDIP1000 != FeatureState.enabled || e.f.isPure() >= PURE.const_) &&
829              e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive.
830            )
831         {
832             result = e.type.immutableOf().implicitConvTo(t);
833             if (result > MATCH.constant) // Match level is MATCH.constant at best.
834                 result = MATCH.constant;
835             return result;
836         }
837 
838         /* Conversion is 'const' conversion if:
839          * 1. function is pure (weakly pure is ok)
840          * 2. implicit conversion only fails because of mod bits
841          * 3. each function parameter can be implicitly converted to the mod bits
842          */
843         auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction();
844         if (!tf)
845             return result;
846 
847         if (tf.purity == PURE.impure)
848             return result;
849         if (e.f && e.f.isNested())
850             return result;
851 
852         /* See if fail only because of mod bits.
853          *
854          * https://issues.dlang.org/show_bug.cgi?id=14155
855          * All pure functions can access global immutable data.
856          * So the returned pointer may refer an immutable global data,
857          * and then the returned pointer that points non-mutable object
858          * cannot be unique pointer.
859          *
860          * Example:
861          *  immutable g;
862          *  static this() { g = 1; }
863          *  const(int*) foo() pure { return &g; }
864          *  void test() {
865          *    immutable(int*) ip = foo(); // OK
866          *    int* mp = foo();            // should be disallowed
867          *  }
868          */
869         if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
870         {
871             return result;
872         }
873         // Allow a conversion to immutable type, or
874         // conversions of mutable types between thread-local and shared.
875 
876         /* Get mod bits of what we're converting to
877          */
878         Type tb = t.toBasetype();
879         MOD mod = tb.mod;
880         if (tf.isref)
881         {
882         }
883         else
884         {
885             if (Type ti = getIndirection(t))
886                 mod = ti.mod;
887         }
888         static if (LOG)
889         {
890             printf("mod = x%x\n", mod);
891         }
892         if (mod & MODFlags.wild)
893             return result; // not sure what to do with this
894 
895         /* Apply mod bits to each function parameter,
896          * and see if we can convert the function argument to the modded type
897          */
898 
899         size_t nparams = tf.parameterList.length;
900         size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended
901         if (auto dve = e.e1.isDotVarExp())
902         {
903             /* Treat 'this' as just another function argument
904              */
905             Type targ = dve.e1.type;
906             if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
907                 return result;
908         }
909         foreach (const i; j .. e.arguments.dim)
910         {
911             Expression earg = (*e.arguments)[i];
912             Type targ = earg.type.toBasetype();
913             static if (LOG)
914             {
915                 printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
916             }
917             if (i - j < nparams)
918             {
919                 Parameter fparam = tf.parameterList[i - j];
920                 if (fparam.storageClass & STC.lazy_)
921                     return result; // not sure what to do with this
922                 Type tparam = fparam.type;
923                 if (!tparam)
924                     continue;
925                 if (fparam.isReference())
926                 {
927                     if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
928                         return result;
929                     continue;
930                 }
931             }
932             static if (LOG)
933             {
934                 printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
935             }
936             if (implicitMod(earg, targ, mod) == MATCH.nomatch)
937                 return result;
938         }
939 
940         /* Success
941          */
942         return MATCH.constant;
943     }
944 
945     MATCH visitAddr(AddrExp e)
946     {
947         version (none)
948         {
949             printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
950         }
951         auto result = e.type.implicitConvTo(t);
952         //printf("\tresult = %d\n", result);
953 
954         if (result != MATCH.nomatch)
955             return result;
956 
957         Type tb = t.toBasetype();
958         Type typeb = e.type.toBasetype();
959 
960         // Look for pointers to functions where the functions are overloaded.
961         if (e.e1.op == EXP.overloadSet &&
962             (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
963         {
964             OverExp eo = e.e1.isOverExp();
965             FuncDeclaration f = null;
966             foreach (s; eo.vars.a[])
967             {
968                 FuncDeclaration f2 = s.isFuncDeclaration();
969                 assert(f2);
970                 if (f2.overloadExactMatch(tb.nextOf()))
971                 {
972                     if (f)
973                     {
974                         /* Error if match in more than one overload set,
975                          * even if one is a 'better' match than the other.
976                          */
977                         ScopeDsymbol.multiplyDefined(e.loc, f, f2);
978                     }
979                     else
980                         f = f2;
981                     result = MATCH.exact;
982                 }
983             }
984         }
985 
986         if (e.e1.op == EXP.variable &&
987             typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
988             tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
989         {
990             /* I don't think this can ever happen -
991              * it should have been
992              * converted to a SymOffExp.
993              */
994             assert(0);
995         }
996 
997         //printf("\tresult = %d\n", result);
998         return result;
999     }
1000 
1001     MATCH visitSymOff(SymOffExp e)
1002     {
1003         version (none)
1004         {
1005             printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
1006         }
1007         auto result = e.type.implicitConvTo(t);
1008         //printf("\tresult = %d\n", result);
1009         if (result != MATCH.nomatch)
1010             return result;
1011 
1012         Type tb = t.toBasetype();
1013         Type typeb = e.type.toBasetype();
1014 
1015         // Look for pointers to functions where the functions are overloaded.
1016         if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
1017             (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
1018         {
1019             if (FuncDeclaration f = e.var.isFuncDeclaration())
1020             {
1021                 f = f.overloadExactMatch(tb.nextOf());
1022                 if (f)
1023                 {
1024                     if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) ||
1025                         (tb.ty == Tpointer && !(f.needThis() || f.isNested())))
1026                     {
1027                         result = MATCH.exact;
1028                     }
1029                 }
1030             }
1031         }
1032         //printf("\tresult = %d\n", result);
1033         return result;
1034     }
1035 
1036     MATCH visitDelegate(DelegateExp e)
1037     {
1038         version (none)
1039         {
1040             printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
1041         }
1042         auto result = e.type.implicitConvTo(t);
1043         if (result != MATCH.nomatch)
1044             return result;
1045 
1046         Type tb = t.toBasetype();
1047         Type typeb = e.type.toBasetype();
1048 
1049         // Look for pointers to functions where the functions are overloaded.
1050         if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
1051         {
1052             if (e.func && e.func.overloadExactMatch(tb.nextOf()))
1053                 result = MATCH.exact;
1054         }
1055         return result;
1056     }
1057 
1058     MATCH visitFunc(FuncExp e)
1059     {
1060         //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
1061         MATCH m = e.matchType(t, null, null, 1);
1062         if (m > MATCH.nomatch)
1063         {
1064             return m;
1065         }
1066         return visit(e);
1067     }
1068 
1069     MATCH visitAnd(AndExp e)
1070     {
1071         auto result = visit(e);
1072         if (result != MATCH.nomatch)
1073             return result;
1074 
1075         MATCH m1 = e.e1.implicitConvTo(t);
1076         MATCH m2 = e.e2.implicitConvTo(t);
1077 
1078         // Pick the worst match
1079         return (m1 < m2) ? m1 : m2;
1080     }
1081 
1082     MATCH visitOr(OrExp e)
1083     {
1084         auto result = visit(e);
1085         if (result != MATCH.nomatch)
1086             return result;
1087 
1088         MATCH m1 = e.e1.implicitConvTo(t);
1089         MATCH m2 = e.e2.implicitConvTo(t);
1090 
1091         // Pick the worst match
1092         return (m1 < m2) ? m1 : m2;
1093     }
1094 
1095     MATCH visitXor(XorExp e)
1096     {
1097         auto result = visit(e);
1098         if (result != MATCH.nomatch)
1099             return result;
1100 
1101         MATCH m1 = e.e1.implicitConvTo(t);
1102         MATCH m2 = e.e2.implicitConvTo(t);
1103 
1104         // Pick the worst match
1105         return (m1 < m2) ? m1 : m2;
1106     }
1107 
1108     MATCH visitCond(CondExp e)
1109     {
1110         e.econd = e.econd.optimize(WANTvalue);
1111         const opt = e.econd.toBool();
1112         if (opt.isPresent())
1113         {
1114             auto result = visit(e);
1115             if (result != MATCH.nomatch)
1116                 return result;
1117         }
1118 
1119         MATCH m1 = e.e1.implicitConvTo(t);
1120         MATCH m2 = e.e2.implicitConvTo(t);
1121         //printf("CondExp: m1 %d m2 %d\n", m1, m2);
1122 
1123         // Pick the worst match
1124         return (m1 < m2) ? m1 : m2;
1125     }
1126 
1127     MATCH visitComma(CommaExp e)
1128     {
1129         return e.e2.implicitConvTo(t);
1130     }
1131 
1132     MATCH visitCast(CastExp e)
1133     {
1134         version (none)
1135         {
1136             printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
1137         }
1138         auto result = e.type.implicitConvTo(t);
1139         if (result != MATCH.nomatch)
1140             return result;
1141 
1142         if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch)
1143             result = MATCH.convert;
1144         else
1145             result = visit(e);
1146         return result;
1147     }
1148 
1149     MATCH visitNew(NewExp e)
1150     {
1151         version (none)
1152         {
1153             printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
1154         }
1155         auto result = visit(e);
1156         if (result != MATCH.nomatch)
1157             return result;
1158 
1159         /* Calling new() is like calling a pure function. We can implicitly convert the
1160          * return from new() to t using the same algorithm as in CallExp, with the function
1161          * 'arguments' being:
1162          *    thisexp
1163          *    arguments
1164          *    .init
1165          * 'member' need to be pure.
1166          */
1167 
1168         /* See if fail only because of mod bits
1169          */
1170         if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch)
1171             return MATCH.nomatch;
1172 
1173         /* Get mod bits of what we're converting to
1174          */
1175         Type tb = t.toBasetype();
1176         MOD mod = tb.mod;
1177         if (Type ti = getIndirection(t))
1178             mod = ti.mod;
1179         static if (LOG)
1180         {
1181             printf("mod = x%x\n", mod);
1182         }
1183         if (mod & MODFlags.wild)
1184             return MATCH.nomatch; // not sure what to do with this
1185 
1186         /* Apply mod bits to each argument,
1187          * and see if we can convert the argument to the modded type
1188          */
1189 
1190         if (e.thisexp)
1191         {
1192             /* Treat 'this' as just another function argument
1193              */
1194             Type targ = e.thisexp.type;
1195             if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
1196                 return MATCH.nomatch;
1197         }
1198 
1199         /* Check call to 'member'
1200          */
1201         if (e.member)
1202         {
1203             FuncDeclaration fd = e.member;
1204             if (fd.errors || fd.type.ty != Tfunction)
1205                 return MATCH.nomatch; // error
1206             TypeFunction tf = fd.type.isTypeFunction();
1207             if (tf.purity == PURE.impure)
1208                 return MATCH.nomatch; // impure
1209 
1210             if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
1211             {
1212                 return MATCH.nomatch;
1213             }
1214             // Allow a conversion to immutable type, or
1215             // conversions of mutable types between thread-local and shared.
1216 
1217             Expressions* args = e.arguments;
1218 
1219             size_t nparams = tf.parameterList.length;
1220             // if TypeInfoArray was prepended
1221             size_t j = tf.isDstyleVariadic();
1222             for (size_t i = j; i < e.arguments.dim; ++i)
1223             {
1224                 Expression earg = (*args)[i];
1225                 Type targ = earg.type.toBasetype();
1226                 static if (LOG)
1227                 {
1228                     printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
1229                 }
1230                 if (i - j < nparams)
1231                 {
1232                     Parameter fparam = tf.parameterList[i - j];
1233                     if (fparam.storageClass & STC.lazy_)
1234                         return MATCH.nomatch; // not sure what to do with this
1235                     Type tparam = fparam.type;
1236                     if (!tparam)
1237                         continue;
1238                     if (fparam.isReference())
1239                     {
1240                         if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
1241                             return MATCH.nomatch;
1242                         continue;
1243                     }
1244                 }
1245                 static if (LOG)
1246                 {
1247                     printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
1248                 }
1249                 if (implicitMod(earg, targ, mod) == MATCH.nomatch)
1250                     return MATCH.nomatch;
1251             }
1252         }
1253 
1254         /* If no 'member', then construction is by simple assignment,
1255          * and just straight check 'arguments'
1256          */
1257         if (!e.member && e.arguments)
1258         {
1259             for (size_t i = 0; i < e.arguments.dim; ++i)
1260             {
1261                 Expression earg = (*e.arguments)[i];
1262                 if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853
1263                            // if it's on overlapped field
1264                     continue;
1265                 Type targ = earg.type.toBasetype();
1266                 static if (LOG)
1267                 {
1268                     printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
1269                     printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
1270                 }
1271                 if (implicitMod(earg, targ, mod) == MATCH.nomatch)
1272                     return MATCH.nomatch;
1273             }
1274         }
1275 
1276         /* Consider the .init expression as an argument
1277          */
1278         Type ntb = e.newtype.toBasetype();
1279         if (ntb.ty == Tarray)
1280             ntb = ntb.nextOf().toBasetype();
1281         if (auto ts = ntb.isTypeStruct())
1282         {
1283             // Don't allow nested structs - uplevel reference may not be convertible
1284             StructDeclaration sd = ts.sym;
1285             sd.size(e.loc); // resolve any forward references
1286             if (sd.isNested())
1287                 return MATCH.nomatch;
1288         }
1289         if (ntb.isZeroInit(e.loc))
1290         {
1291             /* Zeros are implicitly convertible, except for special cases.
1292              */
1293             if (auto tc = ntb.isTypeClass())
1294             {
1295                 /* With new() must look at the class instance initializer.
1296                  */
1297                 ClassDeclaration cd = tc.sym;
1298 
1299                 cd.size(e.loc); // resolve any forward references
1300 
1301                 if (cd.isNested())
1302                     return MATCH.nomatch; // uplevel reference may not be convertible
1303 
1304                 assert(!cd.isInterfaceDeclaration());
1305 
1306                 struct ClassCheck
1307                 {
1308                     extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod)
1309                     {
1310                         for (size_t i = 0; i < cd.fields.dim; i++)
1311                         {
1312                             VarDeclaration v = cd.fields[i];
1313                             Initializer _init = v._init;
1314                             if (_init)
1315                             {
1316                                 if (_init.isVoidInitializer())
1317                                 {
1318                                 }
1319                                 else if (ExpInitializer ei = _init.isExpInitializer())
1320                                 {
1321                                     // https://issues.dlang.org/show_bug.cgi?id=21319
1322                                     // This is to prevent re-analyzing the same expression
1323                                     // over and over again.
1324                                     if (ei.exp == e)
1325                                         return false;
1326                                     Type tb = v.type.toBasetype();
1327                                     if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch)
1328                                         return false;
1329                                 }
1330                                 else
1331                                 {
1332                                     /* Enhancement: handle StructInitializer and ArrayInitializer
1333                                      */
1334                                     return false;
1335                                 }
1336                             }
1337                             else if (!v.type.isZeroInit(e.loc))
1338                                 return false;
1339                         }
1340                         return cd.baseClass ? convertible(e, cd.baseClass, mod) : true;
1341                     }
1342                 }
1343 
1344                 if (!ClassCheck.convertible(e, cd, mod))
1345                     return MATCH.nomatch;
1346             }
1347         }
1348         else
1349         {
1350             Expression earg = e.newtype.defaultInitLiteral(e.loc);
1351             Type targ = e.newtype.toBasetype();
1352 
1353             if (implicitMod(earg, targ, mod) == MATCH.nomatch)
1354                 return MATCH.nomatch;
1355         }
1356 
1357         /* Success
1358          */
1359         return MATCH.constant;
1360     }
1361 
1362     MATCH visitSlice(SliceExp e)
1363     {
1364         //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars());
1365         auto result = visit(e);
1366         if (result != MATCH.nomatch)
1367             return result;
1368 
1369         Type tb = t.toBasetype();
1370         Type typeb = e.type.toBasetype();
1371 
1372         if (tb.ty == Tsarray && typeb.ty == Tarray)
1373         {
1374             typeb = toStaticArrayType(e);
1375             if (typeb)
1376             {
1377                 // Try: T[] -> T[dim]
1378                 // (Slice with compile-time known boundaries to static array)
1379                 result = typeb.implicitConvTo(t);
1380                 if (result > MATCH.convert)
1381                     result = MATCH.convert; // match with implicit conversion at most
1382             }
1383             return result;
1384         }
1385 
1386         /* If the only reason it won't convert is because of the mod bits,
1387          * then test for conversion by seeing if e1 can be converted with those
1388          * same mod bits.
1389          */
1390         Type t1b = e.e1.type.toBasetype();
1391         if (tb.ty == Tarray && typeb.equivalent(tb))
1392         {
1393             Type tbn = tb.nextOf();
1394             Type tx = null;
1395 
1396             /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1
1397              * is equivalent with the uniqueness of the referred data. And in here
1398              * we can have arbitrary typed reference for that.
1399              */
1400             if (t1b.ty == Tarray)
1401                 tx = tbn.arrayOf();
1402             if (t1b.ty == Tpointer)
1403                 tx = tbn.pointerTo();
1404 
1405             /* If e.e1 is static array, at least it should be an rvalue.
1406              * If not, e.e1 is a reference, and its uniqueness does not link
1407              * to the uniqueness of the referred data.
1408              */
1409             if (t1b.ty == Tsarray && !e.e1.isLvalue())
1410                 tx = tbn.sarrayOf(t1b.size() / tbn.size());
1411 
1412             if (tx)
1413             {
1414                 result = e.e1.implicitConvTo(tx);
1415                 if (result > MATCH.constant) // Match level is MATCH.constant at best.
1416                     result = MATCH.constant;
1417             }
1418         }
1419 
1420         // Enhancement 10724
1421         if (tb.ty == Tpointer && e.e1.op == EXP.string_)
1422             result = e.e1.implicitConvTo(t);
1423         return result;
1424     }
1425 
1426     MATCH visitTuple(TupleExp e)
1427     {
1428         auto result = e.type.implicitConvTo(t);
1429         if (result != MATCH.nomatch)
1430             return result;
1431 
1432         /* If target type is a tuple of same length, test conversion of
1433          * each expression to the corresponding type in the tuple.
1434          */
1435         TypeTuple totuple = t.isTypeTuple();
1436         if (totuple && e.exps.length == totuple.arguments.length)
1437         {
1438             result = MATCH.exact;
1439             foreach (i, ex; *e.exps)
1440             {
1441                 auto to = (*totuple.arguments)[i].type;
1442                 MATCH mi = ex.implicitConvTo(to);
1443                 if (mi < result)
1444                     result = mi;
1445             }
1446         }
1447         return result;
1448     }
1449 
1450     switch (e.op)
1451     {
1452         default                   : return visit(e);
1453         case EXP.add              : return visitAdd(e.isAddExp());
1454         case EXP.min              : return visitMin(e.isMinExp());
1455         case EXP.int64            : return visitInteger(e.isIntegerExp());
1456         case EXP.error            : return visitError(e.isErrorExp());
1457         case EXP.null_            : return visitNull(e.isNullExp());
1458         case EXP.structLiteral    : return visitStructLiteral(e.isStructLiteralExp());
1459         case EXP.string_          : return visitString(e.isStringExp());
1460         case EXP.arrayLiteral     : return visitArrayLiteral(e.isArrayLiteralExp());
1461         case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
1462         case EXP.call             : return visitCall(e.isCallExp());
1463         case EXP.address          : return visitAddr(e.isAddrExp());
1464         case EXP.symbolOffset     : return visitSymOff(e.isSymOffExp());
1465         case EXP.delegate_        : return visitDelegate(e.isDelegateExp());
1466         case EXP.function_        : return visitFunc(e.isFuncExp());
1467         case EXP.and              : return visitAnd(e.isAndExp());
1468         case EXP.or               : return visitOr(e.isOrExp());
1469         case EXP.xor              : return visitXor(e.isXorExp());
1470         case EXP.question         : return visitCond(e.isCondExp());
1471         case EXP.comma            : return visitComma(e.isCommaExp());
1472         case EXP.cast_            : return visitCast(e.isCastExp());
1473         case EXP.new_             : return visitNew(e.isNewExp());
1474         case EXP.slice            : return visitSlice(e.isSliceExp());
1475         case EXP.tuple            : return visitTuple(e.isTupleExp());
1476     }
1477 }
1478 
1479 /**
1480  * Same as implicitConvTo(); except follow C11 rules, which are quite a bit
1481  * more permissive than D.
1482  * C11 6.3 and 6.5.16.1
1483  * Params:
1484  *   e = Expression that is to be casted
1485  *   t = Expected resulting type
1486  * Returns:
1487  *   The `MATCH` level between `e.type` and `t`.
1488  */
cimplicitConvTo(Expression e,Type t)1489 MATCH cimplicitConvTo(Expression e, Type t)
1490 {
1491     Type tb = t.toBasetype();
1492     Type typeb = e.type.toBasetype();
1493 
1494     if (tb.equals(typeb))
1495         return MATCH.exact;
1496     if ((typeb.isintegral() || typeb.isfloating()) &&
1497         (tb.isintegral() || tb.isfloating()))
1498         return MATCH.convert;
1499     if (tb.ty == Tpointer && typeb.isintegral()) // C11 6.3.2.3-5
1500         return MATCH.convert;
1501     if (tb.isintegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6
1502         return MATCH.convert;
1503     if (tb.ty == Tpointer && typeb.ty == Tpointer) // C11 6.3.2.3-7
1504         return MATCH.convert;
1505 
1506     return implicitConvTo(e, t);
1507 }
1508 
1509 /*****************************************
1510  */
toStaticArrayType(SliceExp e)1511 Type toStaticArrayType(SliceExp e)
1512 {
1513     if (e.lwr && e.upr)
1514     {
1515         // For the following code to work, e should be optimized beforehand.
1516         // (eg. $ in lwr and upr should be already resolved, if possible)
1517         Expression lwr = e.lwr.optimize(WANTvalue);
1518         Expression upr = e.upr.optimize(WANTvalue);
1519         if (lwr.isConst() && upr.isConst())
1520         {
1521             size_t len = cast(size_t)(upr.toUInteger() - lwr.toUInteger());
1522             return e.type.toBasetype().nextOf().sarrayOf(len);
1523         }
1524     }
1525     else
1526     {
1527         Type t1b = e.e1.type.toBasetype();
1528         if (t1b.ty == Tsarray)
1529             return t1b;
1530     }
1531     return null;
1532 }
1533 
1534 /**************************************
1535  * Do an explicit cast.
1536  * Assume that the expression `e` does not have any indirections.
1537  * (Parameter 'att' is used to stop 'alias this' recursion)
1538  */
1539 Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
1540 {
visit(Expression e)1541     Expression visit(Expression e)
1542     {
1543         //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars());
1544         version (none)
1545         {
1546             printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
1547         }
1548         if (e.type.equals(t))
1549         {
1550             return e;
1551         }
1552         if (auto ve = e.isVarExp())
1553         {
1554             VarDeclaration v = ve.var.isVarDeclaration();
1555             if (v && v.storage_class & STC.manifest)
1556             {
1557                 auto result = e.ctfeInterpret();
1558                 /* https://issues.dlang.org/show_bug.cgi?id=18236
1559                  *
1560                  * The expression returned by ctfeInterpret points
1561                  * to the line where the manifest constant was declared
1562                  * so we need to update the location before trying to cast
1563                  */
1564                 result.loc = e.loc;
1565                 return result.castTo(sc, t);
1566             }
1567         }
1568 
1569         Type tob = t.toBasetype();
1570         Type t1b = e.type.toBasetype();
1571         if (tob.equals(t1b))
1572         {
1573             auto result = e.copy(); // because of COW for assignment to e.type
1574             result.type = t;
1575             return result;
1576         }
1577 
1578         /* Make semantic error against invalid cast between concrete types.
1579          * Assume that 'e' is never be any placeholder expressions.
1580          * The result of these checks should be consistent with CastExp::toElem().
1581          */
1582 
1583         // Fat Value types
1584         const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector);
1585         const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector);
1586 
1587         // Fat Reference types
1588         const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate);
1589         const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate);
1590 
1591         // Reference types
1592         const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass);
1593         const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass);
1594 
1595         // Arithmetic types (== valueable basic types)
1596         const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector);
1597         const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector);
1598 
1599         // Try casting the alias this member.
1600         // Return the expression if it succeeds, null otherwise.
1601         Expression tryAliasThisCast()
1602         {
1603             if (isRecursiveAliasThis(att, t1b))
1604                 return null;
1605 
1606             /* Forward the cast to our alias this member, rewrite to:
1607              *   cast(to)e1.aliasthis
1608              */
1609             auto exp = resolveAliasThis(sc, e);
1610             const errors = global.startGagging();
1611             exp = castTo(exp, sc, t, att);
1612             return global.endGagging(errors) ? null : exp;
1613         }
1614 
1615         bool hasAliasThis;
1616         if (AggregateDeclaration t1ad = isAggregate(t1b))
1617         {
1618             AggregateDeclaration toad = isAggregate(tob);
1619             if (t1ad != toad && t1ad.aliasthis)
1620             {
1621                 if (t1b.ty == Tclass && tob.ty == Tclass)
1622                 {
1623                     ClassDeclaration t1cd = t1b.isClassHandle();
1624                     ClassDeclaration tocd = tob.isClassHandle();
1625                     int offset;
1626                     if (tocd.isBaseOf(t1cd, &offset))
1627                         goto Lok;
1628                 }
1629                 hasAliasThis = true;
1630             }
1631         }
1632         else if (tob.ty == Tvector && t1b.ty != Tvector)
1633         {
1634             //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
1635             TypeVector tv = tob.isTypeVector();
1636             Expression result = new CastExp(e.loc, e, tv.elementType());
1637             result = new VectorExp(e.loc, result, tob);
1638             result = result.expressionSemantic(sc);
1639             return result;
1640         }
1641         else if (tob.ty != Tvector && t1b.ty == Tvector)
1642         {
1643             // T[n] <-- __vector(U[m])
1644             if (tob.ty == Tsarray)
1645             {
1646                 if (t1b.size(e.loc) == tob.size(e.loc))
1647                     goto Lok;
1648             }
1649             goto Lfail;
1650         }
1651         else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf()))
1652         {
1653             auto result = e.copy();
1654             result.type = t;
1655             return result;
1656         }
1657 
1658         // arithmetic values vs. other arithmetic values
1659         // arithmetic values vs. T*
1660         if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer))
1661         {
1662             goto Lok;
1663         }
1664 
1665         // arithmetic values vs. references or fat values
1666         if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV))
1667         {
1668             goto Lfail;
1669         }
1670 
1671         // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
1672         if (tob_isFV && t1b_isFV)
1673         {
1674             if (hasAliasThis)
1675             {
1676                 auto result = tryAliasThisCast();
1677                 if (result)
1678                     return result;
1679             }
1680 
1681             if (t1b.size(e.loc) == tob.size(e.loc))
1682                 goto Lok;
1683 
1684             auto ts = toAutoQualChars(e.type, t);
1685             e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes",
1686                 e.toChars(), ts[0], ts[1]);
1687             return ErrorExp.get();
1688         }
1689 
1690         // Fat values vs. null or references
1691         if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR))
1692         {
1693             if (tob.ty == Tpointer && t1b.ty == Tsarray)
1694             {
1695                 // T[n] sa;
1696                 // cast(U*)sa; // ==> cast(U*)sa.ptr;
1697                 return new AddrExp(e.loc, e, t);
1698             }
1699             if (tob.ty == Tarray && t1b.ty == Tsarray)
1700             {
1701                 // T[n] sa;
1702                 // cast(U[])sa; // ==> cast(U[])sa[];
1703                 if (global.params.useDIP1000 == FeatureState.enabled)
1704                 {
1705                     if (auto v = expToVariable(e))
1706                     {
1707                         if (e.type.hasPointers() && !checkAddressVar(sc, e, v))
1708                             goto Lfail;
1709                     }
1710                 }
1711                 const fsize = t1b.nextOf().size();
1712                 const tsize = tob.nextOf().size();
1713                 if (fsize == SIZE_INVALID || tsize == SIZE_INVALID)
1714                 {
1715                     return ErrorExp.get();
1716                 }
1717                 if (fsize != tsize)
1718                 {
1719                     const dim = t1b.isTypeSArray().dim.toInteger();
1720                     if (tsize == 0 || (dim * fsize) % tsize != 0)
1721                     {
1722                         e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
1723                                 e.toChars(), e.type.toChars(), t.toChars());
1724                         return ErrorExp.get();
1725                     }
1726                 }
1727                 goto Lok;
1728             }
1729             goto Lfail;
1730         }
1731 
1732         /* For references, any reinterpret casts are allowed to same 'ty' type.
1733          *      T* to U*
1734          *      R1 function(P1) to R2 function(P2)
1735          *      R1 delegate(P1) to R2 delegate(P2)
1736          *      T[] to U[]
1737          *      V1[K1] to V2[K2]
1738          *      class/interface A to B  (will be a dynamic cast if possible)
1739          */
1740         if (tob.ty == t1b.ty && tob_isR && t1b_isR)
1741             goto Lok;
1742 
1743         // typeof(null) <-- non-null references or values
1744         if (tob.ty == Tnull && t1b.ty != Tnull)
1745             goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629
1746         // typeof(null) --> non-null references or arithmetic values
1747         if (t1b.ty == Tnull && tob.ty != Tnull)
1748             goto Lok;
1749 
1750         // Check size mismatch of references.
1751         // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
1752         if (tob_isFR && t1b_isR || t1b_isFR && tob_isR)
1753         {
1754             if (tob.ty == Tpointer && t1b.ty == Tarray)
1755             {
1756                 // T[] da;
1757                 // cast(U*)da; // ==> cast(U*)da.ptr;
1758                 goto Lok;
1759             }
1760             if (tob.ty == Tpointer && t1b.ty == Tdelegate)
1761             {
1762                 // void delegate() dg;
1763                 // cast(U*)dg; // ==> cast(U*)dg.ptr;
1764                 // Note that it happens even when U is a Tfunction!
1765                 e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars());
1766                 goto Lok;
1767             }
1768             goto Lfail;
1769         }
1770 
1771         if (t1b.ty == Tvoid && tob.ty != Tvoid)
1772         {
1773         Lfail:
1774             /* if the cast cannot be performed, maybe there is an alias
1775              * this that can be used for casting.
1776              */
1777             if (hasAliasThis)
1778             {
1779                 auto result = tryAliasThisCast();
1780                 if (result)
1781                     return result;
1782             }
1783             e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars());
1784             return ErrorExp.get();
1785         }
1786 
1787     Lok:
1788         auto result = new CastExp(e.loc, e, t);
1789         result.type = t; // Don't call semantic()
1790         //printf("Returning: %s\n", result.toChars());
1791         return result;
1792     }
1793 
visitError(ErrorExp e)1794     Expression visitError(ErrorExp e)
1795     {
1796         return e;
1797     }
1798 
visitReal(RealExp e)1799     Expression visitReal(RealExp e)
1800     {
1801         if (!e.type.equals(t))
1802         {
1803             if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary()))
1804             {
1805                 auto result = e.copy();
1806                 result.type = t;
1807                 return result;
1808             }
1809             else
1810                 return visit(e);
1811         }
1812         return e;
1813     }
1814 
visitComplex(ComplexExp e)1815     Expression visitComplex(ComplexExp e)
1816     {
1817         if (!e.type.equals(t))
1818         {
1819             if (e.type.iscomplex() && t.iscomplex())
1820             {
1821                 auto result = e.copy();
1822                 result.type = t;
1823                 return result;
1824             }
1825             else
1826                 return visit(e);
1827         }
1828         return e;
1829     }
1830 
visitStructLiteral(StructLiteralExp e)1831     Expression visitStructLiteral(StructLiteralExp e)
1832     {
1833         auto result = visit(e);
1834         if (auto sle = result.isStructLiteralExp())
1835             sle.stype = t; // commit type
1836         return result;
1837     }
1838 
visitString(StringExp e)1839     Expression visitString(StringExp e)
1840     {
1841         /* This follows copy-on-write; any changes to 'this'
1842          * will result in a copy.
1843          * The this.string member is considered immutable.
1844          */
1845         int copied = 0;
1846 
1847         //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
1848 
1849         if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid &&
1850             (!sc || !(sc.flags & SCOPE.Cfile)))
1851         {
1852             e.error("cannot convert string literal to `void*`");
1853             return ErrorExp.get();
1854         }
1855 
1856         StringExp se = e;
1857 
1858         Expression lcast()
1859         {
1860             auto result = new CastExp(e.loc, se, t);
1861             result.type = t; // so semantic() won't be run on e
1862             return result;
1863         }
1864 
1865         if (!e.committed)
1866         {
1867             se = e.copy().isStringExp();
1868             se.committed = 1;
1869             copied = 1;
1870         }
1871 
1872         if (e.type.equals(t))
1873         {
1874             return se;
1875         }
1876 
1877         Type tb = t.toBasetype();
1878         Type typeb = e.type.toBasetype();
1879 
1880         //printf("\ttype = %s\n", e.type.toChars());
1881         if (tb.ty == Tdelegate && typeb.ty != Tdelegate)
1882         {
1883             return visit(e);
1884         }
1885 
1886         if (typeb.equals(tb))
1887         {
1888             if (!copied)
1889             {
1890                 se = e.copy().isStringExp();
1891                 copied = 1;
1892             }
1893             se.type = t;
1894             return se;
1895         }
1896 
1897         /* Handle reinterpret casts:
1898          *  cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
1899          *  cast(wchar[2])"abcd"c --> [\u6261, \u6463]
1900          *  cast(wchar[1])"abcd"c --> [\u6261]
1901          *  cast(char[4])"a" --> ['a', 0, 0, 0]
1902          */
1903         if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray)
1904         {
1905             se = e.copy().isStringExp();
1906             uinteger_t szx = tb.nextOf().size();
1907             assert(szx <= 255);
1908             se.sz = cast(ubyte)szx;
1909             se.len = cast(size_t)tb.isTypeSArray().dim.toInteger();
1910             se.committed = 1;
1911             se.type = t;
1912 
1913             /* If larger than source, pad with zeros.
1914              */
1915             const fullSize = (se.len + 1) * se.sz; // incl. terminating 0
1916             if (fullSize > (e.len + 1) * e.sz)
1917             {
1918                 void* s = mem.xmalloc(fullSize);
1919                 const srcSize = e.len * e.sz;
1920                 const data = se.peekData();
1921                 memcpy(s, data.ptr, srcSize);
1922                 memset(s + srcSize, 0, fullSize - srcSize);
1923                 se.setData(s, se.len, se.sz);
1924             }
1925             return se;
1926         }
1927 
1928         if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer)
1929         {
1930             if (!copied)
1931             {
1932                 se = e.copy().isStringExp();
1933                 copied = 1;
1934             }
1935             return lcast();
1936         }
1937         if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer)
1938         {
1939             if (!copied)
1940             {
1941                 se = e.copy().isStringExp();
1942                 copied = 1;
1943             }
1944             return lcast();
1945         }
1946 
1947         const nextSz = typeb.nextOf().size();
1948         if (nextSz == SIZE_INVALID)
1949         {
1950             return ErrorExp.get();
1951         }
1952         if (nextSz == tb.nextOf().size())
1953         {
1954             if (!copied)
1955             {
1956                 se = e.copy().isStringExp();
1957                 copied = 1;
1958             }
1959             if (tb.ty == Tsarray)
1960                 goto L2; // handle possible change in static array dimension
1961             se.type = t;
1962             return se;
1963         }
1964 
1965         if (e.committed)
1966             goto Lcast;
1967 
1968         auto X(T, U)(T tf, U tt)
1969         {
1970             return (cast(int)tf * 256 + cast(int)tt);
1971         }
1972 
1973         {
1974             OutBuffer buffer;
1975             size_t newlen = 0;
1976             int tfty = typeb.nextOf().toBasetype().ty;
1977             int ttty = tb.nextOf().toBasetype().ty;
1978             switch (X(tfty, ttty))
1979             {
1980             case X(Tchar, Tchar):
1981             case X(Twchar, Twchar):
1982             case X(Tdchar, Tdchar):
1983                 break;
1984 
1985             case X(Tchar, Twchar):
1986                 for (size_t u = 0; u < e.len;)
1987                 {
1988                     dchar c;
1989                     if (const s = utf_decodeChar(se.peekString(), u, c))
1990                         e.error("%.*s", cast(int)s.length, s.ptr);
1991                     else
1992                         buffer.writeUTF16(c);
1993                 }
1994                 newlen = buffer.length / 2;
1995                 buffer.writeUTF16(0);
1996                 goto L1;
1997 
1998             case X(Tchar, Tdchar):
1999                 for (size_t u = 0; u < e.len;)
2000                 {
2001                     dchar c;
2002                     if (const s = utf_decodeChar(se.peekString(), u, c))
2003                         e.error("%.*s", cast(int)s.length, s.ptr);
2004                     buffer.write4(c);
2005                     newlen++;
2006                 }
2007                 buffer.write4(0);
2008                 goto L1;
2009 
2010             case X(Twchar, Tchar):
2011                 for (size_t u = 0; u < e.len;)
2012                 {
2013                     dchar c;
2014                     if (const s = utf_decodeWchar(se.peekWstring(), u, c))
2015                         e.error("%.*s", cast(int)s.length, s.ptr);
2016                     else
2017                         buffer.writeUTF8(c);
2018                 }
2019                 newlen = buffer.length;
2020                 buffer.writeUTF8(0);
2021                 goto L1;
2022 
2023             case X(Twchar, Tdchar):
2024                 for (size_t u = 0; u < e.len;)
2025                 {
2026                     dchar c;
2027                     if (const s = utf_decodeWchar(se.peekWstring(), u, c))
2028                         e.error("%.*s", cast(int)s.length, s.ptr);
2029                     buffer.write4(c);
2030                     newlen++;
2031                 }
2032                 buffer.write4(0);
2033                 goto L1;
2034 
2035             case X(Tdchar, Tchar):
2036                 for (size_t u = 0; u < e.len; u++)
2037                 {
2038                     uint c = se.peekDstring()[u];
2039                     if (!utf_isValidDchar(c))
2040                         e.error("invalid UCS-32 char \\U%08x", c);
2041                     else
2042                         buffer.writeUTF8(c);
2043                     newlen++;
2044                 }
2045                 newlen = buffer.length;
2046                 buffer.writeUTF8(0);
2047                 goto L1;
2048 
2049             case X(Tdchar, Twchar):
2050                 for (size_t u = 0; u < e.len; u++)
2051                 {
2052                     uint c = se.peekDstring()[u];
2053                     if (!utf_isValidDchar(c))
2054                         e.error("invalid UCS-32 char \\U%08x", c);
2055                     else
2056                         buffer.writeUTF16(c);
2057                     newlen++;
2058                 }
2059                 newlen = buffer.length / 2;
2060                 buffer.writeUTF16(0);
2061                 goto L1;
2062 
2063             L1:
2064                 if (!copied)
2065                 {
2066                     se = e.copy().isStringExp();
2067                     copied = 1;
2068                 }
2069 
2070                 {
2071                     uinteger_t szx = tb.nextOf().size();
2072                     assert(szx <= 255);
2073                     se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx);
2074                 }
2075                 break;
2076 
2077             default:
2078                 assert(typeb.nextOf().size() != tb.nextOf().size());
2079                 goto Lcast;
2080             }
2081         }
2082     L2:
2083         assert(copied);
2084 
2085         // See if need to truncate or extend the literal
2086         if (auto tsa = tb.isTypeSArray())
2087         {
2088             size_t dim2 = cast(size_t)tsa.dim.toInteger();
2089             //printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
2090 
2091             // Changing dimensions
2092             if (dim2 != se.len)
2093             {
2094                 // Copy when changing the string literal
2095                 const newsz = se.sz;
2096                 const d = (dim2 < se.len) ? dim2 : se.len;
2097                 void* s = mem.xmalloc((dim2 + 1) * newsz);
2098                 memcpy(s, se.peekData().ptr, d * newsz);
2099                 // Extend with 0, add terminating 0
2100                 memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz);
2101                 se.setData(s, dim2, newsz);
2102             }
2103         }
2104         se.type = t;
2105         return se;
2106 
2107     Lcast:
2108         auto result = new CastExp(e.loc, se, t);
2109         result.type = t; // so semantic() won't be run on e
2110         return result;
2111     }
2112 
visitAddr(AddrExp e)2113     Expression visitAddr(AddrExp e)
2114     {
2115         version (none)
2116         {
2117             printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
2118         }
2119         Type tb = t.toBasetype();
2120         Type typeb = e.type.toBasetype();
2121 
2122         if (tb.equals(typeb))
2123         {
2124             auto result = e.copy();
2125             result.type = t;
2126             return result;
2127         }
2128 
2129         // Look for pointers to functions where the functions are overloaded.
2130         if (e.e1.isOverExp() &&
2131             (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
2132         {
2133             OverExp eo = e.e1.isOverExp();
2134             FuncDeclaration f = null;
2135             for (size_t i = 0; i < eo.vars.a.dim; i++)
2136             {
2137                 auto s = eo.vars.a[i];
2138                 auto f2 = s.isFuncDeclaration();
2139                 assert(f2);
2140                 if (f2.overloadExactMatch(tb.nextOf()))
2141                 {
2142                     if (f)
2143                     {
2144                         /* Error if match in more than one overload set,
2145                          * even if one is a 'better' match than the other.
2146                          */
2147                         ScopeDsymbol.multiplyDefined(e.loc, f, f2);
2148                     }
2149                     else
2150                         f = f2;
2151                 }
2152             }
2153             if (f)
2154             {
2155                 f.tookAddressOf++;
2156                 auto se = new SymOffExp(e.loc, f, 0, false);
2157                 auto se2 = se.expressionSemantic(sc);
2158                 // Let SymOffExp::castTo() do the heavy lifting
2159                 return visit(se2);
2160             }
2161         }
2162 
2163         if (e.e1.isVarExp() &&
2164             typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
2165             tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
2166         {
2167             auto ve = e.e1.isVarExp();
2168             auto f = ve.var.isFuncDeclaration();
2169             if (f)
2170             {
2171                 assert(f.isImportedSymbol());
2172                 f = f.overloadExactMatch(tb.nextOf());
2173                 if (f)
2174                 {
2175                     Expression result = new VarExp(e.loc, f, false);
2176                     result.type = f.type;
2177                     result = new AddrExp(e.loc, result, t);
2178                     return result;
2179                 }
2180             }
2181         }
2182 
2183         if (auto f = isFuncAddress(e))
2184         {
2185             if (f.checkForwardRef(e.loc))
2186             {
2187                 return ErrorExp.get();
2188             }
2189         }
2190 
2191         return visit(e);
2192     }
2193 
visitTuple(TupleExp e)2194     Expression visitTuple(TupleExp e)
2195     {
2196         if (e.type.equals(t))
2197         {
2198             return e;
2199         }
2200 
2201         /* If target type is a tuple of same length, cast each expression to
2202          * the corresponding type in the tuple.
2203          */
2204         TypeTuple totuple;
2205         if (auto tt = t.isTypeTuple())
2206             totuple = e.exps.length == tt.arguments.length ? tt : null;
2207 
2208         TupleExp te = e.copy().isTupleExp();
2209         te.e0 = e.e0 ? e.e0.copy() : null;
2210         te.exps = e.exps.copy();
2211         for (size_t i = 0; i < te.exps.dim; i++)
2212         {
2213             Expression ex = (*te.exps)[i];
2214             ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t);
2215             (*te.exps)[i] = ex;
2216         }
2217         if (totuple)
2218             te.type = totuple;
2219         return te;
2220 
2221         /* Questionable behavior: In here, result.type is not set to t
2222          *  if target type is not a tuple of same length.
2223          * Therefoe:
2224          *  TypeTuple!(int, int) values;
2225          *  auto values2 = cast(long)values;
2226          *  // typeof(values2) == TypeTuple!(int, int) !!
2227          *
2228          * Only when the casted tuple is immediately expanded, it would work.
2229          *  auto arr = [cast(long)values];
2230          *  // typeof(arr) == long[]
2231          */
2232     }
2233 
visitArrayLiteral(ArrayLiteralExp e)2234     Expression visitArrayLiteral(ArrayLiteralExp e)
2235     {
2236         version (none)
2237         {
2238             printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
2239         }
2240 
2241         ArrayLiteralExp ae = e;
2242 
2243         Type tb = t.toBasetype();
2244         if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled)
2245         {
2246             if (checkArrayLiteralEscape(sc, ae, false))
2247             {
2248                 return ErrorExp.get();
2249             }
2250         }
2251 
2252         if (e.type == t)
2253         {
2254             return e;
2255         }
2256         Type typeb = e.type.toBasetype();
2257 
2258         if ((tb.ty == Tarray || tb.ty == Tsarray) &&
2259             (typeb.ty == Tarray || typeb.ty == Tsarray))
2260         {
2261             if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid)
2262             {
2263                 // Don't do anything to cast non-void[] to void[]
2264             }
2265             else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid)
2266             {
2267                 // Don't do anything for casting void[n] to others
2268             }
2269             else
2270             {
2271                 if (auto tsa = tb.isTypeSArray())
2272                 {
2273                     if (e.elements.dim != tsa.dim.toInteger())
2274                         goto L1;
2275                 }
2276 
2277                 ae = e.copy().isArrayLiteralExp();
2278                 if (e.basis)
2279                     ae.basis = e.basis.castTo(sc, tb.nextOf());
2280                 ae.elements = e.elements.copy();
2281                 for (size_t i = 0; i < e.elements.dim; i++)
2282                 {
2283                     Expression ex = (*e.elements)[i];
2284                     if (!ex)
2285                         continue;
2286                     ex = ex.castTo(sc, tb.nextOf());
2287                     (*ae.elements)[i] = ex;
2288                 }
2289                 ae.type = t;
2290                 return ae;
2291             }
2292         }
2293         else if (tb.ty == Tpointer && typeb.ty == Tsarray)
2294         {
2295             Type tp = typeb.nextOf().pointerTo();
2296             if (!tp.equals(ae.type))
2297             {
2298                 ae = e.copy().isArrayLiteralExp();
2299                 ae.type = tp;
2300             }
2301         }
2302         else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
2303         {
2304             // Convert array literal to vector type
2305             TypeVector tv = tb.isTypeVector();
2306             TypeSArray tbase = tv.basetype.isTypeSArray();
2307             assert(tbase.ty == Tsarray);
2308             const edim = e.elements.dim;
2309             const tbasedim = tbase.dim.toInteger();
2310             if (edim > tbasedim)
2311                 goto L1;
2312 
2313             ae = e.copy().isArrayLiteralExp();
2314             ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642
2315             ae.elements = e.elements.copy();
2316             Type telement = tv.elementType();
2317             foreach (i; 0 .. edim)
2318             {
2319                 Expression ex = (*e.elements)[i];
2320                 ex = ex.castTo(sc, telement);
2321                 (*ae.elements)[i] = ex;
2322             }
2323             // Fill in the rest with the default initializer
2324             ae.elements.setDim(cast(size_t)tbasedim);
2325             foreach (i; edim .. cast(size_t)tbasedim)
2326             {
2327                 Expression ex = typeb.nextOf.defaultInitLiteral(e.loc);
2328                 ex = ex.castTo(sc, telement);
2329                 (*ae.elements)[i] = ex;
2330             }
2331             Expression ev = new VectorExp(e.loc, ae, tb);
2332             ev = ev.expressionSemantic(sc);
2333             return ev;
2334         }
2335     L1:
2336         return visit(ae);
2337     }
2338 
visitAssocArrayLiteral(AssocArrayLiteralExp e)2339     Expression visitAssocArrayLiteral(AssocArrayLiteralExp e)
2340     {
2341         //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
2342         if (e.type == t)
2343         {
2344             return e;
2345         }
2346 
2347         Type tb = t.toBasetype();
2348         Type typeb = e.type.toBasetype();
2349 
2350         if (tb.ty == Taarray && typeb.ty == Taarray &&
2351             tb.nextOf().toBasetype().ty != Tvoid)
2352         {
2353             AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp();
2354             ae.keys = e.keys.copy();
2355             ae.values = e.values.copy();
2356             assert(e.keys.dim == e.values.dim);
2357             for (size_t i = 0; i < e.keys.dim; i++)
2358             {
2359                 Expression ex = (*e.values)[i];
2360                 ex = ex.castTo(sc, tb.nextOf());
2361                 (*ae.values)[i] = ex;
2362 
2363                 ex = (*e.keys)[i];
2364                 ex = ex.castTo(sc, tb.isTypeAArray().index);
2365                 (*ae.keys)[i] = ex;
2366             }
2367             ae.type = t;
2368             return ae;
2369         }
2370         return visit(e);
2371     }
2372 
visitSymOff(SymOffExp e)2373     Expression visitSymOff(SymOffExp e)
2374     {
2375         version (none)
2376         {
2377             printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
2378         }
2379         if (e.type == t && !e.hasOverloads)
2380         {
2381             return e;
2382         }
2383 
2384         Type tb = t.toBasetype();
2385         Type typeb = e.type.toBasetype();
2386 
2387         if (tb.equals(typeb))
2388         {
2389             auto result = e.copy();
2390             result.type = t;
2391             result.isSymOffExp().hasOverloads = false;
2392             return result;
2393         }
2394 
2395         // Look for pointers to functions where the functions are overloaded.
2396         if (e.hasOverloads &&
2397             typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
2398             (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
2399         {
2400             FuncDeclaration f = e.var.isFuncDeclaration();
2401             f = f ? f.overloadExactMatch(tb.nextOf()) : null;
2402             if (f)
2403             {
2404                 Expression result;
2405                 if (tb.ty == Tdelegate)
2406                 {
2407                     if (f.needThis() && hasThis(sc))
2408                     {
2409                         result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false);
2410                         result = result.expressionSemantic(sc);
2411                     }
2412                     else if (f.needThis())
2413                     {
2414                         e.error("no `this` to create delegate for `%s`", f.toChars());
2415                         return ErrorExp.get();
2416                     }
2417                     else if (f.isNested())
2418                     {
2419                         result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false);
2420                         result = result.expressionSemantic(sc);
2421                     }
2422                     else
2423                     {
2424                         e.error("cannot cast from function pointer to delegate");
2425                         return ErrorExp.get();
2426                     }
2427                 }
2428                 else
2429                 {
2430                     result = new SymOffExp(e.loc, f, 0, false);
2431                     result.type = t;
2432                 }
2433                 f.tookAddressOf++;
2434                 return result;
2435             }
2436         }
2437 
2438         if (auto f = isFuncAddress(e))
2439         {
2440             if (f.checkForwardRef(e.loc))
2441             {
2442                 return ErrorExp.get();
2443             }
2444         }
2445 
2446         return visit(e);
2447     }
2448 
visitDelegate(DelegateExp e)2449     Expression visitDelegate(DelegateExp e)
2450     {
2451         version (none)
2452         {
2453             printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
2454         }
2455         static immutable msg = "cannot form delegate due to covariant return type";
2456 
2457         Type tb = t.toBasetype();
2458         Type typeb = e.type.toBasetype();
2459 
2460         if (tb.equals(typeb) && !e.hasOverloads)
2461         {
2462             int offset;
2463             e.func.tookAddressOf++;
2464             if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset)
2465                 e.error("%s", msg.ptr);
2466             auto result = e.copy();
2467             result.type = t;
2468             return result;
2469         }
2470 
2471         // Look for delegates to functions where the functions are overloaded.
2472         if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
2473         {
2474             if (e.func)
2475             {
2476                 auto f = e.func.overloadExactMatch(tb.nextOf());
2477                 if (f)
2478                 {
2479                     int offset;
2480                     if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
2481                         e.error("%s", msg.ptr);
2482                     if (f != e.func)    // if address not already marked as taken
2483                         f.tookAddressOf++;
2484                     auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
2485                     result.type = t;
2486                     return result;
2487                 }
2488                 if (e.func.tintro)
2489                     e.error("%s", msg.ptr);
2490             }
2491         }
2492 
2493         if (auto f = isFuncAddress(e))
2494         {
2495             if (f.checkForwardRef(e.loc))
2496             {
2497                 return ErrorExp.get();
2498             }
2499         }
2500 
2501         return visit(e);
2502     }
2503 
visitFunc(FuncExp e)2504     Expression visitFunc(FuncExp e)
2505     {
2506         //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars());
2507         FuncExp fe;
2508         if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch)
2509         {
2510             return fe;
2511         }
2512         return visit(e);
2513     }
2514 
visitCond(CondExp e)2515     Expression visitCond(CondExp e)
2516     {
2517         if (!e.type.equals(t))
2518         {
2519             auto result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t));
2520             result.type = t;
2521             return result;
2522         }
2523         return e;
2524     }
2525 
visitComma(CommaExp e)2526     Expression visitComma(CommaExp e)
2527     {
2528         Expression e2c = e.e2.castTo(sc, t);
2529 
2530         if (e2c != e.e2)
2531         {
2532             auto result = new CommaExp(e.loc, e.e1, e2c);
2533             result.type = e2c.type;
2534             return result;
2535         }
2536         else
2537         {
2538             e.type = e.e2.type;
2539             return e;
2540         }
2541     }
2542 
visitSlice(SliceExp e)2543     Expression visitSlice(SliceExp e)
2544     {
2545         //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars());
2546 
2547         Type tb = t.toBasetype();
2548         Type typeb = e.type.toBasetype();
2549 
2550         if (e.type.equals(t) || typeb.ty != Tarray ||
2551             (tb.ty != Tarray && tb.ty != Tsarray))
2552         {
2553             return visit(e);
2554         }
2555 
2556         if (tb.ty == Tarray)
2557         {
2558             if (typeb.nextOf().equivalent(tb.nextOf()))
2559             {
2560                 // T[] to const(T)[]
2561                 auto result = e.copy();
2562                 result.type = t;
2563                 return result;
2564             }
2565             else
2566             {
2567                 return visit(e);
2568             }
2569         }
2570 
2571         // Handle the cast from Tarray to Tsarray with CT-known slicing
2572 
2573         TypeSArray tsa = toStaticArrayType(e).isTypeSArray();
2574         if (tsa && tsa.size(e.loc) == tb.size(e.loc))
2575         {
2576             /* Match if the sarray sizes are equal:
2577              *  T[a .. b] to const(T)[b-a]
2578              *  T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
2579              *
2580              * If a SliceExp has Tsarray, it will become lvalue.
2581              * That's handled in SliceExp::isLvalue and toLvalue
2582              */
2583             auto result = e.copy();
2584             result.type = t;
2585             return result;
2586         }
2587         if (tsa && tsa.dim.equals(tb.isTypeSArray().dim))
2588         {
2589             /* Match if the dimensions are equal
2590              * with the implicit conversion of e.e1:
2591              *  cast(float[2]) [2.0, 1.0, 0.0][0..2];
2592              */
2593             Type t1b = e.e1.type.toBasetype();
2594             if (t1b.ty == Tsarray)
2595                 t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger());
2596             else if (t1b.ty == Tarray)
2597                 t1b = tb.nextOf().arrayOf();
2598             else if (t1b.ty == Tpointer)
2599                 t1b = tb.nextOf().pointerTo();
2600             else
2601                 assert(0);
2602             if (e.e1.implicitConvTo(t1b) > MATCH.nomatch)
2603             {
2604                 Expression e1x = e.e1.implicitCastTo(sc, t1b);
2605                 assert(e1x.op != EXP.error);
2606                 e = e.copy().isSliceExp();
2607                 e.e1 = e1x;
2608                 e.type = t;
2609                 return e;
2610             }
2611         }
2612         auto ts = toAutoQualChars(tsa ? tsa : e.type, t);
2613         e.error("cannot cast expression `%s` of type `%s` to `%s`",
2614             e.toChars(), ts[0], ts[1]);
2615         return ErrorExp.get();
2616     }
2617 
2618     // Casting to noreturn isn't an actual cast
2619     // Rewrite cast(<qual> noreturn) <exp>
2620     // as      <exp>, assert(false)
2621     if (t.isTypeNoreturn())
2622     {
2623         // Don't generate an unreachable assert(false) if e will abort
2624         if (e.type.isTypeNoreturn())
2625         {
2626             // Paint e to accomodate for different type qualifiers
2627             e.type = t;
2628             return e;
2629         }
2630 
2631         auto ini = t.defaultInitLiteral(e.loc);
2632         return Expression.combine(e, ini);
2633     }
2634 
2635     switch (e.op)
2636     {
2637         default                   : return visit(e);
2638         case EXP.error            : return visitError(e.isErrorExp());
2639         case EXP.float64          : return visitReal(e.isRealExp());
2640         case EXP.complex80        : return visitComplex(e.isComplexExp());
2641         case EXP.structLiteral    : return visitStructLiteral(e.isStructLiteralExp());
2642         case EXP.string_          : return visitString(e.isStringExp());
2643         case EXP.address          : return visitAddr(e.isAddrExp());
2644         case EXP.tuple            : return visitTuple(e.isTupleExp());
2645         case EXP.arrayLiteral     : return visitArrayLiteral(e.isArrayLiteralExp());
2646         case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
2647         case EXP.symbolOffset     : return visitSymOff(e.isSymOffExp());
2648         case EXP.delegate_        : return visitDelegate(e.isDelegateExp());
2649         case EXP.function_        : return visitFunc(e.isFuncExp());
2650         case EXP.question         : return visitCond(e.isCondExp());
2651         case EXP.comma            : return visitComma(e.isCommaExp());
2652         case EXP.slice            : return visitSlice(e.isSliceExp());
2653     }
2654 }
2655 
2656 /****************************************
2657  * Set type inference target
2658  *      t       Target type
2659  *      flag    1: don't put an error when inference fails
2660  */
2661 Expression inferType(Expression e, Type t, int flag = 0)
2662 {
visitAle(ArrayLiteralExp ale)2663     Expression visitAle(ArrayLiteralExp ale)
2664     {
2665         Type tb = t.toBasetype();
2666         if (tb.ty == Tarray || tb.ty == Tsarray)
2667         {
2668             Type tn = tb.nextOf();
2669             if (ale.basis)
2670                 ale.basis = inferType(ale.basis, tn, flag);
2671             for (size_t i = 0; i < ale.elements.dim; i++)
2672             {
2673                 if (Expression e = (*ale.elements)[i])
2674                 {
2675                     e = inferType(e, tn, flag);
2676                     (*ale.elements)[i] = e;
2677                 }
2678             }
2679         }
2680         return ale;
2681     }
2682 
visitAar(AssocArrayLiteralExp aale)2683     Expression visitAar(AssocArrayLiteralExp aale)
2684     {
2685         Type tb = t.toBasetype();
2686         if (auto taa = tb.isTypeAArray())
2687         {
2688             Type ti = taa.index;
2689             Type tv = taa.nextOf();
2690             for (size_t i = 0; i < aale.keys.dim; i++)
2691             {
2692                 if (Expression e = (*aale.keys)[i])
2693                 {
2694                     e = inferType(e, ti, flag);
2695                     (*aale.keys)[i] = e;
2696                 }
2697             }
2698             for (size_t i = 0; i < aale.values.dim; i++)
2699             {
2700                 if (Expression e = (*aale.values)[i])
2701                 {
2702                     e = inferType(e, tv, flag);
2703                     (*aale.values)[i] = e;
2704                 }
2705             }
2706         }
2707         return aale;
2708     }
2709 
visitFun(FuncExp fe)2710     Expression visitFun(FuncExp fe)
2711     {
2712         //printf("FuncExp::inferType('%s'), to=%s\n", fe.type ? fe.type.toChars() : "null", t.toChars());
2713         if (t.ty == Tdelegate || t.ty == Tpointer && t.nextOf().ty == Tfunction)
2714         {
2715             fe.fd.treq = t;
2716         }
2717         return fe;
2718     }
2719 
visitTer(CondExp ce)2720     Expression visitTer(CondExp ce)
2721     {
2722         Type tb = t.toBasetype();
2723         ce.e1 = inferType(ce.e1, tb, flag);
2724         ce.e2 = inferType(ce.e2, tb, flag);
2725         return ce;
2726     }
2727 
2728     if (t) switch (e.op)
2729     {
2730         case EXP.arrayLiteral:      return visitAle(e.isArrayLiteralExp());
2731         case EXP.assocArrayLiteral: return visitAar(e.isAssocArrayLiteralExp());
2732         case EXP.function_:         return visitFun(e.isFuncExp());
2733         case EXP.question:          return visitTer(e.isCondExp());
2734         default:
2735     }
2736     return e;
2737 }
2738 
2739 /****************************************
2740  * Scale addition/subtraction to/from pointer.
2741  */
scaleFactor(BinExp be,Scope * sc)2742 Expression scaleFactor(BinExp be, Scope* sc)
2743 {
2744     Type t1b = be.e1.type.toBasetype();
2745     Type t2b = be.e2.type.toBasetype();
2746     Expression eoff;
2747 
2748     if (t1b.ty == Tpointer && t2b.isintegral())
2749     {
2750         // Need to adjust operator by the stride
2751         // Replace (ptr + int) with (ptr + (int * stride))
2752         Type t = Type.tptrdiff_t;
2753 
2754         uinteger_t stride = t1b.nextOf().size(be.loc);
2755         if (!t.equals(t2b))
2756             be.e2 = be.e2.castTo(sc, t);
2757         eoff = be.e2;
2758         be.e2 = new MulExp(be.loc, be.e2, new IntegerExp(Loc.initial, stride, t));
2759         be.e2.type = t;
2760         be.type = be.e1.type;
2761     }
2762     else if (t2b.ty == Tpointer && t1b.isintegral())
2763     {
2764         // Need to adjust operator by the stride
2765         // Replace (int + ptr) with (ptr + (int * stride))
2766         Type t = Type.tptrdiff_t;
2767         Expression e;
2768 
2769         uinteger_t stride = t2b.nextOf().size(be.loc);
2770         if (!t.equals(t1b))
2771             e = be.e1.castTo(sc, t);
2772         else
2773             e = be.e1;
2774         eoff = e;
2775         e = new MulExp(be.loc, e, new IntegerExp(Loc.initial, stride, t));
2776         e.type = t;
2777         be.type = be.e2.type;
2778         be.e1 = be.e2;
2779         be.e2 = e;
2780     }
2781     else
2782         assert(0);
2783 
2784     if (sc.func && !sc.intypeof)
2785     {
2786         eoff = eoff.optimize(WANTvalue);
2787         if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
2788         {
2789         }
2790         else if (sc.func.setUnsafe())
2791         {
2792             be.error("pointer arithmetic not allowed in @safe functions");
2793             return ErrorExp.get();
2794         }
2795     }
2796 
2797     return be;
2798 }
2799 
2800 /**************************************
2801  * Return true if e is an empty array literal with dimensionality
2802  * equal to or less than type of other array.
2803  * [], [[]], [[[]]], etc.
2804  * I.e., make sure that [1,2] is compatible with [],
2805  * [[1,2]] is compatible with [[]], etc.
2806  */
isVoidArrayLiteral(Expression e,Type other)2807 private bool isVoidArrayLiteral(Expression e, Type other)
2808 {
2809     while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && (e.isArrayLiteralExp().elements.dim == 1))
2810     {
2811         auto ale = e.isArrayLiteralExp();
2812         e = ale[0];
2813         if (other.ty == Tsarray || other.ty == Tarray)
2814             other = other.nextOf();
2815         else
2816             return false;
2817     }
2818     if (other.ty != Tsarray && other.ty != Tarray)
2819         return false;
2820     Type t = e.type;
2821     return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && e.isArrayLiteralExp().elements.dim == 0);
2822 }
2823 
2824 /**
2825  * Merge types of `e1` and `e2` into a common subset
2826  *
2827  * Parameters `e1` and `e2` will be rewritten in place as needed.
2828  *
2829  * Params:
2830  *     sc  = Current scope
2831  *     op  = Operator such as `e1 op e2`. In practice, either EXP.question
2832  *           or one of the binary operator.
2833  *     pe1 = The LHS of the operation, will be rewritten
2834  *     pe2 = The RHS of the operation, will be rewritten
2835  *
2836  * Returns:
2837  *      The resulting type in case of success, `null` in case of error
2838  */
typeMerge(Scope * sc,EXP op,ref Expression pe1,ref Expression pe2)2839 Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2)
2840 {
2841     //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
2842 
2843     Expression e1 = pe1;
2844     Expression e2 = pe2;
2845 
2846     // ImportC: do array/function conversions
2847     if (sc)
2848     {
2849         e1 = e1.arrayFuncConv(sc);
2850         e2 = e2.arrayFuncConv(sc);
2851     }
2852 
2853     Type Lret(Type result)
2854     {
2855         pe1 = e1;
2856         pe2 = e2;
2857 
2858         version (none)
2859         {
2860             printf("-typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
2861             if (e1.type)
2862                 printf("\tt1 = %s\n", e1.type.toChars());
2863             if (e2.type)
2864                 printf("\tt2 = %s\n", e2.type.toChars());
2865             printf("\ttype = %s\n", result.toChars());
2866         }
2867         return result;
2868     }
2869 
2870     /// Converts one of the expression to the other
2871     Type convert(ref Expression from, Type to)
2872     {
2873         from = from.castTo(sc, to);
2874         return Lret(to);
2875     }
2876 
2877     /// Converts both expression to a third type
2878     Type coerce(Type towards)
2879     {
2880         e1 = e1.castTo(sc, towards);
2881         e2 = e2.castTo(sc, towards);
2882         return Lret(towards);
2883     }
2884 
2885     Type t1b = e1.type.toBasetype();
2886     Type t2b = e2.type.toBasetype();
2887 
2888     if (sc && sc.flags & SCOPE.Cfile)
2889     {
2890         // Integral types can be implicitly converted to pointers
2891         if ((t1b.ty == Tpointer) != (t2b.ty == Tpointer))
2892         {
2893             if (t1b.isintegral())
2894             {
2895                 return convert(e1, t2b);
2896             }
2897             else if (t2b.isintegral())
2898             {
2899                 return convert(e2, t1b);
2900             }
2901         }
2902     }
2903 
2904     if (op != EXP.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
2905     {
2906         if (op == EXP.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
2907         {
2908             e1 = e1.castTo(sc, Type.tdchar);
2909             e2 = e2.castTo(sc, Type.tdchar);
2910         }
2911         else
2912         {
2913             e1 = integralPromotions(e1, sc);
2914             e2 = integralPromotions(e2, sc);
2915         }
2916     }
2917 
2918     MATCH m;
2919     Type t1 = e1.type;
2920     Type t2 = e2.type;
2921     assert(t1);
2922     Type t = t1;
2923 
2924     /* The start type of alias this type recursion.
2925      * In following case, we should save A, and stop recursion
2926      * if it appears again.
2927      *      X -> Y -> [A] -> B -> A -> B -> ...
2928      */
2929     Type att1 = null;
2930     Type att2 = null;
2931 
2932     if (t1.mod != t2.mod &&
2933         t1.ty == Tenum && t2.ty == Tenum &&
2934         t1.isTypeEnum().sym == t2.isTypeEnum().sym)
2935     {
2936         ubyte mod = MODmerge(t1.mod, t2.mod);
2937         t1 = t1.castMod(mod);
2938         t2 = t2.castMod(mod);
2939     }
2940 
2941 Lagain:
2942     t1b = t1.toBasetype();
2943     t2b = t2.toBasetype();
2944 
2945     const ty = implicitConvCommonTy(t1b.ty, t2b.ty);
2946     if (ty != Terror)
2947     {
2948         const ty1 = implicitConvTy1(t1b.ty, t2b.ty);
2949         const ty2 = implicitConvTy1(t2b.ty, t1b.ty);
2950 
2951         if (t1b.ty == ty1) // if no promotions
2952         {
2953             if (t1.equals(t2))
2954                 return Lret(t1);
2955 
2956             if (t1b.equals(t2b))
2957                 return Lret(t1b);
2958         }
2959 
2960         t1 = Type.basic[ty1];
2961         t2 = Type.basic[ty2];
2962 
2963         if (!(t1 && t2))
2964             return null;
2965         e1 = e1.castTo(sc, t1);
2966         e2 = e2.castTo(sc, t2);
2967         return Lret(Type.basic[ty]);
2968     }
2969 
2970     t1 = t1b;
2971     t2 = t2b;
2972 
2973     if (t1.ty == Ttuple || t2.ty == Ttuple)
2974         return null;
2975 
2976     if (t1.equals(t2))
2977     {
2978         // merging can not result in new enum type
2979         if (t.ty == Tenum)
2980             return Lret(t1b);
2981         return Lret(t);
2982     }
2983 
2984     if ((t1.ty == Tpointer && t2.ty == Tpointer) || (t1.ty == Tdelegate && t2.ty == Tdelegate))
2985     {
2986         // Bring pointers to compatible type
2987         Type t1n = t1.nextOf();
2988         Type t2n = t2.nextOf();
2989 
2990         if (t1n.equals(t2n))
2991             return Lret(t);
2992 
2993         if (t1n.ty == Tvoid) // pointers to void are always compatible
2994             return Lret(t2);
2995 
2996         if (t2n.ty == Tvoid)
2997             return Lret(t);
2998 
2999         if (t1.implicitConvTo(t2))
3000             return convert(e1, t2);
3001 
3002         if (t2.implicitConvTo(t1))
3003             return convert(e2, t1);
3004 
3005         if (t1n.ty == Tfunction && t2n.ty == Tfunction)
3006         {
3007             TypeFunction tf1 = t1n.isTypeFunction();
3008             TypeFunction tf2 = t2n.isTypeFunction();
3009             tf1.purityLevel();
3010             tf2.purityLevel();
3011 
3012             TypeFunction d = tf1.syntaxCopy();
3013 
3014             if (tf1.purity != tf2.purity)
3015                 d.purity = PURE.impure;
3016             assert(d.purity != PURE.fwdref);
3017 
3018             d.isnothrow = (tf1.isnothrow && tf2.isnothrow);
3019             d.isnogc = (tf1.isnogc && tf2.isnogc);
3020 
3021             if (tf1.trust == tf2.trust)
3022                 d.trust = tf1.trust;
3023             else if (tf1.trust <= TRUST.system || tf2.trust <= TRUST.system)
3024                 d.trust = TRUST.system;
3025             else
3026                 d.trust = TRUST.trusted;
3027 
3028             Type tx = (t1.ty == Tdelegate) ? new TypeDelegate(d) : d.pointerTo();
3029             tx = tx.typeSemantic(e1.loc, sc);
3030 
3031             if (t1.implicitConvTo(tx) && t2.implicitConvTo(tx))
3032                 return coerce(tx);
3033             return null;
3034         }
3035 
3036         if (t1n.mod != t2n.mod)
3037         {
3038             if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
3039                 return null;
3040             ubyte mod = MODmerge(t1n.mod, t2n.mod);
3041             t1 = t1n.castMod(mod).pointerTo();
3042             t2 = t2n.castMod(mod).pointerTo();
3043             t = t1;
3044             goto Lagain;
3045         }
3046 
3047         if (t1n.ty == Tclass && t2n.ty == Tclass)
3048         {
3049             ClassDeclaration cd1 = t1n.isClassHandle();
3050             ClassDeclaration cd2 = t2n.isClassHandle();
3051             int offset;
3052             if (cd1.isBaseOf(cd2, &offset))
3053             {
3054                 if (offset)
3055                     e2 = e2.castTo(sc, t);
3056                 return Lret(t);
3057             }
3058 
3059             if (cd2.isBaseOf(cd1, &offset))
3060             {
3061                 if (offset)
3062                     e1 = e1.castTo(sc, t2);
3063                 return Lret(t2);
3064             }
3065 
3066             return null;
3067         }
3068 
3069         t1 = t1n.constOf().pointerTo();
3070         t2 = t2n.constOf().pointerTo();
3071         if (t1.implicitConvTo(t2))
3072             return convert(e1, t2);
3073         if (t2.implicitConvTo(t1))
3074             return convert(e2, t1);
3075         return null;
3076     }
3077 
3078     if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
3079     {
3080         /*  (T[n] op void*)   => T[]
3081          *  (T[]  op void*)   => T[]
3082          *  (T[n] op void[0]) => T[]
3083          *  (T[]  op void[0]) => T[]
3084          *  (T[n] op void[])  => T[]
3085          *  (T[]  op void[])  => T[]
3086          */
3087         return coerce(t1.nextOf().arrayOf());
3088     }
3089 
3090     if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
3091     {
3092         /*  (void*   op T[n]) => T[]
3093          *  (void*   op T[])  => T[]
3094          *  (void[0] op T[n]) => T[]
3095          *  (void[0] op T[])  => T[]
3096          *  (void[]  op T[n]) => T[]
3097          *  (void[]  op T[])  => T[]
3098          */
3099         return coerce(t2.nextOf().arrayOf());
3100     }
3101 
3102     if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch)
3103     {
3104         // https://issues.dlang.org/show_bug.cgi?id=7285
3105         // Tsarray op [x, y, ...] should to be Tsarray
3106         // https://issues.dlang.org/show_bug.cgi?id=14737
3107         // Tsarray ~ [x, y, ...] should to be Tarray
3108         if (t1.ty == Tsarray && e2.op == EXP.arrayLiteral && op != EXP.concatenate)
3109             return convert(e2, t1);
3110         if (m == MATCH.constant && (op == EXP.addAssign || op == EXP.minAssign || op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || op == EXP.powAssign || op == EXP.andAssign || op == EXP.orAssign || op == EXP.xorAssign))
3111         {
3112             // Don't make the lvalue const
3113             return Lret(t2);
3114         }
3115         return convert(e1, t2);
3116     }
3117 
3118     if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1))
3119     {
3120         // https://issues.dlang.org/show_bug.cgi?id=7285
3121         // https://issues.dlang.org/show_bug.cgi?id=14737
3122         if (t2.ty == Tsarray && e1.op == EXP.arrayLiteral && op != EXP.concatenate)
3123             return convert(e1, t2);
3124         return convert(e2, t1);
3125     }
3126 
3127     if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod)
3128     {
3129         /* If one is mutable and the other immutable, then retry
3130          * with both of them as const
3131          */
3132         Type t1n = t1.nextOf();
3133         Type t2n = t2.nextOf();
3134         ubyte mod;
3135         if (e1.op == EXP.null_ && e2.op != EXP.null_)
3136             mod = t2n.mod;
3137         else if (e1.op != EXP.null_ && e2.op == EXP.null_)
3138             mod = t1n.mod;
3139         else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
3140             return null;
3141         else
3142             mod = MODmerge(t1n.mod, t2n.mod);
3143 
3144         if (t1.ty == Tpointer)
3145             t1 = t1n.castMod(mod).pointerTo();
3146         else
3147             t1 = t1n.castMod(mod).arrayOf();
3148 
3149         if (t2.ty == Tpointer)
3150             t2 = t2n.castMod(mod).pointerTo();
3151         else
3152             t2 = t2n.castMod(mod).arrayOf();
3153         t = t1;
3154         goto Lagain;
3155     }
3156 
3157     if (t1.ty == Tclass && t2.ty == Tclass)
3158     {
3159         if (t1.mod != t2.mod)
3160         {
3161             ubyte mod;
3162             if (e1.op == EXP.null_ && e2.op != EXP.null_)
3163                 mod = t2.mod;
3164             else if (e1.op != EXP.null_ && e2.op == EXP.null_)
3165                 mod = t1.mod;
3166             else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
3167                 return null;
3168             else
3169                 mod = MODmerge(t1.mod, t2.mod);
3170             t1 = t1.castMod(mod);
3171             t2 = t2.castMod(mod);
3172             t = t1;
3173             goto Lagain;
3174         }
3175         goto Lcc;
3176     }
3177 
3178     if (t1.ty == Tclass || t2.ty == Tclass)
3179     {
3180     Lcc:
3181         while (1)
3182         {
3183             MATCH i1woat = MATCH.exact;
3184             MATCH i2woat = MATCH.exact;
3185 
3186             if (auto t2c = t2.isTypeClass())
3187                 i1woat = t2c.implicitConvToWithoutAliasThis(t1);
3188             if (auto t1c = t1.isTypeClass())
3189                 i2woat = t1c.implicitConvToWithoutAliasThis(t2);
3190 
3191             MATCH i1 = e2.implicitConvTo(t1);
3192             MATCH i2 = e1.implicitConvTo(t2);
3193 
3194             if (i1 && i2)
3195             {
3196                 // We have the case of class vs. void*, so pick class
3197                 if (t1.ty == Tpointer)
3198                     i1 = MATCH.nomatch;
3199                 else if (t2.ty == Tpointer)
3200                     i2 = MATCH.nomatch;
3201             }
3202 
3203             // Match but without 'alias this' on classes
3204             if (i2 && i2woat)
3205                 return coerce(t2);
3206             if (i1 && i1woat)
3207                 return coerce(t1);
3208 
3209             // Here use implicitCastTo() instead of castTo() to try 'alias this' on classes
3210             Type coerceImplicit(Type towards)
3211             {
3212                 e1 = e1.implicitCastTo(sc, towards);
3213                 e2 = e2.implicitCastTo(sc, towards);
3214                 return Lret(towards);
3215             }
3216 
3217             // Implicit conversion with 'alias this'
3218             if (i2)
3219                 return coerceImplicit(t2);
3220             if (i1)
3221                 return coerceImplicit(t1);
3222 
3223             if (t1.ty == Tclass && t2.ty == Tclass)
3224             {
3225                 TypeClass tc1 = t1.isTypeClass();
3226                 TypeClass tc2 = t2.isTypeClass();
3227 
3228                 /* Pick 'tightest' type
3229                  */
3230                 ClassDeclaration cd1 = tc1.sym.baseClass;
3231                 ClassDeclaration cd2 = tc2.sym.baseClass;
3232                 if (cd1 && cd2)
3233                 {
3234                     t1 = cd1.type.castMod(t1.mod);
3235                     t2 = cd2.type.castMod(t2.mod);
3236                 }
3237                 else if (cd1)
3238                     t1 = cd1.type;
3239                 else if (cd2)
3240                     t2 = cd2.type;
3241                 else
3242                     return null;
3243             }
3244             else if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
3245             {
3246                 if (isRecursiveAliasThis(att1, e1.type))
3247                     return null;
3248                 //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars());
3249                 e1 = resolveAliasThis(sc, e1);
3250                 t1 = e1.type;
3251                 continue;
3252             }
3253             else if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
3254             {
3255                 if (isRecursiveAliasThis(att2, e2.type))
3256                     return null;
3257                 //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars());
3258                 e2 = resolveAliasThis(sc, e2);
3259                 t2 = e2.type;
3260                 continue;
3261             }
3262             else
3263                 return null;
3264         }
3265     }
3266 
3267     if (t1.ty == Tstruct && t2.ty == Tstruct)
3268     {
3269         if (t1.mod != t2.mod)
3270         {
3271             if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
3272                 return null;
3273             ubyte mod = MODmerge(t1.mod, t2.mod);
3274             t1 = t1.castMod(mod);
3275             t2 = t2.castMod(mod);
3276             t = t1;
3277             goto Lagain;
3278         }
3279 
3280         TypeStruct ts1 = t1.isTypeStruct();
3281         TypeStruct ts2 = t2.isTypeStruct();
3282         if (ts1.sym != ts2.sym)
3283         {
3284             if (!ts1.sym.aliasthis && !ts2.sym.aliasthis)
3285                 return null;
3286 
3287             MATCH i1 = MATCH.nomatch;
3288             MATCH i2 = MATCH.nomatch;
3289 
3290             Expression e1b = null;
3291             Expression e2b = null;
3292             if (ts2.sym.aliasthis)
3293             {
3294                 if (isRecursiveAliasThis(att2, e2.type))
3295                     return null;
3296                 //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars());
3297                 e2b = resolveAliasThis(sc, e2);
3298                 i1 = e2b.implicitConvTo(t1);
3299             }
3300             if (ts1.sym.aliasthis)
3301             {
3302                 if (isRecursiveAliasThis(att1, e1.type))
3303                     return null;
3304                 //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars());
3305                 e1b = resolveAliasThis(sc, e1);
3306                 i2 = e1b.implicitConvTo(t2);
3307             }
3308             if (i1 && i2)
3309                 return null;
3310 
3311             if (i1)
3312                 return convert(e2, t1);
3313             if (i2)
3314                 return convert(e1, t2);
3315 
3316             if (e1b)
3317             {
3318                 e1 = e1b;
3319                 t1 = e1b.type.toBasetype();
3320             }
3321             if (e2b)
3322             {
3323                 e2 = e2b;
3324                 t2 = e2b.type.toBasetype();
3325             }
3326             t = t1;
3327             goto Lagain;
3328         }
3329     }
3330 
3331     if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
3332     {
3333         if (isRecursiveAliasThis(att1, e1.type))
3334             return null;
3335         //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
3336         e1 = resolveAliasThis(sc, e1);
3337         t1 = e1.type;
3338         t = t1;
3339         goto Lagain;
3340     }
3341 
3342     if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
3343     {
3344         if (isRecursiveAliasThis(att2, e2.type))
3345             return null;
3346         //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
3347         e2 = resolveAliasThis(sc, e2);
3348         t2 = e2.type;
3349         t = t2;
3350         goto Lagain;
3351     }
3352 
3353     if ((e1.op == EXP.string_ || e1.op == EXP.null_) && e1.implicitConvTo(t2))
3354         return convert(e1, t2);
3355     if ((e2.op == EXP.string_ || e2.op == EXP.null_) && e2.implicitConvTo(t1))
3356         return convert(e2, t1);
3357     if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf()))
3358         return coerce(t1.nextOf().arrayOf());
3359     if (t1.ty == Tsarray && t2.ty == Tsarray && e1.implicitConvTo(t2.nextOf().arrayOf()))
3360         return coerce(t2.nextOf().arrayOf());
3361 
3362     if (t1.ty == Tvector && t2.ty == Tvector)
3363     {
3364         // https://issues.dlang.org/show_bug.cgi?id=13841
3365         // all vector types should have no common types between
3366         // different vectors, even though their sizes are same.
3367         auto tv1 = t1.isTypeVector();
3368         auto tv2 = t2.isTypeVector();
3369         if (!tv1.basetype.equals(tv2.basetype))
3370             return null;
3371 
3372         goto LmodCompare;
3373     }
3374 
3375     if (t1.ty == Tvector && t2.ty != Tvector && e2.implicitConvTo(t1))
3376     {
3377         e2 = e2.castTo(sc, t1);
3378         t2 = t1;
3379         t = t1;
3380         goto Lagain;
3381     }
3382 
3383     if (t2.ty == Tvector && t1.ty != Tvector && e1.implicitConvTo(t2))
3384     {
3385         e1 = e1.castTo(sc, t2);
3386         t1 = t2;
3387         t = t1;
3388         goto Lagain;
3389     }
3390 
3391     if (t1.isintegral() && t2.isintegral())
3392     {
3393         if (t1.ty != t2.ty)
3394         {
3395             if (t1.ty == Tvector || t2.ty == Tvector)
3396                 return null;
3397             e1 = integralPromotions(e1, sc);
3398             e2 = integralPromotions(e2, sc);
3399             t1 = e1.type;
3400             t2 = e2.type;
3401             goto Lagain;
3402         }
3403         assert(t1.ty == t2.ty);
3404 LmodCompare:
3405         if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
3406             return null;
3407         ubyte mod = MODmerge(t1.mod, t2.mod);
3408 
3409         t1 = t1.castMod(mod);
3410         t2 = t2.castMod(mod);
3411         t = t1;
3412         e1 = e1.castTo(sc, t);
3413         e2 = e2.castTo(sc, t);
3414         goto Lagain;
3415     }
3416 
3417     if (t1.ty == Tnull && t2.ty == Tnull)
3418     {
3419         ubyte mod = MODmerge(t1.mod, t2.mod);
3420         return coerce(t1.castMod(mod));
3421     }
3422 
3423     if (t2.ty == Tnull && (t1.ty == Tpointer || t1.ty == Taarray || t1.ty == Tarray))
3424         return convert(e2, t1);
3425     if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray))
3426         return convert(e1, t2);
3427 
3428     /// Covers array operations for user-defined types
3429     Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope *sc)
3430     {
3431         // scalar op scalar - we shouldn't be here
3432         if (e1.type.ty != Tarray && e1.type.ty != Tsarray && e2.type.ty != Tarray && e2.type.ty != Tsarray)
3433             return null;
3434 
3435         // only supporting slices and array literals
3436         if (!e1.isSliceExp() && !e1.isArrayLiteralExp() && !e2.isSliceExp() && !e2.isArrayLiteralExp())
3437             return null;
3438 
3439         // start with e1 op e2 and if either one of e1 or e2 is a slice or array literal,
3440         // replace it with the first element of the array
3441         Expression lhs = e1;
3442         Expression rhs = e2;
3443 
3444         // T[x .. y] op ?
3445         if (auto se1 = e1.isSliceExp())
3446             lhs = new IndexExp(Loc.initial, se1.e1, IntegerExp.literal!0);
3447 
3448         // [t1, t2, .. t3] op ?
3449         if (auto ale1 = e1.isArrayLiteralExp())
3450             lhs = ale1.opIndex(0);
3451 
3452         // ? op U[z .. t]
3453         if (auto se2 = e2.isSliceExp())
3454             rhs = new IndexExp(Loc.initial, se2.e1, IntegerExp.literal!0);
3455 
3456         // ? op [u1, u2, .. u3]
3457         if (auto ale2 = e2.isArrayLiteralExp())
3458             rhs = ale2.opIndex(0);
3459 
3460         // create a new binary expression with the new lhs and rhs (at this stage, at least
3461         // one of lhs/rhs has been replaced with the 0'th element of the array it was before)
3462         Expression exp;
3463         switch (op)
3464         {
3465             case EXP.add:
3466                 exp = new AddExp(Loc.initial, lhs, rhs); break;
3467             case EXP.min:
3468                 exp = new MinExp(Loc.initial, lhs, rhs); break;
3469             case EXP.mul:
3470                 exp = new MulExp(Loc.initial, lhs, rhs); break;
3471             case EXP.div:
3472                 exp = new DivExp(Loc.initial, lhs, rhs); break;
3473             case EXP.pow:
3474                 exp = new PowExp(Loc.initial, lhs, rhs); break;
3475             default:
3476                 exp = null;
3477         }
3478 
3479         if (exp)
3480         {
3481             // if T op U is valid and has type V
3482             // then T[] op U and T op U[] should be valid and have type V[]
3483             Expression e = exp.trySemantic(sc);
3484             if (e && e.type)
3485                 return e.type.arrayOf;
3486         }
3487 
3488         return null;
3489     }
3490 
3491     if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
3492     {
3493         if (e2.implicitConvTo(t1.nextOf()))
3494         {
3495             // T[] op T
3496             // T[] op cast(T)U
3497             e2 = e2.castTo(sc, t1.nextOf());
3498             return Lret(t1.nextOf().arrayOf());
3499         }
3500         if (t1.nextOf().implicitConvTo(e2.type))
3501         {
3502             // (cast(T)U)[] op T    (https://issues.dlang.org/show_bug.cgi?id=12780)
3503             // e1 is left as U[], it will be handled in arrayOp() later.
3504             return Lret(e2.type.arrayOf());
3505         }
3506         if (t2.ty == Tarray && isArrayOpOperand(e2))
3507         {
3508             if (t1.nextOf().implicitConvTo(t2.nextOf()))
3509             {
3510                 // (cast(T)U)[] op T[]  (https://issues.dlang.org/show_bug.cgi?id=12780)
3511                 t = t2.nextOf().arrayOf();
3512                 // if cast won't be handled in arrayOp() later
3513                 if (!isArrayOpImplicitCast(t1.isTypeDArray(), t2.isTypeDArray()))
3514                     e1 = e1.castTo(sc, t);
3515                 return Lret(t);
3516             }
3517             if (t2.nextOf().implicitConvTo(t1.nextOf()))
3518             {
3519                 // T[] op (cast(T)U)[]  (https://issues.dlang.org/show_bug.cgi?id=12780)
3520                 // e2 is left as U[], it will be handled in arrayOp() later.
3521                 t = t1.nextOf().arrayOf();
3522                 // if cast won't be handled in arrayOp() later
3523                 if (!isArrayOpImplicitCast(t2.isTypeDArray(), t1.isTypeDArray()))
3524                     e2 = e2.castTo(sc, t);
3525                 return Lret(t);
3526             }
3527         }
3528 
3529         t = checkArrayOpType(e1, e2, op, sc);
3530         if (t !is null)
3531             return Lret(t);
3532 
3533         return null;
3534     }
3535     else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
3536     {
3537         if (e1.implicitConvTo(t2.nextOf()))
3538         {
3539             // T op T[]
3540             // cast(T)U op T[]
3541             e1 = e1.castTo(sc, t2.nextOf());
3542             t = t2.nextOf().arrayOf();
3543         }
3544         else if (t2.nextOf().implicitConvTo(e1.type))
3545         {
3546             // T op (cast(T)U)[]    (https://issues.dlang.org/show_bug.cgi?id=12780)
3547             // e2 is left as U[], it will be handled in arrayOp() later.
3548             t = e1.type.arrayOf();
3549         }
3550         else
3551         {
3552             t = checkArrayOpType(e1, e2, op, sc);
3553             if (t is null)
3554                 return null;
3555         }
3556 
3557         //printf("test %s\n", EXPtoString(op).ptr);
3558         e1 = e1.optimize(WANTvalue);
3559         if (isCommutative(op) && e1.isConst())
3560         {
3561             /* Swap operands to minimize number of functions generated
3562              */
3563             //printf("swap %s\n", EXPtoString(op).ptr);
3564             Expression tmp = e1;
3565             e1 = e2;
3566             e2 = tmp;
3567         }
3568         return Lret(t);
3569     }
3570 
3571     return null;
3572 }
3573 
3574 /************************************
3575  * Bring leaves to common type.
3576  * Returns:
3577  *    null on success, ErrorExp if error occurs
3578  */
typeCombine(BinExp be,Scope * sc)3579 Expression typeCombine(BinExp be, Scope* sc)
3580 {
3581     Expression errorReturn()
3582     {
3583         Expression ex = be.incompatibleTypes();
3584         if (ex.op == EXP.error)
3585             return ex;
3586         return ErrorExp.get();
3587     }
3588 
3589     Type t1 = be.e1.type.toBasetype();
3590     Type t2 = be.e2.type.toBasetype();
3591 
3592     if (be.op == EXP.min || be.op == EXP.add)
3593     {
3594         // struct+struct, and class+class are errors
3595         if (t1.ty == Tstruct && t2.ty == Tstruct)
3596             return errorReturn();
3597         else if (t1.ty == Tclass && t2.ty == Tclass)
3598             return errorReturn();
3599         else if (t1.ty == Taarray && t2.ty == Taarray)
3600             return errorReturn();
3601     }
3602 
3603     if (auto result = typeMerge(sc, be.op, be.e1, be.e2))
3604     {
3605         if (be.type is null)
3606             be.type = result;
3607     }
3608     else
3609         return errorReturn();
3610 
3611     // If the types have no value, return an error
3612     if (be.e1.op == EXP.error)
3613         return be.e1;
3614     if (be.e2.op == EXP.error)
3615         return be.e2;
3616     return null;
3617 }
3618 
3619 /***********************************
3620  * Do integral promotions (convertchk).
3621  * Don't convert <array of> to <pointer to>
3622  */
integralPromotions(Expression e,Scope * sc)3623 Expression integralPromotions(Expression e, Scope* sc)
3624 {
3625     //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars());
3626     switch (e.type.toBasetype().ty)
3627     {
3628     case Tvoid:
3629         e.error("void has no value");
3630         return ErrorExp.get();
3631 
3632     case Tint8:
3633     case Tuns8:
3634     case Tint16:
3635     case Tuns16:
3636     case Tbool:
3637     case Tchar:
3638     case Twchar:
3639         e = e.castTo(sc, Type.tint32);
3640         break;
3641 
3642     case Tdchar:
3643         e = e.castTo(sc, Type.tuns32);
3644         break;
3645 
3646     default:
3647         break;
3648     }
3649     return e;
3650 }
3651 
3652 /******************************************************
3653  * This provides a transition from the non-promoting behavior
3654  * of unary + - ~ to the C-like integral promotion behavior.
3655  * Params:
3656  *    sc = context
3657  *    ue = NegExp, UAddExp, or ComExp which is revised per rules
3658  * References:
3659  *      https://issues.dlang.org/show_bug.cgi?id=16997
3660  */
3661 
fix16997(Scope * sc,UnaExp ue)3662 void fix16997(Scope* sc, UnaExp ue)
3663 {
3664     if (global.params.fix16997 || sc.flags & SCOPE.Cfile)
3665         ue.e1 = integralPromotions(ue.e1, sc);          // desired C-like behavor
3666     else
3667     {
3668         switch (ue.e1.type.toBasetype.ty)
3669         {
3670             case Tint8:
3671             case Tuns8:
3672             case Tint16:
3673             case Tuns16:
3674             //case Tbool:       // these operations aren't allowed on bool anyway
3675             case Tchar:
3676             case Twchar:
3677             case Tdchar:
3678                 ue.deprecation("integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`",
3679                     ue.toChars(), EXPtoString(ue.op).ptr, ue.e1.toChars());
3680                 break;
3681 
3682             default:
3683                 break;
3684         }
3685     }
3686 }
3687 
3688 /***********************************
3689  * See if both types are arrays that can be compared
3690  * for equality without any casting. Return true if so.
3691  * This is to enable comparing things like an immutable
3692  * array with a mutable one.
3693  */
arrayTypeCompatibleWithoutCasting(Type t1,Type t2)3694 extern (C++) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2)
3695 {
3696     t1 = t1.toBasetype();
3697     t2 = t2.toBasetype();
3698 
3699     if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && t2.ty == t1.ty)
3700     {
3701         if (t1.nextOf().implicitConvTo(t2.nextOf()) >= MATCH.constant || t2.nextOf().implicitConvTo(t1.nextOf()) >= MATCH.constant)
3702             return true;
3703     }
3704     return false;
3705 }
3706 
3707 /******************************************************************/
3708 /* Determine the integral ranges of an expression.
3709  * This is used to determine if implicit narrowing conversions will
3710  * be allowed.
3711  */
3712 @trusted
getIntRange(Expression e)3713 IntRange getIntRange(Expression e)
3714 {
3715     IntRange visit(Expression e)
3716     {
3717         return IntRange.fromType(e.type);
3718     }
3719 
3720     IntRange visitInteger(IntegerExp e)
3721     {
3722         return IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type);
3723     }
3724 
3725     IntRange visitCast(CastExp e)
3726     {
3727         return getIntRange(e.e1)._cast(e.type);
3728     }
3729 
3730     IntRange visitAdd(AddExp e)
3731     {
3732         IntRange ir1 = getIntRange(e.e1);
3733         IntRange ir2 = getIntRange(e.e2);
3734         return (ir1 + ir2)._cast(e.type);
3735     }
3736 
3737     IntRange visitMin(MinExp e)
3738     {
3739         IntRange ir1 = getIntRange(e.e1);
3740         IntRange ir2 = getIntRange(e.e2);
3741         return (ir1 - ir2)._cast(e.type);
3742     }
3743 
3744     IntRange visitDiv(DivExp e)
3745     {
3746         IntRange ir1 = getIntRange(e.e1);
3747         IntRange ir2 = getIntRange(e.e2);
3748 
3749         return (ir1 / ir2)._cast(e.type);
3750     }
3751 
3752     IntRange visitMul(MulExp e)
3753     {
3754         IntRange ir1 = getIntRange(e.e1);
3755         IntRange ir2 = getIntRange(e.e2);
3756 
3757         return (ir1 * ir2)._cast(e.type);
3758     }
3759 
3760     IntRange visitMod(ModExp e)
3761     {
3762         IntRange ir1 = getIntRange(e.e1);
3763         IntRange ir2 = getIntRange(e.e2);
3764 
3765         // Modding on 0 is invalid anyway.
3766         if (!ir2.absNeg().imin.negative)
3767         {
3768             return visit(e);
3769         }
3770         return (ir1 % ir2)._cast(e.type);
3771     }
3772 
3773     IntRange visitAnd(AndExp e)
3774     {
3775         IntRange result;
3776         bool hasResult = false;
3777         result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult);
3778 
3779         assert(hasResult);
3780         return result._cast(e.type);
3781     }
3782 
3783     IntRange visitOr(OrExp e)
3784     {
3785         IntRange result;
3786         bool hasResult = false;
3787         result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult);
3788 
3789         assert(hasResult);
3790         return result._cast(e.type);
3791     }
3792 
3793     IntRange visitXor(XorExp e)
3794     {
3795         IntRange result;
3796         bool hasResult = false;
3797         result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult);
3798 
3799         assert(hasResult);
3800         return result._cast(e.type);
3801     }
3802 
3803     IntRange visitShl(ShlExp e)
3804     {
3805         IntRange ir1 = getIntRange(e.e1);
3806         IntRange ir2 = getIntRange(e.e2);
3807 
3808         return (ir1 << ir2)._cast(e.type);
3809     }
3810 
3811     IntRange visitShr(ShrExp e)
3812     {
3813         IntRange ir1 = getIntRange(e.e1);
3814         IntRange ir2 = getIntRange(e.e2);
3815 
3816         return (ir1 >> ir2)._cast(e.type);
3817     }
3818 
3819     IntRange visitUshr(UshrExp e)
3820     {
3821         IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type);
3822         IntRange ir2 = getIntRange(e.e2);
3823 
3824         return (ir1 >>> ir2)._cast(e.type);
3825     }
3826 
3827     IntRange visitAssign(AssignExp e)
3828     {
3829         return getIntRange(e.e2)._cast(e.type);
3830     }
3831 
3832     IntRange visitCond(CondExp e)
3833     {
3834         // No need to check e.econd; assume caller has called optimize()
3835         IntRange ir1 = getIntRange(e.e1);
3836         IntRange ir2 = getIntRange(e.e2);
3837         return ir1.unionWith(ir2)._cast(e.type);
3838     }
3839 
3840     IntRange visitVar(VarExp e)
3841     {
3842         Expression ie;
3843         VarDeclaration vd = e.var.isVarDeclaration();
3844         if (vd && vd.range)
3845             return vd.range._cast(e.type);
3846         else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null)
3847             return getIntRange(ie);
3848         else
3849             return visit(e);
3850     }
3851 
3852     IntRange visitComma(CommaExp e)
3853     {
3854         return getIntRange(e.e2);
3855     }
3856 
3857     IntRange visitCom(ComExp e)
3858     {
3859         IntRange ir = getIntRange(e.e1);
3860         return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type);
3861     }
3862 
3863     IntRange visitNeg(NegExp e)
3864     {
3865         IntRange ir = getIntRange(e.e1);
3866         return (-ir)._cast(e.type);
3867     }
3868 
3869     switch (e.op)
3870     {
3871         default                     : return visit(e);
3872         case EXP.int64              : return visitInteger(e.isIntegerExp());
3873         case EXP.cast_              : return visitCast(e.isCastExp());
3874         case EXP.add                : return visitAdd(e.isAddExp());
3875         case EXP.min                : return visitMin(e.isMinExp());
3876         case EXP.div                : return visitDiv(e.isDivExp());
3877         case EXP.mul                : return visitMul(e.isMulExp());
3878         case EXP.mod                : return visitMod(e.isModExp());
3879         case EXP.and                : return visitAnd(e.isAndExp());
3880         case EXP.or                 : return visitOr(e.isOrExp());
3881         case EXP.xor                : return visitXor(e.isXorExp());
3882         case EXP.leftShift          : return visitShl(e.isShlExp());
3883         case EXP.rightShift         : return visitShr(e.isShrExp());
3884         case EXP.unsignedRightShift : return visitUshr(e.isUshrExp());
3885         case EXP.blit               : return visitAssign(e.isBlitExp());
3886         case EXP.construct          : return visitAssign(e.isConstructExp());
3887         case EXP.assign             : return visitAssign(e.isAssignExp());
3888         case EXP.question           : return visitCond(e.isCondExp());
3889         case EXP.variable           : return visitVar(e.isVarExp());
3890         case EXP.comma              : return visitComma(e.isCommaExp());
3891         case EXP.tilde              : return visitCom(e.isComExp());
3892         case EXP.negate             : return visitNeg(e.isNegExp());
3893     }
3894 }
3895