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