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