2 * Perform constant folding of arithmetic expressions.
4 * The routines in this module are called from `optimize.d`.
6 * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
8 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
10 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d)
12 * Documentation: https://dlang.org/phobos/dmd_constfold.html
13 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/constfold.d
18 import core
.stdc
.string
;
19 import core
.stdc
.stdio
;
20 import dmd
.arraytypes
;
24 import dmd
.declaration
;
27 import dmd
.expression
;
31 import dmd
.root
.complex
;
32 import dmd
.root
.ctfloat
;
36 import dmd
.sideeffect
;
39 import dmd
.typesem
: toDsymbol
, equivalent
, sarrayOf
;
41 private enum LOG
= false;
43 private Expression
expType(Type type
, Expression e
)
53 /**********************************
54 * Initialize a EXP.cantExpression Expression.
56 * ue = where to write it
58 void cantExp(out UnionExp ue
)
60 emplaceExp
!(CTFEExp
)(&ue
, EXP
.cantExpression
);
63 /* =============================== constFold() ============================== */
64 /* The constFold() functions were redundant with the optimize() ones,
65 * and so have been folded in with them.
67 /* ========================================================================== */
68 UnionExp
Neg(Type type
, Expression e1
)
74 emplaceExp
!(RealExp
)(&ue
, loc
, -e1
.toReal(), type
);
76 else if (e1
.type
.isimaginary())
78 emplaceExp
!(RealExp
)(&ue
, loc
, -e1
.toImaginary(), type
);
80 else if (e1
.type
.iscomplex())
82 emplaceExp
!(ComplexExp
)(&ue
, loc
, -e1
.toComplex(), type
);
86 emplaceExp
!(IntegerExp
)(&ue
, loc
, -e1
.toInteger(), type
);
91 UnionExp
Com(Type type
, Expression e1
)
95 emplaceExp
!(IntegerExp
)(&ue
, loc
, ~e1
.toInteger(), type
);
99 UnionExp
Not(Type type
, Expression e1
)
103 // BUG: Should be replaced with e1.toBool().get(), but this is apparently
104 // executed for some expressions that cannot be const-folded
105 // To be fixed in another PR
106 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toBool().hasValue(false) ?
1 : 0, type
);
110 UnionExp
Add(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
115 printf("Add(e1 = %s, e2 = %s)\n", e1
.toChars(), e2
.toChars());
119 emplaceExp
!(RealExp
)(&ue
, loc
, e1
.toReal() + e2
.toReal(), type
);
121 else if (type
.isimaginary())
123 emplaceExp
!(RealExp
)(&ue
, loc
, e1
.toImaginary() + e2
.toImaginary(), type
);
125 else if (type
.iscomplex())
127 // This rigamarole is necessary so that -0.0 doesn't get
128 // converted to +0.0 by doing an extraneous add with +0.0
129 auto c1
= complex_t(CTFloat
.zero
);
130 real_t r1
= CTFloat
.zero
;
131 real_t i1
= CTFloat
.zero
;
132 auto c2
= complex_t(CTFloat
.zero
);
133 real_t r2
= CTFloat
.zero
;
134 real_t i2
= CTFloat
.zero
;
135 auto v
= complex_t(CTFloat
.zero
);
137 if (e1
.type
.isreal())
142 else if (e1
.type
.isimaginary())
144 i1
= e1
.toImaginary();
152 if (e2
.type
.isreal())
156 else if (e2
.type
.isimaginary())
158 i2
= e2
.toImaginary();
169 v
= complex_t(r1
+ r2
);
172 v
= complex_t(r1
, i2
);
175 v
= complex_t(r1
+ creall(c2
), cimagl(c2
));
178 v
= complex_t(r2
, i1
);
181 v
= complex_t(CTFloat
.zero
, i1
+ i2
);
184 v
= complex_t(creall(c2
), i1
+ cimagl(c2
));
187 v
= complex_t(creall(c1
) + r2
, cimagl(c2
));
190 v
= complex_t(creall(c1
), cimagl(c1
) + i2
);
198 emplaceExp
!(ComplexExp
)(&ue
, loc
, v
, type
);
200 else if (SymOffExp soe
= e1
.isSymOffExp())
202 emplaceExp
!(SymOffExp
)(&ue
, loc
, soe
.var
, soe
.offset
+ e2
.toInteger());
203 ue
.exp().type
= type
;
205 else if (SymOffExp soe
= e2
.isSymOffExp())
207 emplaceExp
!(SymOffExp
)(&ue
, loc
, soe
.var
, soe
.offset
+ e1
.toInteger());
208 ue
.exp().type
= type
;
211 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() + e2
.toInteger(), type
);
215 UnionExp
Min(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
217 // Compute e1-e2 as e1+(-e2)
218 UnionExp
neg = Neg(e2
.type
, e2
);
219 UnionExp ue
= Add(loc
, type
, e1
, neg.exp());
223 UnionExp
Mul(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
226 if (type
.isfloating())
228 auto c
= complex_t(CTFloat
.zero
);
229 real_t r
= CTFloat
.zero
;
230 if (e1
.type
.isreal())
234 c
= complex_t(r
* creall(c
), r
* cimagl(c
));
236 else if (e1
.type
.isimaginary())
238 r
= e1
.toImaginary();
240 c
= complex_t(-r
* cimagl(c
), r
* creall(c
));
242 else if (e2
.type
.isreal())
246 c
= complex_t(r
* creall(c
), r
* cimagl(c
));
248 else if (e2
.type
.isimaginary())
250 r
= e2
.toImaginary();
252 c
= complex_t(-r
* cimagl(c
), r
* creall(c
));
255 c
= e1
.toComplex() * e2
.toComplex();
257 emplaceExp
!(RealExp
)(&ue
, loc
, creall(c
), type
);
258 else if (type
.isimaginary())
259 emplaceExp
!(RealExp
)(&ue
, loc
, cimagl(c
), type
);
260 else if (type
.iscomplex())
261 emplaceExp
!(ComplexExp
)(&ue
, loc
, c
, type
);
267 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() * e2
.toInteger(), type
);
272 UnionExp
Div(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
275 if (type
.isfloating())
277 auto c
= complex_t(CTFloat
.zero
);
278 if (e2
.type
.isreal())
280 if (e1
.type
.isreal())
282 emplaceExp
!(RealExp
)(&ue
, loc
, e1
.toReal() / e2
.toReal(), type
);
285 const r
= e2
.toReal();
287 c
= complex_t(creall(c
) / r
, cimagl(c
) / r
);
289 else if (e2
.type
.isimaginary())
291 const r
= e2
.toImaginary();
293 c
= complex_t(cimagl(c
) / r
, -creall(c
) / r
);
297 c
= e1
.toComplex() / e2
.toComplex();
301 emplaceExp
!(RealExp
)(&ue
, loc
, creall(c
), type
);
302 else if (type
.isimaginary())
303 emplaceExp
!(RealExp
)(&ue
, loc
, cimagl(c
), type
);
304 else if (type
.iscomplex())
305 emplaceExp
!(ComplexExp
)(&ue
, loc
, c
, type
);
318 error(e2
.loc
, "divide by 0");
319 emplaceExp
!(ErrorExp
)(&ue
);
322 if (n2
== -1 && !type
.isunsigned())
324 // Check for int.min / -1
325 if (n1
== 0xFFFFFFFF80000000UL
&& type
.toBasetype().ty
!= Tint64
)
327 error(e2
.loc
, "integer overflow: `int.min / -1`");
328 emplaceExp
!(ErrorExp
)(&ue
);
331 else if (n1
== 0x8000000000000000L
) // long.min / -1
333 error(e2
.loc
, "integer overflow: `long.min / -1L`");
334 emplaceExp
!(ErrorExp
)(&ue
);
338 if (e1
.type
.isunsigned() || e2
.type
.isunsigned())
339 n
= (cast(dinteger_t
)n1
) / (cast(dinteger_t
)n2
);
342 emplaceExp
!(IntegerExp
)(&ue
, loc
, n
, type
);
347 UnionExp
Mod(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
350 if (type
.isfloating())
352 auto c
= complex_t(CTFloat
.zero
);
353 if (e2
.type
.isreal())
355 const r2
= e2
.toReal();
356 c
= complex_t(e1
.toReal() % r2
, e1
.toImaginary() % r2
);
358 else if (e2
.type
.isimaginary())
360 const i2
= e2
.toImaginary();
361 c
= complex_t(e1
.toReal() % i2
, e1
.toImaginary() % i2
);
366 emplaceExp
!(RealExp
)(&ue
, loc
, creall(c
), type
);
367 else if (type
.isimaginary())
368 emplaceExp
!(RealExp
)(&ue
, loc
, cimagl(c
), type
);
369 else if (type
.iscomplex())
370 emplaceExp
!(ComplexExp
)(&ue
, loc
, c
, type
);
383 error(e2
.loc
, "divide by 0");
384 emplaceExp
!(ErrorExp
)(&ue
);
387 if (n2
== -1 && !type
.isunsigned())
389 // Check for int.min % -1
390 if (n1
== 0xFFFFFFFF80000000UL
&& type
.toBasetype().ty
!= Tint64
)
392 error(e2
.loc
, "integer overflow: `int.min %% -1`");
393 emplaceExp
!(ErrorExp
)(&ue
);
396 else if (n1
== 0x8000000000000000L
) // long.min % -1
398 error(e2
.loc
, "integer overflow: `long.min %% -1L`");
399 emplaceExp
!(ErrorExp
)(&ue
);
403 if (e1
.type
.isunsigned() || e2
.type
.isunsigned())
404 n
= (cast(dinteger_t
)n1
) % (cast(dinteger_t
)n2
);
407 emplaceExp
!(IntegerExp
)(&ue
, loc
, n
, type
);
412 UnionExp
Pow(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
416 // Handle integer power operations.
417 if (e2
.type
.isintegral())
419 dinteger_t n
= e2
.toInteger();
421 if (!e2
.type
.isunsigned() && cast(sinteger_t
)n
< 0)
423 if (e1
.type
.isintegral())
428 // Don't worry about overflow, from now on n is unsigned.
435 if (e1
.type
.iscomplex())
437 emplaceExp
!(ComplexExp
)(&ur
, loc
, e1
.toComplex(), e1
.type
);
438 emplaceExp
!(ComplexExp
)(&uv
, loc
, complex_t(CTFloat
.one
), e1
.type
);
440 else if (e1
.type
.isfloating())
442 emplaceExp
!(RealExp
)(&ur
, loc
, e1
.toReal(), e1
.type
);
443 emplaceExp
!(RealExp
)(&uv
, loc
, CTFloat
.one
, e1
.type
);
447 emplaceExp
!(IntegerExp
)(&ur
, loc
, e1
.toInteger(), e1
.type
);
448 emplaceExp
!(IntegerExp
)(&uv
, loc
, 1, e1
.type
);
450 Expression r
= ur
.exp();
451 Expression v
= uv
.exp();
457 uv
= Mul(loc
, v
.type
, v
, r
);
461 ur
= Mul(loc
, r
.type
, r
, r
);
467 emplaceExp
!(RealExp
)(&one
, loc
, CTFloat
.one
, v
.type
);
468 uv
= Div(loc
, v
.type
, one
.exp(), v
);
470 if (type
.iscomplex())
471 emplaceExp
!(ComplexExp
)(&ue
, loc
, v
.toComplex(), type
);
472 else if (type
.isintegral())
473 emplaceExp
!(IntegerExp
)(&ue
, loc
, v
.toInteger(), type
);
475 emplaceExp
!(RealExp
)(&ue
, loc
, v
.toReal(), type
);
477 else if (e2
.type
.isfloating())
479 // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
480 if (e1
.toReal() < CTFloat
.zero
)
482 emplaceExp
!(RealExp
)(&ue
, loc
, target
.RealProperties
.nan
, type
);
492 UnionExp
Shl(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
495 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() << e2
.toInteger(), type
);
499 UnionExp
Shr(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
502 dinteger_t value
= e1
.toInteger();
503 dinteger_t dcount
= e2
.toInteger();
504 assert(dcount
<= 0xFFFFFFFF);
505 uint count
= cast(uint)dcount
;
506 switch (e1
.type
.toBasetype().ty
)
509 value
= cast(byte)value
>> count
;
513 value
= cast(ubyte)value
>> count
;
516 value
= cast(short)value
>> count
;
520 value
= cast(ushort)value
>> count
;
523 value
= cast(int)value
>> count
;
527 value
= cast(uint)value
>> count
;
530 value
= cast(long)value
>> count
;
533 value
= cast(ulong)value
>> count
;
536 emplaceExp
!(ErrorExp
)(&ue
);
541 emplaceExp
!(IntegerExp
)(&ue
, loc
, value
, type
);
545 UnionExp
Ushr(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
548 dinteger_t value
= e1
.toInteger();
549 dinteger_t dcount
= e2
.toInteger();
550 assert(dcount
<= 0xFFFFFFFF);
551 uint count
= cast(uint)dcount
;
552 switch (e1
.type
.toBasetype().ty
)
557 // Possible only with >>>=. >>> always gets promoted to int.
558 value
= (value
& 0xFF) >>> count
;
563 // Possible only with >>>=. >>> always gets promoted to int.
564 value
= (value
& 0xFFFF) >>> count
;
569 value
= (value
& 0xFFFFFFFF) >>> count
;
573 value
= value
>>> count
;
576 emplaceExp
!(ErrorExp
)(&ue
);
581 emplaceExp
!(IntegerExp
)(&ue
, loc
, value
, type
);
585 UnionExp
And(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
588 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() & e2
.toInteger(), type
);
592 UnionExp
Or(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
595 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() | e2
.toInteger(), type
);
599 UnionExp
Xor(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
601 //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
603 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() ^ e2
.toInteger(), type
);
607 /* Also returns EXP.cantExpression if cannot be computed.
609 UnionExp
Equal(EXP op
, const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
613 real_t r1
= CTFloat
.zero
;
614 real_t r2
= CTFloat
.zero
;
615 //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
616 assert(op
== EXP
.equal || op
== EXP
.notEqual
);
617 if (e1
.op
== EXP
.null_
)
619 if (e2
.op
== EXP
.null_
)
621 else if (StringExp es2
= e2
.isStringExp())
623 cmp = (0 == es2
.len
);
625 else if (ArrayLiteralExp es2
= e2
.isArrayLiteralExp())
627 cmp = !es2
.elements ||
(0 == es2
.elements
.length
);
635 else if (e2
.op
== EXP
.null_
)
637 if (StringExp es1
= e1
.isStringExp())
639 cmp = (0 == es1
.len
);
641 else if (ArrayLiteralExp es1
= e1
.isArrayLiteralExp())
643 cmp = !es1
.elements ||
(0 == es1
.elements
.length
);
651 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.string_
)
653 StringExp es1
= e1
.isStringExp();
654 StringExp es2
= e2
.isStringExp();
655 if (es1
.sz
!= es2
.sz
)
657 assert(global
.errors
);
661 const data1
= es1
.peekData();
662 const data2
= es2
.peekData();
663 if (es1
.len
== es2
.len
&& memcmp(data1
.ptr
, data2
.ptr
, es1
.sz
* es1
.len
) == 0)
668 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.arrayLiteral
)
670 ArrayLiteralExp es1
= e1
.isArrayLiteralExp();
671 ArrayLiteralExp es2
= e2
.isArrayLiteralExp();
672 if ((!es1
.elements ||
!es1
.elements
.length
) && (!es2
.elements ||
!es2
.elements
.length
))
673 cmp = 1; // both arrays are empty
674 else if (!es1
.elements ||
!es2
.elements
)
676 else if (es1
.elements
.length
!= es2
.elements
.length
)
680 for (size_t i
= 0; i
< es1
.elements
.length
; i
++)
684 ue
= Equal(EXP
.equal
, loc
, Type
.tint32
, ee1
, ee2
);
685 if (CTFEExp
.isCantExp(ue
.exp()))
687 cmp = cast(int)ue
.exp().toInteger();
693 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.string_
)
695 // Swap operands and use common code
696 Expression etmp
= e1
;
701 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.arrayLiteral
)
704 StringExp es1
= e1
.isStringExp();
705 ArrayLiteralExp es2
= e2
.isArrayLiteralExp();
706 size_t dim1
= es1
.len
;
707 size_t dim2
= es2
.elements ? es2
.elements
.length
: 0;
712 cmp = 1; // if dim1 winds up being 0
713 foreach (i
; 0 .. dim1
)
715 uinteger_t c
= es1
.getIndex(i
);
717 if (ee2
.isConst() != 1)
722 cmp = (c
== ee2
.toInteger());
728 else if (e1
.op
== EXP
.structLiteral
&& e2
.op
== EXP
.structLiteral
)
730 StructLiteralExp es1
= e1
.isStructLiteralExp();
731 StructLiteralExp es2
= e2
.isStructLiteralExp();
732 if (es1
.sd
!= es2
.sd
)
734 else if ((!es1
.elements ||
!es1
.elements
.length
) && (!es2
.elements ||
!es2
.elements
.length
))
735 cmp = 1; // both arrays are empty
736 else if (!es1
.elements ||
!es2
.elements
)
738 else if (es1
.elements
.length
!= es2
.elements
.length
)
743 for (size_t i
= 0; i
< es1
.elements
.length
; i
++)
745 Expression ee1
= (*es1
.elements
)[i
];
746 Expression ee2
= (*es2
.elements
)[i
];
754 ue
= Equal(EXP
.equal
, loc
, Type
.tint32
, ee1
, ee2
);
755 if (ue
.exp().op
== EXP
.cantExpression
)
757 cmp = cast(int)ue
.exp().toInteger();
763 else if (e1
.isConst() != 1 || e2
.isConst() != 1)
768 else if (e1
.type
.isreal())
774 else if (e1
.type
.isimaginary())
776 r1
= e1
.toImaginary();
777 r2
= e2
.toImaginary();
779 if (CTFloat
.isNaN(r1
) || CTFloat
.isNaN(r2
)) // if unordered
788 else if (e1
.type
.iscomplex())
790 cmp = e1
.toComplex() == e2
.toComplex();
792 else if (e1
.type
.isintegral() || e1
.type
.toBasetype().ty
== Tpointer
)
794 cmp = (e1
.toInteger() == e2
.toInteger());
801 if (op
== EXP
.notEqual
)
803 emplaceExp
!(IntegerExp
)(&ue
, loc
, cmp, type
);
807 UnionExp
Identity(EXP op
, const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
811 if (e1
.op
== EXP
.null_
)
813 cmp = (e2
.op
== EXP
.null_
);
815 else if (e2
.op
== EXP
.null_
)
819 else if (e1
.op
== EXP
.symbolOffset
&& e2
.op
== EXP
.symbolOffset
)
821 SymOffExp es1
= e1
.isSymOffExp();
822 SymOffExp es2
= e2
.isSymOffExp();
823 cmp = (es1
.var
== es2
.var
&& es1
.offset
== es2
.offset
);
827 if (e1
.type
.isfloating())
828 cmp = e1
.isIdentical(e2
);
831 ue
= Equal((op
== EXP
.identity
) ? EXP
.equal
: EXP
.notEqual
, loc
, type
, e1
, e2
);
835 if (op
== EXP
.notIdentity
)
837 emplaceExp
!(IntegerExp
)(&ue
, loc
, cmp, type
);
841 UnionExp
Cmp(EXP op
, const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
845 real_t r1
= CTFloat
.zero
;
846 real_t r2
= CTFloat
.zero
;
847 //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
848 if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.string_
)
850 StringExp es1
= e1
.isStringExp();
851 StringExp es2
= e2
.isStringExp();
853 assert(sz
== es2
.sz
);
854 size_t len
= es1
.len
;
857 const data1
= es1
.peekData();
858 const data2
= es1
.peekData();
859 int rawCmp
= memcmp(data1
.ptr
, data2
.ptr
, sz
* len
);
861 rawCmp
= cast(int)(es1
.len
- es2
.len
);
862 n
= specificCmp(op
, rawCmp
);
864 else if (e1
.isConst() != 1 || e2
.isConst() != 1)
869 else if (e1
.type
.isreal())
875 else if (e1
.type
.isimaginary())
877 r1
= e1
.toImaginary();
878 r2
= e2
.toImaginary();
880 n
= realCmp(op
, r1
, r2
);
882 else if (e1
.type
.iscomplex())
892 if (e1
.type
.isunsigned() || e2
.type
.isunsigned())
893 n
= intUnsignedCmp(op
, n1
, n2
);
895 n
= intSignedCmp(op
, n1
, n2
);
897 emplaceExp
!(IntegerExp
)(&ue
, loc
, n
, type
);
901 /* Also returns EXP.cantExpression if cannot be computed.
902 * to: type to cast to
903 * type: type to paint the result
905 UnionExp
Cast(const ref Loc loc
, Type type
, Type to
, Expression e1
)
908 Type tb
= to
.toBasetype();
909 Type typeb
= type
.toBasetype();
910 //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
911 //printf("\te1.type = %s\n", e1.type.toChars());
912 if (e1
.type
.equals(type
) && type
.equals(to
))
914 emplaceExp
!(UnionExp
)(&ue
, e1
);
917 if (e1
.op
== EXP
.vector
&& (cast(TypeVector
)e1
.type
).basetype
.equals(type
) && type
.equals(to
))
919 Expression ex
= e1
.isVectorExp().e1
;
920 emplaceExp
!(UnionExp
)(&ue
, ex
);
923 if (e1
.type
.toBasetype
.equals(type
) && type
.equals(to
))
925 emplaceExp
!(UnionExp
)(&ue
, e1
);
926 ue
.exp().type
= type
;
929 if (e1
.type
.implicitConvTo(to
) >= MATCH
.constant || to
.implicitConvTo(e1
.type
) >= MATCH
.constant
)
933 // Allow covariant converions of delegates
934 // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
935 // then we wouldn't need this extra check.)
936 if (e1
.type
.toBasetype().ty
== Tdelegate
&& e1
.type
.implicitConvTo(to
) == MATCH
.convert
)
940 /* Allow casting from one string type to another
942 if (e1
.op
== EXP
.string_
)
944 if (tb
.ty
== Tarray
&& typeb
.ty
== Tarray
&& tb
.nextOf().size() == typeb
.nextOf().size())
949 if (e1
.op
== EXP
.arrayLiteral
&& typeb
== tb
)
952 Expression ex
= expType(to
, e1
);
953 emplaceExp
!(UnionExp
)(&ue
, ex
);
956 if (e1
.isConst() != 1)
960 else if (tb
.ty
== Tbool
)
962 const opt
= e1
.toBool();
969 emplaceExp
!(IntegerExp
)(&ue
, loc
, opt
.get(), type
);
971 else if (type
.isintegral())
973 if (e1
.type
.isfloating())
976 real_t r
= e1
.toReal();
980 result
= cast(byte)cast(sinteger_t
)r
;
984 result
= cast(ubyte)cast(dinteger_t
)r
;
987 result
= cast(short)cast(sinteger_t
)r
;
991 result
= cast(ushort)cast(dinteger_t
)r
;
998 result
= cast(uint)r
;
1001 result
= cast(long)r
;
1004 result
= cast(ulong)r
;
1009 emplaceExp
!(IntegerExp
)(&ue
, loc
, result
, type
);
1011 else if (type
.isunsigned())
1012 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toUInteger(), type
);
1014 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger(), type
);
1016 else if (tb
.isreal())
1018 real_t value
= e1
.toReal();
1019 emplaceExp
!(RealExp
)(&ue
, loc
, value
, type
);
1021 else if (tb
.isimaginary())
1023 real_t value
= e1
.toImaginary();
1024 emplaceExp
!(RealExp
)(&ue
, loc
, value
, type
);
1026 else if (tb
.iscomplex())
1028 complex_t value
= e1
.toComplex();
1029 emplaceExp
!(ComplexExp
)(&ue
, loc
, value
, type
);
1031 else if (tb
.isscalar())
1033 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger(), type
);
1035 else if (tb
.ty
== Tvoid
)
1039 else if (tb
.ty
== Tstruct
&& e1
.op
== EXP
.int64
)
1042 StructDeclaration sd
= tb
.toDsymbol(null).isStructDeclaration();
1044 auto elements
= new Expressions();
1045 for (size_t i
= 0; i
< sd
.fields
.length
; i
++)
1047 VarDeclaration v
= sd
.fields
[i
];
1049 emplaceExp
!(IntegerExp
)(&zero
, 0);
1050 ue
= Cast(loc
, v
.type
, v
.type
, zero
.exp());
1051 if (ue
.exp().op
== EXP
.cantExpression
)
1053 elements
.push(ue
.exp().copy());
1055 emplaceExp
!(StructLiteralExp
)(&ue
, loc
, sd
, elements
);
1056 ue
.exp().type
= type
;
1060 if (type
!= Type
.terror
)
1062 // have to change to internal compiler error
1063 // all invalid casts should be handled already in Expression::castTo().
1064 error(loc
, "cannot cast `%s` to `%s`", e1
.type
.toChars(), type
.toChars());
1066 emplaceExp
!(ErrorExp
)(&ue
);
1071 UnionExp
ArrayLength(Type type
, Expression e1
)
1075 if (StringExp es1
= e1
.isStringExp())
1077 emplaceExp
!(IntegerExp
)(&ue
, loc
, es1
.len
, type
);
1079 else if (ArrayLiteralExp ale
= e1
.isArrayLiteralExp())
1081 size_t dim
= ale
.elements ? ale
.elements
.length
: 0;
1082 emplaceExp
!(IntegerExp
)(&ue
, loc
, dim
, type
);
1084 else if (AssocArrayLiteralExp ale
= e1
.isAssocArrayLiteralExp
)
1086 size_t dim
= ale
.keys
.length
;
1087 emplaceExp
!(IntegerExp
)(&ue
, loc
, dim
, type
);
1089 else if (e1
.type
.toBasetype().ty
== Tsarray
)
1091 Expression e
= (cast(TypeSArray
)e1
.type
.toBasetype()).dim
;
1092 emplaceExp
!(UnionExp
)(&ue
, e
);
1094 else if (e1
.isNullExp())
1096 emplaceExp
!(IntegerExp
)(&ue
, loc
, 0, type
);
1103 /* Also return EXP.cantExpression if this fails
1105 UnionExp
Index(Type type
, Expression e1
, Expression e2
, bool indexIsInBounds
)
1109 //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1111 if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.int64
)
1113 StringExp es1
= e1
.isStringExp();
1114 uinteger_t i
= e2
.toInteger();
1117 error(e1
.loc
, "string index %llu is out of bounds `[0 .. %llu]`", i
, cast(ulong)es1
.len
);
1118 emplaceExp
!(ErrorExp
)(&ue
);
1122 emplaceExp
!(IntegerExp
)(&ue
, loc
, es1
.getIndex(cast(size_t
) i
), type
);
1125 else if (e1
.type
.toBasetype().ty
== Tsarray
&& e2
.op
== EXP
.int64
)
1127 TypeSArray tsa
= cast(TypeSArray
)e1
.type
.toBasetype();
1128 uinteger_t length
= tsa
.dim
.toInteger();
1129 uinteger_t i
= e2
.toInteger();
1130 if (i
>= length
&& (e1
.op
== EXP
.arrayLiteral ||
!indexIsInBounds
))
1132 // C code only checks bounds if an ArrayLiteralExp
1133 error(e1
.loc
, "array index %llu is out of bounds `%s[0 .. %llu]`", i
, e1
.toChars(), length
);
1134 emplaceExp
!(ErrorExp
)(&ue
);
1136 else if (ArrayLiteralExp ale
= e1
.isArrayLiteralExp())
1138 auto e
= ale
[cast(size_t
)i
];
1141 if (hasSideEffect(e
))
1144 emplaceExp
!(UnionExp
)(&ue
, e
);
1149 else if (e1
.type
.toBasetype().ty
== Tarray
&& e2
.op
== EXP
.int64
)
1151 uinteger_t i
= e2
.toInteger();
1152 if (ArrayLiteralExp ale
= e1
.isArrayLiteralExp())
1154 if (i
>= ale
.elements
.length
)
1156 error(e1
.loc
, "array index %llu is out of bounds `%s[0 .. %llu]`", i
, e1
.toChars(), cast(ulong) ale
.elements
.length
);
1157 emplaceExp
!(ErrorExp
)(&ue
);
1161 auto e
= ale
[cast(size_t
)i
];
1164 if (hasSideEffect(e
))
1167 emplaceExp
!(UnionExp
)(&ue
, e
);
1173 else if (AssocArrayLiteralExp ae
= e1
.isAssocArrayLiteralExp())
1175 /* Search the keys backwards, in case there are duplicate keys
1177 for (size_t i
= ae
.keys
.length
; i
;)
1180 Expression ekey
= (*ae
.keys
)[i
];
1181 ue
= Equal(EXP
.equal
, loc
, Type
.tbool
, ekey
, e2
);
1182 if (CTFEExp
.isCantExp(ue
.exp()))
1184 if (ue
.exp().toBool().hasValue(true))
1186 Expression e
= (*ae
.values
)[i
];
1189 if (hasSideEffect(e
))
1192 emplaceExp
!(UnionExp
)(&ue
, e
);
1203 /* Also return EXP.cantExpression if this fails
1205 UnionExp
Slice(Type type
, Expression e1
, Expression lwr
, Expression upr
)
1211 printf("Slice()\n");
1214 printf("\te1 = %s\n", e1
.toChars());
1215 printf("\tlwr = %s\n", lwr
.toChars());
1216 printf("\tupr = %s\n", upr
.toChars());
1222 if (e1
.op
== EXP
.string_
)
1223 emplaceExp(&ue
, e1
);
1227 else if (e1
.op
== EXP
.string_
&& lwr
.op
== EXP
.int64
&& upr
.op
== EXP
.int64
)
1229 StringExp es1
= e1
.isStringExp();
1230 const uinteger_t ilwr
= lwr
.toInteger();
1231 const uinteger_t iupr
= upr
.toInteger();
1232 if (sliceBoundsCheck(0, es1
.len
, ilwr
, iupr
))
1233 cantExp(ue
); // https://issues.dlang.org/show_bug.cgi?id=18115
1236 const len
= cast(size_t
)(iupr
- ilwr
);
1238 void* s
= mem
.xmalloc(len
* sz
);
1239 const data1
= es1
.peekData();
1240 memcpy(s
, data1
.ptr
+ ilwr
* sz
, len
* sz
);
1241 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
, es1
.postfix
);
1242 StringExp es
= ue
.exp().isStringExp();
1243 es
.committed
= es1
.committed
;
1247 else if (e1
.op
== EXP
.arrayLiteral
&& lwr
.op
== EXP
.int64
&& upr
.op
== EXP
.int64
&& !hasSideEffect(e1
))
1249 ArrayLiteralExp es1
= e1
.isArrayLiteralExp();
1250 const uinteger_t ilwr
= lwr
.toInteger();
1251 const uinteger_t iupr
= upr
.toInteger();
1252 if (sliceBoundsCheck(0, es1
.elements
.length
, ilwr
, iupr
))
1256 auto elements
= new Expressions(cast(size_t
)(iupr
- ilwr
));
1257 memcpy(elements
.tdata(), es1
.elements
.tdata() + ilwr
, cast(size_t
)(iupr
- ilwr
) * ((*es1
.elements
)[0]).sizeof
);
1258 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, elements
);
1266 /* Check whether slice `[newlwr .. newupr]` is in the range `[lwr .. upr]`
1268 bool sliceBoundsCheck(uinteger_t lwr
, uinteger_t upr
, uinteger_t newlwr
, uinteger_t newupr
) pure @safe
1271 return !(newlwr
<= newupr
&&
1276 /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
1277 * existingAE[firstIndex..firstIndex+newval.length] = newval.
1279 void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE
, const StringExp newval
, size_t firstIndex
)
1281 const len
= newval
.len
;
1282 Type elemType
= existingAE
.type
.nextOf();
1283 foreach (j
; 0 .. len
)
1285 const val
= newval
.getIndex(j
);
1286 (*existingAE
.elements
)[j
+ firstIndex
] = new IntegerExp(newval
.loc
, val
, elemType
);
1290 /* Set a slice of string 'existingSE' from a char array literal 'newae'.
1291 * existingSE[firstIndex..firstIndex+newae.length] = newae.
1293 void sliceAssignStringFromArrayLiteral(StringExp existingSE
, ArrayLiteralExp newae
, size_t firstIndex
)
1295 assert(existingSE
.ownedByCtfe
!= OwnedBy
.code
);
1296 foreach (j
; 0 .. newae
.elements
.length
)
1298 existingSE
.setCodeUnit(firstIndex
+ j
, cast(dchar)newae
[j
].toInteger());
1302 /* Set a slice of string 'existingSE' from a string 'newstr'.
1303 * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
1305 void sliceAssignStringFromString(StringExp existingSE
, const StringExp newstr
, size_t firstIndex
)
1307 assert(existingSE
.ownedByCtfe
!= OwnedBy
.code
);
1308 size_t sz
= existingSE
.sz
;
1309 assert(sz
== newstr
.sz
);
1310 auto data1
= existingSE
.borrowData();
1311 const data2
= newstr
.peekData();
1312 memcpy(data1
.ptr
+ firstIndex
* sz
, data2
.ptr
, data2
.length
);
1315 /* Compare a string slice with another string slice.
1316 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
1318 int sliceCmpStringWithString(const StringExp se1
, const StringExp se2
, size_t lo1
, size_t lo2
, size_t len
)
1321 assert(sz
== se2
.sz
);
1322 const data1
= se1
.peekData();
1323 const data2
= se2
.peekData();
1324 return memcmp(data1
.ptr
+ sz
* lo1
, data2
.ptr
+ sz
* lo2
, sz
* len
);
1327 /* Compare a string slice with an array literal slice
1328 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
1330 int sliceCmpStringWithArray(const StringExp se1
, ArrayLiteralExp ae2
, size_t lo1
, size_t lo2
, size_t len
)
1332 foreach (j
; 0 .. len
)
1334 const val2
= ae2
[j
+ lo2
].toInteger();
1335 const val1
= se1
.getIndex(j
+ lo1
);
1336 const int c
= (val1
> val2
) - (val1
< val2
);
1343 /** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
1345 * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
1346 * Otherwise, `e1` itself will be pushed into the new `Expressions`.
1347 * e2 = If it's not `null`, it will be pushed/appended to the new
1348 * `Expressions` by the same way with `e1`.
1350 * Newly allocated `Expressions`. Note that it points to the original
1351 * `Expression` values in e1 and e2.
1353 private Expressions
* copyElements(Expression e1
, Expression e2
= null)
1355 auto elems
= new Expressions();
1357 void append(ArrayLiteralExp ale
)
1361 auto d
= elems
.length
;
1362 elems
.append(ale
.elements
);
1363 foreach (ref el
; (*elems
)[d
.. elems
.length
])
1370 if (auto ale
= e1
.isArrayLiteralExp())
1377 if (auto ale
= e2
.isArrayLiteralExp())
1386 /* Also return EXP.cantExpression if this fails
1388 UnionExp
Cat(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
1391 Expression e
= CTFEExp
.cantexp
;
1393 Type t1
= e1
.type
.toBasetype();
1394 Type t2
= e2
.type
.toBasetype();
1395 //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1396 //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
1398 /* e is the non-null operand, t is the type of the null operand
1400 UnionExp
catNull(Expression e
, Type t
)
1402 Type tn
= e
.type
.toBasetype();
1403 if (tn
.ty
.isSomeChar
)
1405 // Create a StringExp
1407 t
= t
.nextOf().toBasetype();
1408 const sz
= cast(ubyte)t
.size();
1409 dinteger_t v
= e
.toInteger();
1410 const len
= (t
.ty
== tn
.ty
) ?
1 : utf_codeLength(sz
, cast(dchar)v
);
1411 void* s
= mem
.xmalloc(len
* sz
);
1413 Port
.valcpy(s
, v
, sz
);
1415 utf_encode(sz
, s
, cast(dchar)v
);
1416 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1417 StringExp es
= ue
.exp().isStringExp();
1419 es
.committed
= true;
1423 // Create an ArrayLiteralExp
1424 auto elements
= new Expressions();
1426 emplaceExp
!(ArrayLiteralExp
)(&ue
, e
.loc
, type
, elements
);
1428 assert(ue
.exp().type
);
1432 if (e1
.op
== EXP
.null_
&& (e2
.op
== EXP
.int64 || e2
.op
== EXP
.structLiteral
))
1434 return catNull(e2
, t1
);
1436 else if ((e1
.op
== EXP
.int64 || e1
.op
== EXP
.structLiteral
) && e2
.op
== EXP
.null_
)
1438 return catNull(e1
, t2
);
1440 else if (e1
.op
== EXP
.null_
&& e2
.op
== EXP
.null_
)
1442 if (type
== e1
.type
)
1444 // Handle null ~= null
1445 if (t1
.ty
== Tarray
&& t2
== t1
.nextOf())
1447 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, e2
);
1448 assert(ue
.exp().type
);
1453 emplaceExp
!(UnionExp
)(&ue
, e1
);
1454 assert(ue
.exp().type
);
1458 if (type
== e2
.type
)
1460 emplaceExp
!(UnionExp
)(&ue
, e2
);
1461 assert(ue
.exp().type
);
1464 emplaceExp
!(NullExp
)(&ue
, e1
.loc
, type
);
1465 assert(ue
.exp().type
);
1468 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.string_
)
1470 // Concatenate the strings
1471 StringExp es1
= e1
.isStringExp();
1472 StringExp es2
= e2
.isStringExp();
1473 size_t len
= es1
.len
+ es2
.len
;
1478 * auto s = "foo"d ~ "bar"c;
1480 assert(global
.errors
);
1482 assert(ue
.exp().type
);
1485 void* s
= mem
.xmalloc(len
* sz
);
1486 const data1
= es1
.peekData();
1487 const data2
= es2
.peekData();
1488 memcpy(cast(char*)s
, data1
.ptr
, es1
.len
* sz
);
1489 memcpy(cast(char*)s
+ es1
.len
* sz
, data2
.ptr
, es2
.len
* sz
);
1490 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1491 StringExp es
= ue
.exp().isStringExp();
1492 es
.committed
= es1
.committed | es2
.committed
;
1494 assert(ue
.exp().type
);
1497 else if (e2
.op
== EXP
.string_
&& e1
.op
== EXP
.arrayLiteral
&& t1
.nextOf().isintegral())
1499 // [chars] ~ string --> [chars]
1500 StringExp es
= e2
.isStringExp();
1501 ArrayLiteralExp ea
= e1
.isArrayLiteralExp();
1502 size_t len
= es
.len
+ ea
.elements
.length
;
1503 auto elems
= new Expressions(len
);
1504 for (size_t i
= 0; i
< ea
.elements
.length
; ++i
)
1506 (*elems
)[i
] = ea
[i
];
1508 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, elems
);
1509 ArrayLiteralExp dest
= ue
.exp().isArrayLiteralExp();
1510 sliceAssignArrayLiteralFromString(dest
, es
, ea
.elements
.length
);
1511 assert(ue
.exp().type
);
1514 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.arrayLiteral
&& t2
.nextOf().isintegral())
1516 // string ~ [chars] --> [chars]
1517 StringExp es
= e1
.isStringExp();
1518 ArrayLiteralExp ea
= e2
.isArrayLiteralExp();
1519 size_t len
= es
.len
+ ea
.elements
.length
;
1520 auto elems
= new Expressions(len
);
1521 for (size_t i
= 0; i
< ea
.elements
.length
; ++i
)
1523 (*elems
)[es
.len
+ i
] = ea
[i
];
1525 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, elems
);
1526 ArrayLiteralExp dest
= ue
.exp().isArrayLiteralExp();
1527 sliceAssignArrayLiteralFromString(dest
, es
, 0);
1528 assert(ue
.exp().type
);
1531 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.int64
)
1533 // string ~ char --> string
1534 StringExp es1
= e1
.isStringExp();
1537 dinteger_t v
= e2
.toInteger();
1538 // Is it a concatenation of homogenous types?
1539 // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
1540 bool homoConcat
= (sz
== t2
.size());
1541 const len
= es1
.len
+ (homoConcat ?
1 : utf_codeLength(sz
, cast(dchar)v
));
1542 void* s
= mem
.xmalloc(len
* sz
);
1543 const data1
= es1
.peekData();
1544 memcpy(s
, data1
.ptr
, data1
.length
);
1546 Port
.valcpy(cast(char*)s
+ (sz
* es1
.len
), v
, sz
);
1548 utf_encode(sz
, cast(char*)s
+ (sz
* es1
.len
), cast(dchar)v
);
1549 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1550 es
= ue
.exp().isStringExp();
1551 es
.committed
= es1
.committed
;
1553 assert(ue
.exp().type
);
1556 else if (e1
.op
== EXP
.int64
&& e2
.op
== EXP
.string_
)
1558 // [w|d]?char ~ string --> string
1559 // We assume that we only ever prepend one char of the same type
1560 // (wchar,dchar) as the string's characters.
1561 StringExp es2
= e2
.isStringExp();
1562 const len
= 1 + es2
.len
;
1564 dinteger_t v
= e1
.toInteger();
1565 void* s
= mem
.xmalloc(len
* sz
);
1566 Port
.valcpy(cast(char*)s
, v
, sz
);
1567 const data2
= es2
.peekData();
1568 memcpy(cast(char*)s
+ sz
, data2
.ptr
, data2
.length
);
1569 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1570 StringExp es
= ue
.exp().isStringExp();
1572 es
.committed
= es2
.committed
;
1574 assert(ue
.exp().type
);
1577 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.arrayLiteral
&& t1
.nextOf().equals(t2
.nextOf()))
1579 // Concatenate the arrays
1580 auto elems
= copyElements(e1
, e2
);
1582 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, cast(Type
)null, elems
);
1585 if (type
.toBasetype().ty
== Tsarray
)
1587 e
.type
= t1
.nextOf().sarrayOf(elems
.length
);
1591 assert(ue
.exp().type
);
1594 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.null_
&& t1
.nextOf().equals(t2
.nextOf()))
1599 else if (e1
.op
== EXP
.null_
&& e2
.op
== EXP
.arrayLiteral
&& t1
.nextOf().equals(t2
.nextOf()))
1603 // Concatenate the array with null
1604 auto elems
= copyElements(e
);
1606 emplaceExp
!(ArrayLiteralExp
)(&ue
, e
.loc
, cast(Type
)null, elems
);
1609 if (type
.toBasetype().ty
== Tsarray
)
1611 e
.type
= t1
.nextOf().sarrayOf(elems
.length
);
1615 assert(ue
.exp().type
);
1618 else if ((e1
.op
== EXP
.arrayLiteral || e1
.op
== EXP
.null_
) && e1
.type
.toBasetype().nextOf() && e1
.type
.toBasetype().nextOf().equals(e2
.type
))
1620 auto elems
= (e1
.op
== EXP
.arrayLiteral
)
1621 ?
copyElements(e1
) : new Expressions();
1624 emplaceExp
!(ArrayLiteralExp
)(&ue
, loc
, cast(Type
)null, elems
);
1627 if (type
.toBasetype().ty
== Tsarray
)
1629 e
.type
= e2
.type
.sarrayOf(elems
.length
);
1633 assert(ue
.exp().type
);
1636 else if (e2
.op
== EXP
.arrayLiteral
&& e2
.type
.toBasetype().nextOf().equals(e1
.type
))
1638 auto elems
= copyElements(e1
, e2
);
1640 emplaceExp
!(ArrayLiteralExp
)(&ue
, loc
, cast(Type
)null, elems
);
1643 if (type
.toBasetype().ty
== Tsarray
)
1645 e
.type
= e1
.type
.sarrayOf(elems
.length
);
1649 assert(ue
.exp().type
);
1652 else if (e1
.op
== EXP
.null_
&& e2
.op
== EXP
.string_
)
1658 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.null_
)
1663 Type tb
= t
.toBasetype();
1664 if (tb
.ty
== Tarray
&& tb
.nextOf().equivalent(e
.type
))
1666 auto expressions
= new Expressions();
1667 expressions
.push(e
);
1668 emplaceExp
!(ArrayLiteralExp
)(&ue
, loc
, t
, expressions
);
1673 emplaceExp
!(UnionExp
)(&ue
, e
);
1676 if (!e
.type
.equals(type
))
1678 StringExp se
= e
.copy().isStringExp();
1679 e
= se
.castTo(null, type
);
1680 emplaceExp
!(UnionExp
)(&ue
, e
);
1686 assert(ue
.exp().type
);
1690 UnionExp
Ptr(Type type
, Expression e1
)
1692 //printf("Ptr(e1 = %s)\n", e1.toChars());
1694 if (AddExp ae
= e1
.isAddExp())
1696 if (AddrExp ade
= ae
.e1
.isAddrExp())
1698 if (ae
.e2
.op
== EXP
.int64
)
1699 if (StructLiteralExp se
= ade
.e1
.isStructLiteralExp())
1701 uint offset
= cast(uint)ae
.e2
.toInteger();
1702 Expression e
= se
.getField(type
, offset
);
1705 emplaceExp
!(UnionExp
)(&ue
, e
);