2 * Semantic analysis for cast-expressions.
4 * Copyright: Copyright (C) 1999-2023 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
14 import core
.stdc
.stdio
;
15 import core
.stdc
.string
;
19 import dmd
.arraytypes
;
22 import dmd
.declaration
;
23 import dmd
.dinterpret
;
29 import dmd
.expression
;
30 import dmd
.expressionsem
;
42 import dmd
.root
.ctfloat
;
43 import dmd
.common
.outbuffer
;
52 * Attempt to implicitly cast the expression into type `t`.
54 * This routine will change `e`. To check the matching level,
55 * use `implicitConvTo`.
58 * e = Expression that is to be casted
60 * t = Expected resulting type
63 * The resulting casted expression (mutating `e`), or `ErrorExp`
64 * if such an implicit conversion is not possible.
66 Expression
implicitCastTo(Expression e
, Scope
* sc
, Type t
)
68 Expression
visit(Expression e
)
70 // printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
72 if (const match
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? e
.cimplicitConvTo(t
) : e
.implicitConvTo(t
))
74 // no need for an extra cast when matching is exact
76 if (match
== MATCH
.convert
&& e
.type
.isTypeNoreturn() && e
.op
!= EXP
.type
)
78 return specialNoreturnCast(e
, t
);
80 if (match
== MATCH
.constant
&& (e
.type
.constConv(t
) ||
!e
.isLvalue() && e
.type
.equivalent(t
)))
82 /* Do not emit CastExp for const conversions and
83 * unique conversions on rvalue.
85 auto result
= e
.copy();
90 auto ad
= isAggregate(e
.type
);
91 if (ad
&& ad
.aliasthis
)
93 if (!ad
.type || ad
.type
.isTypeError())
95 auto ts
= ad
.type
.isTypeStruct();
97 ? ts
.implicitConvToWithoutAliasThis(t
)
98 : ad
.type
.isTypeClass().implicitConvToWithoutAliasThis(t
);
102 Type tob
= t
.toBasetype();
103 Type t1b
= e
.type
.toBasetype();
104 if (ad
!= isAggregate(tob
))
106 if (t1b
.ty
== Tclass
&& tob
.ty
== Tclass
)
108 ClassDeclaration t1cd
= t1b
.isClassHandle();
109 ClassDeclaration tocd
= tob
.isClassHandle();
111 if (tocd
.isBaseOf(t1cd
, &offset
))
113 auto result
= new CastExp(e
.loc
, e
, t
);
119 /* Forward the cast to our alias this member, rewrite to:
120 * cast(to)e1.aliasthis
122 auto result
= resolveAliasThis(sc
, e
);
123 return result
.castTo(sc
, t
);
128 return e
.castTo(sc
, t
);
131 auto result
= e
.optimize(WANTvalue
);
134 return implicitCastTo(result
, sc
, t
);
137 if (t
.ty
!= Terror
&& e
.type
.ty
!= Terror
)
141 error(e
.loc
, "forward reference to type `%s`", t
.toChars());
145 //printf("type %p ty %d deco %p\n", type, type.ty, type.deco);
146 //type = type.typeSemantic(loc, sc);
147 //printf("type %s t %s\n", type.deco, t.deco);
148 auto ts
= toAutoQualChars(e
.type
, t
);
149 error(e
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
150 e
.toChars(), ts
[0], ts
[1]);
153 return ErrorExp
.get();
156 Expression
visitString(StringExp e
)
158 //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
159 auto result
= visit(e
);
160 if (auto se
= result
.isStringExp())
162 // Retain polysemous nature if it started out that way
163 se
.committed
= e
.committed
;
168 Expression
visitError(ErrorExp e
)
173 Expression
visitFunc(FuncExp e
)
175 //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
177 if (e
.matchType(t
, sc
, &fe
, global
.errorSink
) > MATCH
.nomatch
)
184 Expression
visitArrayLiteral(ArrayLiteralExp e
)
186 auto result
= visit(e
);
188 Type tb
= result
.type
.toBasetype();
189 if (auto ta
= tb
.isTypeDArray())
190 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
191 semanticTypeInfo(sc
, ta
.next
);
195 Expression
visitSlice(SliceExp e
)
197 auto result
= visit(e
);
199 if (auto se
= result
.isSliceExp())
200 if (auto ale
= se
.e1
.isArrayLiteralExp())
202 Type tb
= t
.toBasetype();
203 Type tx
= (tb
.ty
== Tsarray
)
204 ? tb
.nextOf().sarrayOf(ale
.elements ? ale
.elements
.length
: 0)
205 : tb
.nextOf().arrayOf();
206 se
.e1
= ale
.implicitCastTo(sc
, tx
);
214 default : return visit (e
);
215 case EXP
.string_
: return visitString (e
.isStringExp());
216 case EXP
.error
: return visitError (e
.isErrorExp());
217 case EXP
.function_
: return visitFunc (e
.isFuncExp());
218 case EXP
.arrayLiteral
: return visitArrayLiteral(e
.isArrayLiteralExp());
219 case EXP
.slice
: return visitSlice (e
.isSliceExp());
224 * Checks whether or not an expression can be implicitly converted
227 * Unlike `implicitCastTo`, this routine does not perform the actual cast,
228 * but only checks up to what `MATCH` level the conversion would be possible.
231 * e = Expression that is to be casted
232 * t = Expected resulting type
235 * The `MATCH` level between `e.type` and `t`.
237 extern(C
++) MATCH
implicitConvTo(Expression e
, Type t
)
239 MATCH
visit(Expression e
)
243 printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
245 //static int nest; if (++nest == 10) assert(0);
246 if (t
== Type
.terror
)
247 return MATCH
.nomatch
;
250 error(e
.loc
, "`%s` is not an expression", e
.toChars());
251 e
.type
= Type
.terror
;
254 Expression ex
= e
.optimize(WANTvalue
);
255 if (ex
.type
.equals(t
))
261 //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars());
262 return ex
.implicitConvTo(t
);
265 MATCH match
= e
.type
.implicitConvTo(t
);
266 if (match
!= MATCH
.nomatch
)
271 /* See if we can do integral narrowing conversions
273 if (e
.type
.isintegral() && t
.isintegral() && e
.type
.isTypeBasic() && t
.isTypeBasic())
275 IntRange src
= getIntRange(e
);
276 IntRange target
= IntRange
.fromType(t
);
277 if (target
.contains(src
))
279 return MATCH
.convert
;
282 return MATCH
.nomatch
;
286 * Given expression e of type t, see if we can implicitly convert e
287 * to type tprime, where tprime is type t with mod bits added.
291 static MATCH
implicitMod(Expression e
, Type t
, MOD mod
)
294 if (t
.ty
== Tpointer
)
295 tprime
= t
.nextOf().castMod(mod
).pointerTo();
296 else if (t
.ty
== Tarray
)
297 tprime
= t
.nextOf().castMod(mod
).arrayOf();
298 else if (t
.ty
== Tsarray
)
299 tprime
= t
.nextOf().castMod(mod
).sarrayOf(t
.size() / t
.nextOf().size());
301 tprime
= t
.castMod(mod
);
303 return e
.implicitConvTo(tprime
);
306 static MATCH
implicitConvToAddMin(BinExp e
, Type t
)
308 /* Is this (ptr +- offset)? If so, then ask ptr
309 * if the conversion can be done.
310 * This is to support doing things like implicitly converting a mutable unique
311 * pointer to an immutable pointer.
314 Type tb
= t
.toBasetype();
315 Type typeb
= e
.type
.toBasetype();
317 if (typeb
.ty
!= Tpointer || tb
.ty
!= Tpointer
)
318 return MATCH
.nomatch
;
320 Type t1b
= e
.e1
.type
.toBasetype();
321 Type t2b
= e
.e2
.type
.toBasetype();
322 if (t1b
.ty
== Tpointer
&& t2b
.isintegral() && t1b
.equivalent(tb
))
326 MATCH m
= e
.e1
.implicitConvTo(t
);
327 return (m
> MATCH
.constant
) ? MATCH
.constant
: m
;
329 if (t2b
.ty
== Tpointer
&& t1b
.isintegral() && t2b
.equivalent(tb
))
332 MATCH m
= e
.e2
.implicitConvTo(t
);
333 return (m
> MATCH
.constant
) ? MATCH
.constant
: m
;
336 return MATCH
.nomatch
;
339 // Apply mod bits to each function parameter,
340 // and see if we can convert the function argument to the modded type
341 static bool parametersModMatch(Expressions
* args
, TypeFunction tf
, MOD mod
)
343 const size_t nparams
= tf
.parameterList
.length
;
344 const size_t j
= tf
.isDstyleVariadic(); // if TypeInfoArray was prepended
345 foreach (const i
; j
.. args
.length
)
347 Expression earg
= (*args
)[i
];
348 Type targ
= earg
.type
.toBasetype();
351 printf("[%d] earg: %s, targ: %s\n", cast(int)i
, earg
.toChars(), targ
.toChars());
355 Parameter fparam
= tf
.parameterList
[i
- j
];
357 return false; // not sure what to do with this
358 Type tparam
= fparam
.type
;
361 if (fparam
.isReference())
363 if (targ
.constConv(tparam
.castMod(mod
)) == MATCH
.nomatch
)
370 printf("[%d] earg: %s, targm: %s\n", cast(int)i
, earg
.toChars(), targ
.addMod(mod
).toChars());
372 if (implicitMod(earg
, targ
, mod
) == MATCH
.nomatch
)
378 MATCH
visitAdd(AddExp e
)
382 printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
384 auto result
= visit(e
);
385 if (result
== MATCH
.nomatch
)
386 result
= implicitConvToAddMin(e
, t
);
390 MATCH
visitMin(MinExp e
)
394 printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
396 auto result
= visit(e
);
397 if (result
== MATCH
.nomatch
)
398 result
= implicitConvToAddMin(e
, t
);
402 MATCH
visitInteger(IntegerExp e
)
406 printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
408 MATCH m
= e
.type
.implicitConvTo(t
);
409 if (m
>= MATCH
.constant
)
414 TY ty
= e
.type
.toBasetype().ty
;
415 TY toty
= t
.toBasetype().ty
;
418 if (m
== MATCH
.nomatch
&& t
.ty
== Tenum
)
419 return MATCH
.nomatch
;
421 if (auto tv
= t
.isTypeVector())
423 TypeBasic tb
= tv
.elementType();
425 return MATCH
.nomatch
;
449 // Only allow conversion if no change in value
450 immutable dinteger_t value
= e
.toInteger();
452 bool isLosslesslyConvertibleToFP(T
)()
454 if (e
.type
.isunsigned())
456 const f
= cast(T
) value
;
457 return cast(dinteger_t
) f
== value
;
460 const f
= cast(T
) cast(sinteger_t
) value
;
461 return cast(sinteger_t
) f
== cast(sinteger_t
) value
;
467 if ((value
& 1) != value
)
468 return MATCH
.nomatch
;
472 if (ty
== Tuns64
&& value
& ~0x7FU
)
473 return MATCH
.nomatch
;
474 else if (cast(byte)value
!= value
)
475 return MATCH
.nomatch
;
479 if ((oldty
== Twchar || oldty
== Tdchar
) && value
> 0x7F)
480 return MATCH
.nomatch
;
483 //printf("value = %llu %llu\n", cast(dinteger_t)cast(ubyte)value, value);
484 if (cast(ubyte)value
!= value
)
485 return MATCH
.nomatch
;
489 if (ty
== Tuns64
&& value
& ~0x7FFFU
)
490 return MATCH
.nomatch
;
491 else if (cast(short)value
!= value
)
492 return MATCH
.nomatch
;
496 if (oldty
== Tdchar
&& value
> 0xD7FF && value
< 0xE000)
497 return MATCH
.nomatch
;
500 if (cast(ushort)value
!= value
)
501 return MATCH
.nomatch
;
508 else if (ty
== Tuns64
&& value
& ~0x7FFFFFFFU
)
509 return MATCH
.nomatch
;
510 else if (cast(int)value
!= value
)
511 return MATCH
.nomatch
;
518 else if (cast(uint)value
!= value
)
519 return MATCH
.nomatch
;
523 if (value
> 0x10FFFFU
)
524 return MATCH
.nomatch
;
528 if (!isLosslesslyConvertibleToFP
!float)
529 return MATCH
.nomatch
;
533 if (!isLosslesslyConvertibleToFP
!double)
534 return MATCH
.nomatch
;
538 if (!isLosslesslyConvertibleToFP
!real_t
)
539 return MATCH
.nomatch
;
543 //printf("type = %s\n", type.toBasetype().toChars());
544 //printf("t = %s\n", t.toBasetype().toChars());
545 if (ty
== Tpointer
&& e
.type
.toBasetype().nextOf().ty
== t
.toBasetype().nextOf().ty
)
547 /* Allow things like:
548 * const char* P = cast(char *)3;
559 //printf("MATCH.convert\n");
560 return MATCH
.convert
;
563 MATCH
visitError(ErrorExp e
)
565 return MATCH
.nomatch
;
568 MATCH
visitNull(NullExp e
)
572 printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
574 if (e
.type
.equals(t
))
579 /* Allow implicit conversions from immutable to mutable|const,
580 * and mutable to immutable. It works because, after all, a null
581 * doesn't actually point to anything.
583 if (t
.equivalent(e
.type
))
585 return MATCH
.constant
;
591 MATCH
visitStructLiteral(StructLiteralExp e
)
595 printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
597 auto result
= visit(e
);
598 if (result
!= MATCH
.nomatch
)
600 if (e
.type
.ty
== t
.ty
&& e
.type
.isTypeStruct() && e
.type
.isTypeStruct().sym
== t
.isTypeStruct().sym
)
602 result
= MATCH
.constant
;
603 foreach (i
, el
; (*e
.elements
)[])
607 Type te
= e
.sd
.fields
[i
].type
.addMod(t
.mod
);
608 MATCH m2
= el
.implicitConvTo(te
);
609 //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2);
617 MATCH
visitString(StringExp e
)
621 printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e
.toChars(), e
.committed
, e
.type
.toChars(), t
.toChars());
623 if (!e
.committed
&& t
.ty
== Tpointer
&& t
.nextOf().ty
== Tvoid
)
624 return MATCH
.nomatch
;
626 if (!(e
.type
.ty
== Tsarray || e
.type
.ty
== Tarray || e
.type
.ty
== Tpointer
))
629 TY tyn
= e
.type
.nextOf().ty
;
637 if (e
.type
.ty
== Tsarray
)
639 TY tynto
= t
.nextOf().ty
;
642 if (e
.type
.isTypeSArray().dim
.toInteger() == t
.isTypeSArray().dim
.toInteger())
646 return MATCH
.nomatch
;
648 if (tynto
.isSomeChar
)
650 if (e
.committed
&& tynto
!= tyn
)
651 return MATCH
.nomatch
;
652 size_t fromlen
= e
.numberOfCodeUnits(tynto
);
653 size_t tolen
= cast(size_t
)t
.isTypeSArray().dim
.toInteger();
655 return MATCH
.nomatch
;
656 if (tolen
!= fromlen
)
658 // implicit length extending
659 return MATCH
.convert
;
662 if (!e
.committed
&& tynto
.isSomeChar
)
667 else if (e
.type
.ty
== Tarray
)
669 TY tynto
= t
.nextOf().ty
;
670 if (tynto
.isSomeChar
)
672 if (e
.committed
&& tynto
!= tyn
)
673 return MATCH
.nomatch
;
674 size_t fromlen
= e
.numberOfCodeUnits(tynto
);
675 size_t tolen
= cast(size_t
)t
.isTypeSArray().dim
.toInteger();
677 return MATCH
.nomatch
;
678 if (tolen
!= fromlen
)
680 // implicit length extending
681 return MATCH
.convert
;
688 if (!e
.committed
&& tynto
.isSomeChar
)
693 goto case; /+ fall through +/
696 Type tn
= t
.nextOf();
697 MATCH m
= MATCH
.exact
;
698 if (e
.type
.nextOf().mod
!= tn
.mod
)
700 // https://issues.dlang.org/show_bug.cgi?id=16183
701 if (!tn
.isConst() && !tn
.isImmutable())
702 return MATCH
.nomatch
;
710 if (e
.postfix
== 'w' || e
.postfix
== 'd')
714 if (e
.postfix
!= 'w')
718 if (e
.postfix
!= 'd')
730 if (tn
.isTypeEnum().sym
.isSpecial())
732 /* Allow string literal -> const(wchar_t)[]
734 if (TypeBasic tob
= tn
.toBasetype().isTypeBasic())
735 return tn
.implicitConvTo(tob
);
751 MATCH
visitArrayLiteral(ArrayLiteralExp e
)
755 printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
757 Type tb
= t
.toBasetype();
758 Type typeb
= e
.type
.toBasetype();
760 auto result
= MATCH
.nomatch
;
761 if ((tb
.ty
== Tarray || tb
.ty
== Tsarray
) &&
762 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
))
764 result
= MATCH
.exact
;
765 Type typen
= typeb
.nextOf().toBasetype();
767 if (auto tsa
= tb
.isTypeSArray())
769 if (e
.elements
.length
!= tsa
.dim
.toInteger())
770 result
= MATCH
.nomatch
;
773 Type telement
= tb
.nextOf();
774 if (!e
.elements
.length
)
776 if (typen
.ty
!= Tvoid
)
777 result
= typen
.implicitConvTo(telement
);
783 MATCH m
= e
.basis
.implicitConvTo(telement
);
787 for (size_t i
= 0; i
< e
.elements
.length
; i
++)
789 Expression el
= (*e
.elements
)[i
];
790 if (result
== MATCH
.nomatch
)
794 MATCH m
= el
.implicitConvTo(telement
);
796 result
= m
; // remember worst match
801 result
= e
.type
.implicitConvTo(t
);
805 else if (tb
.ty
== Tvector
&& (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
))
807 result
= MATCH
.exact
;
808 // Convert array literal to vector type
809 TypeVector tv
= tb
.isTypeVector();
810 TypeSArray tbase
= tv
.basetype
.isTypeSArray();
812 const edim
= e
.elements
.length
;
813 const tbasedim
= tbase
.dim
.toInteger();
816 return MATCH
.nomatch
;
819 Type telement
= tv
.elementType();
822 Expression el
= typeb
.nextOf
.defaultInitLiteral(e
.loc
);
823 MATCH m
= el
.implicitConvTo(telement
);
825 result
= m
; // remember worst match
827 foreach (el
; (*e
.elements
)[])
829 MATCH m
= el
.implicitConvTo(telement
);
831 result
= m
; // remember worst match
832 if (result
== MATCH
.nomatch
)
833 break; // no need to check for worse
841 MATCH
visitAssocArrayLiteral(AssocArrayLiteralExp e
)
843 auto taa
= t
.toBasetype().isTypeAArray();
844 Type typeb
= e
.type
.toBasetype();
846 if (!(taa
&& typeb
.ty
== Taarray
))
849 auto result
= MATCH
.exact
;
850 foreach (i
, el
; (*e
.keys
)[])
852 MATCH m
= el
.implicitConvTo(taa
.index
);
854 result
= m
; // remember worst match
855 if (result
== MATCH
.nomatch
)
856 break; // no need to check for worse
858 m
= el
.implicitConvTo(taa
.nextOf());
860 result
= m
; // remember worst match
861 if (result
== MATCH
.nomatch
)
862 break; // no need to check for worse
867 MATCH
visitCall(CallExp e
)
872 printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
875 auto result
= visit(e
);
876 if (result
!= MATCH
.nomatch
)
879 /* Allow the result of strongly pure functions to
880 * convert to immutable
883 (!global
.params
.fixImmutableConv || e
.f
.isPure() >= PURE
.const_
) &&
884 e
.f
.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive.
887 result
= e
.type
.immutableOf().implicitConvTo(t
);
888 if (result
> MATCH
.constant
) // Match level is MATCH.constant at best.
889 result
= MATCH
.constant
;
893 /* Conversion is 'const' conversion if:
894 * 1. function is pure (weakly pure is ok)
895 * 2. implicit conversion only fails because of mod bits
896 * 3. each function parameter can be implicitly converted to the mod bits
898 auto tf
= (e
.f ? e
.f
.type
: e
.e1
.type
).toBasetype().isTypeFunction();
902 if (tf
.purity
== PURE
.impure
)
904 if (e
.f
&& e
.f
.isNested())
907 /* See if fail only because of mod bits.
909 * https://issues.dlang.org/show_bug.cgi?id=14155
910 * All pure functions can access global immutable data.
911 * So the returned pointer may refer an immutable global data,
912 * and then the returned pointer that points non-mutable object
913 * cannot be unique pointer.
917 * static this() { g = 1; }
918 * const(int*) foo() pure { return &g; }
920 * immutable(int*) ip = foo(); // OK
921 * int* mp = foo(); // should be disallowed
924 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
)
928 // Allow a conversion to immutable type, or
929 // conversions of mutable types between thread-local and shared.
931 /* Get mod bits of what we're converting to
933 Type tb
= t
.toBasetype();
940 if (Type ti
= getIndirection(t
))
945 printf("mod = x%x\n", mod
);
947 if (mod
& MODFlags
.wild
)
948 return result
; // not sure what to do with this
950 /* Apply mod bits to each function parameter,
951 * and see if we can convert the function argument to the modded type
953 if (auto dve
= e
.e1
.isDotVarExp())
955 /* Treat 'this' as just another function argument
957 Type targ
= dve
.e1
.type
;
958 if (targ
.constConv(targ
.castMod(mod
)) == MATCH
.nomatch
)
962 if (!parametersModMatch(e
.arguments
, tf
, mod
))
967 return MATCH
.constant
;
970 MATCH
visitAddr(AddrExp e
)
974 printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
976 auto result
= e
.type
.implicitConvTo(t
);
977 //printf("\tresult = %d\n", result);
979 if (result
!= MATCH
.nomatch
)
982 Type tb
= t
.toBasetype();
983 Type typeb
= e
.type
.toBasetype();
985 // Look for pointers to functions where the functions are overloaded.
986 if (e
.e1
.op
== EXP
.overloadSet
&&
987 (tb
.ty
== Tpointer || tb
.ty
== Tdelegate
) && tb
.nextOf().ty
== Tfunction
)
989 OverExp eo
= e
.e1
.isOverExp();
990 FuncDeclaration f
= null;
991 foreach (s
; eo
.vars
.a
[])
993 FuncDeclaration f2
= s
.isFuncDeclaration();
995 if (f2
.overloadExactMatch(tb
.nextOf()))
999 /* Error if match in more than one overload set,
1000 * even if one is a 'better' match than the other.
1002 ScopeDsymbol
.multiplyDefined(e
.loc
, f
, f2
);
1006 result
= MATCH
.exact
;
1011 if (e
.e1
.op
== EXP
.variable
&&
1012 typeb
.ty
== Tpointer
&& typeb
.nextOf().ty
== Tfunction
&&
1013 tb
.ty
== Tpointer
&& tb
.nextOf().ty
== Tfunction
)
1015 /* I don't think this can ever happen -
1016 * it should have been
1017 * converted to a SymOffExp.
1022 //printf("\tresult = %d\n", result);
1026 MATCH
visitSymOff(SymOffExp e
)
1030 printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
1032 auto result
= e
.type
.implicitConvTo(t
);
1033 //printf("\tresult = %d\n", result);
1034 if (result
!= MATCH
.nomatch
)
1037 Type tb
= t
.toBasetype();
1038 Type typeb
= e
.type
.toBasetype();
1040 // Look for pointers to functions where the functions are overloaded.
1041 if (typeb
.ty
== Tpointer
&& typeb
.nextOf().ty
== Tfunction
&&
1042 (tb
.ty
== Tpointer || tb
.ty
== Tdelegate
) && tb
.nextOf().ty
== Tfunction
)
1044 if (FuncDeclaration f
= e
.var
.isFuncDeclaration())
1046 f
= f
.overloadExactMatch(tb
.nextOf());
1049 if ((tb
.ty
== Tdelegate
&& (f
.needThis() || f
.isNested())) ||
1050 (tb
.ty
== Tpointer
&& !(f
.needThis() || f
.isNested())))
1052 result
= MATCH
.exact
;
1057 //printf("\tresult = %d\n", result);
1061 MATCH
visitDelegate(DelegateExp e
)
1065 printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
1067 auto result
= e
.type
.implicitConvTo(t
);
1068 if (result
!= MATCH
.nomatch
)
1071 Type tb
= t
.toBasetype();
1072 Type typeb
= e
.type
.toBasetype();
1074 // Look for pointers to functions where the functions are overloaded.
1075 if (typeb
.ty
== Tdelegate
&& tb
.ty
== Tdelegate
)
1077 if (e
.func
&& e
.func
.overloadExactMatch(tb
.nextOf()))
1078 result
= MATCH
.exact
;
1083 MATCH
visitFunc(FuncExp e
)
1085 //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
1086 MATCH m
= e
.matchType(t
, null, null, global
.errorSinkNull
);
1087 if (m
> MATCH
.nomatch
)
1094 MATCH
visitAnd(AndExp e
)
1096 auto result
= visit(e
);
1097 if (result
!= MATCH
.nomatch
)
1100 MATCH m1
= e
.e1
.implicitConvTo(t
);
1101 MATCH m2
= e
.e2
.implicitConvTo(t
);
1103 // Pick the worst match
1104 return (m1
< m2
) ? m1
: m2
;
1107 MATCH
visitOr(OrExp e
)
1109 auto result
= visit(e
);
1110 if (result
!= MATCH
.nomatch
)
1113 MATCH m1
= e
.e1
.implicitConvTo(t
);
1114 MATCH m2
= e
.e2
.implicitConvTo(t
);
1116 // Pick the worst match
1117 return (m1
< m2
) ? m1
: m2
;
1120 MATCH
visitXor(XorExp e
)
1122 auto result
= visit(e
);
1123 if (result
!= MATCH
.nomatch
)
1126 MATCH m1
= e
.e1
.implicitConvTo(t
);
1127 MATCH m2
= e
.e2
.implicitConvTo(t
);
1129 // Pick the worst match
1130 return (m1
< m2
) ? m1
: m2
;
1133 MATCH
visitCond(CondExp e
)
1135 e
.econd
= e
.econd
.optimize(WANTvalue
);
1136 const opt
= e
.econd
.toBool();
1137 if (opt
.isPresent())
1139 auto result
= visit(e
);
1140 if (result
!= MATCH
.nomatch
)
1144 MATCH m1
= e
.e1
.implicitConvTo(t
);
1145 MATCH m2
= e
.e2
.implicitConvTo(t
);
1146 //printf("CondExp: m1 %d m2 %d\n", m1, m2);
1148 // Pick the worst match
1149 return (m1
< m2
) ? m1
: m2
;
1152 MATCH
visitComma(CommaExp e
)
1154 return e
.e2
.implicitConvTo(t
);
1157 MATCH
visitCast(CastExp e
)
1161 printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
1163 auto result
= e
.type
.implicitConvTo(t
);
1164 if (result
!= MATCH
.nomatch
)
1167 if (t
.isintegral() && e
.e1
.type
.isintegral() && e
.e1
.implicitConvTo(t
) != MATCH
.nomatch
)
1168 result
= MATCH
.convert
;
1174 MATCH
visitNew(NewExp e
)
1178 printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
1180 auto result
= visit(e
);
1181 if (result
!= MATCH
.nomatch
)
1184 /* Calling new() is like calling a pure function. We can implicitly convert the
1185 * return from new() to t using the same algorithm as in CallExp, with the function
1186 * 'arguments' being:
1190 * 'member' need to be pure.
1193 /* See if fail only because of mod bits
1195 if (e
.type
.immutableOf().implicitConvTo(t
.immutableOf()) == MATCH
.nomatch
)
1196 return MATCH
.nomatch
;
1198 /* Get mod bits of what we're converting to
1200 Type tb
= t
.toBasetype();
1202 if (Type ti
= getIndirection(t
))
1206 printf("mod = x%x\n", mod
);
1208 if (mod
& MODFlags
.wild
)
1209 return MATCH
.nomatch
; // not sure what to do with this
1211 /* Apply mod bits to each argument,
1212 * and see if we can convert the argument to the modded type
1217 /* Treat 'this' as just another function argument
1219 Type targ
= e
.thisexp
.type
;
1220 if (targ
.constConv(targ
.castMod(mod
)) == MATCH
.nomatch
)
1221 return MATCH
.nomatch
;
1224 /* Check call to 'member'
1228 FuncDeclaration fd
= e
.member
;
1229 if (fd
.errors || fd
.type
.ty
!= Tfunction
)
1230 return MATCH
.nomatch
; // error
1231 TypeFunction tf
= fd
.type
.isTypeFunction();
1232 if (tf
.purity
== PURE
.impure
)
1233 return MATCH
.nomatch
; // impure
1235 // Allow a conversion to immutable type, or
1236 // conversions of mutable types between thread-local and shared.
1237 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
)
1239 return MATCH
.nomatch
;
1242 if (!parametersModMatch(e
.arguments
, tf
, mod
))
1244 return MATCH
.nomatch
;
1248 /* If no 'member', then construction is by simple assignment,
1249 * and just straight check 'arguments'
1251 if (!e
.member
&& e
.arguments
)
1253 for (size_t i
= 0; i
< e
.arguments
.length
; ++i
)
1255 Expression earg
= (*e
.arguments
)[i
];
1256 if (!earg
) // https://issues.dlang.org/show_bug.cgi?id=14853
1257 // if it's on overlapped field
1259 Type targ
= earg
.type
.toBasetype();
1262 printf("[%d] earg: %s, targ: %s\n", cast(int)i
, earg
.toChars(), targ
.toChars());
1263 printf("[%d] earg: %s, targm: %s\n", cast(int)i
, earg
.toChars(), targ
.addMod(mod
).toChars());
1265 if (implicitMod(earg
, targ
, mod
) == MATCH
.nomatch
)
1266 return MATCH
.nomatch
;
1270 /* Consider the .init expression as an argument
1272 Type ntb
= e
.newtype
.toBasetype();
1273 if (ntb
.ty
== Tarray
)
1274 ntb
= ntb
.nextOf().toBasetype();
1275 if (auto ts
= ntb
.isTypeStruct())
1277 // Don't allow nested structs - uplevel reference may not be convertible
1278 StructDeclaration sd
= ts
.sym
;
1279 sd
.size(e
.loc
); // resolve any forward references
1281 return MATCH
.nomatch
;
1283 if (ntb
.isZeroInit(e
.loc
))
1285 /* Zeros are implicitly convertible, except for special cases.
1287 if (auto tc
= ntb
.isTypeClass())
1289 /* With new() must look at the class instance initializer.
1291 ClassDeclaration cd
= tc
.sym
;
1293 cd
.size(e
.loc
); // resolve any forward references
1296 return MATCH
.nomatch
; // uplevel reference may not be convertible
1298 assert(!cd
.isInterfaceDeclaration());
1302 extern (C
++) static bool convertible(Expression e
, ClassDeclaration cd
, MOD mod
)
1304 for (size_t i
= 0; i
< cd
.fields
.length
; i
++)
1306 VarDeclaration v
= cd
.fields
[i
];
1307 Initializer _init
= v
._init
;
1310 if (_init
.isVoidInitializer())
1313 else if (ExpInitializer ei
= _init
.isExpInitializer())
1315 // https://issues.dlang.org/show_bug.cgi?id=21319
1316 // This is to prevent re-analyzing the same expression
1317 // over and over again.
1320 Type tb
= v
.type
.toBasetype();
1321 if (implicitMod(ei
.exp
, tb
, mod
) == MATCH
.nomatch
)
1326 /* Enhancement: handle StructInitializer and ArrayInitializer
1331 else if (!v
.type
.isZeroInit(e
.loc
))
1334 return cd
.baseClass ?
convertible(e
, cd
.baseClass
, mod
) : true;
1338 if (!ClassCheck
.convertible(e
, cd
, mod
))
1339 return MATCH
.nomatch
;
1344 Expression earg
= e
.newtype
.defaultInitLiteral(e
.loc
);
1345 Type targ
= e
.newtype
.toBasetype();
1347 if (implicitMod(earg
, targ
, mod
) == MATCH
.nomatch
)
1348 return MATCH
.nomatch
;
1353 return MATCH
.constant
;
1356 MATCH
visitSlice(SliceExp e
)
1358 //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars());
1359 auto result
= visit(e
);
1360 if (result
!= MATCH
.nomatch
)
1363 Type tb
= t
.toBasetype();
1364 Type typeb
= e
.type
.toBasetype();
1366 if (tb
.ty
== Tsarray
&& typeb
.ty
== Tarray
)
1368 typeb
= toStaticArrayType(e
);
1371 // Try: T[] -> T[dim]
1372 // (Slice with compile-time known boundaries to static array)
1373 result
= typeb
.implicitConvTo(t
);
1374 if (result
> MATCH
.convert
)
1375 result
= MATCH
.convert
; // match with implicit conversion at most
1380 /* If the only reason it won't convert is because of the mod bits,
1381 * then test for conversion by seeing if e1 can be converted with those
1384 Type t1b
= e
.e1
.type
.toBasetype();
1385 if (tb
.ty
== Tarray
&& typeb
.equivalent(tb
))
1387 Type tbn
= tb
.nextOf();
1390 /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1
1391 * is equivalent with the uniqueness of the referred data. And in here
1392 * we can have arbitrary typed reference for that.
1394 if (t1b
.ty
== Tarray
)
1396 if (t1b
.ty
== Tpointer
)
1397 tx
= tbn
.pointerTo();
1399 /* If e.e1 is static array, at least it should be an rvalue.
1400 * If not, e.e1 is a reference, and its uniqueness does not link
1401 * to the uniqueness of the referred data.
1403 if (t1b
.ty
== Tsarray
&& !e
.e1
.isLvalue())
1404 tx
= tbn
.sarrayOf(t1b
.size() / tbn
.size());
1408 result
= e
.e1
.implicitConvTo(tx
);
1409 if (result
> MATCH
.constant
) // Match level is MATCH.constant at best.
1410 result
= MATCH
.constant
;
1414 // Enhancement 10724
1415 if (tb
.ty
== Tpointer
&& e
.e1
.op
== EXP
.string_
)
1416 result
= e
.e1
.implicitConvTo(t
);
1420 MATCH
visitTuple(TupleExp e
)
1422 auto result
= e
.type
.implicitConvTo(t
);
1423 if (result
!= MATCH
.nomatch
)
1426 /* If target type is a tuple of same length, test conversion of
1427 * each expression to the corresponding type in the tuple.
1429 TypeTuple totuple
= t
.isTypeTuple();
1430 if (totuple
&& e
.exps
.length
== totuple
.arguments
.length
)
1432 result
= MATCH
.exact
;
1433 foreach (i
, ex
; *e
.exps
)
1435 auto to
= (*totuple
.arguments
)[i
].type
;
1436 MATCH mi
= ex
.implicitConvTo(to
);
1446 default : return visit(e
);
1447 case EXP
.add : return visitAdd(e
.isAddExp());
1448 case EXP
.min
: return visitMin(e
.isMinExp());
1449 case EXP
.int64
: return visitInteger(e
.isIntegerExp());
1450 case EXP
.error
: return visitError(e
.isErrorExp());
1451 case EXP
.null_
: return visitNull(e
.isNullExp());
1452 case EXP
.structLiteral
: return visitStructLiteral(e
.isStructLiteralExp());
1453 case EXP
.string_
: return visitString(e
.isStringExp());
1454 case EXP
.arrayLiteral
: return visitArrayLiteral(e
.isArrayLiteralExp());
1455 case EXP
.assocArrayLiteral
: return visitAssocArrayLiteral(e
.isAssocArrayLiteralExp());
1456 case EXP
.call : return visitCall(e
.isCallExp());
1457 case EXP
.address
: return visitAddr(e
.isAddrExp());
1458 case EXP
.symbolOffset
: return visitSymOff(e
.isSymOffExp());
1459 case EXP
.delegate_
: return visitDelegate(e
.isDelegateExp());
1460 case EXP
.function_
: return visitFunc(e
.isFuncExp());
1461 case EXP
.and : return visitAnd(e
.isAndExp());
1462 case EXP
.or : return visitOr(e
.isOrExp());
1463 case EXP
.xor : return visitXor(e
.isXorExp());
1464 case EXP
.question
: return visitCond(e
.isCondExp());
1465 case EXP
.comma
: return visitComma(e
.isCommaExp());
1466 case EXP
.cast_
: return visitCast(e
.isCastExp());
1467 case EXP
.new_
: return visitNew(e
.isNewExp());
1468 case EXP
.slice
: return visitSlice(e
.isSliceExp());
1469 case EXP
.tuple
: return visitTuple(e
.isTupleExp());
1474 * Same as implicitConvTo(); except follow C11 rules, which are quite a bit
1475 * more permissive than D.
1476 * C11 6.3 and 6.5.16.1
1478 * e = Expression that is to be casted
1479 * t = Expected resulting type
1481 * The `MATCH` level between `e.type` and `t`.
1483 MATCH
cimplicitConvTo(Expression e
, Type t
)
1485 Type tb
= t
.toBasetype();
1486 Type typeb
= e
.type
.toBasetype();
1488 if (tb
.equals(typeb
))
1490 if ((typeb
.isintegral() || typeb
.isfloating()) &&
1491 (tb
.isintegral() || tb
.isfloating()))
1492 return MATCH
.convert
;
1493 if (tb
.ty
== Tpointer
&& typeb
.isintegral()) // C11 6.3.2.3-5
1494 return MATCH
.convert
;
1495 if (tb
.isintegral() && typeb
.ty
== Tpointer
) // C11 6.3.2.3-6
1496 return MATCH
.convert
;
1497 if (tb
.ty
== Tpointer
&& typeb
.ty
== Tpointer
) // C11 6.3.2.3-7
1498 return MATCH
.convert
;
1500 return implicitConvTo(e
, t
);
1503 /*****************************************
1505 Type
toStaticArrayType(SliceExp e
)
1509 // For the following code to work, e should be optimized beforehand.
1510 // (eg. $ in lwr and upr should be already resolved, if possible)
1511 Expression lwr
= e
.lwr
.optimize(WANTvalue
);
1512 Expression upr
= e
.upr
.optimize(WANTvalue
);
1513 if (lwr
.isConst() && upr
.isConst())
1515 size_t len
= cast(size_t
)(upr
.toUInteger() - lwr
.toUInteger());
1516 return e
.type
.toBasetype().nextOf().sarrayOf(len
);
1521 Type t1b
= e
.e1
.type
.toBasetype();
1522 if (t1b
.ty
== Tsarray
)
1528 /**************************************
1529 * Do an explicit cast.
1530 * Assume that the expression `e` does not have any indirections.
1531 * (Parameter 'att' is used to stop 'alias this' recursion)
1533 Expression
castTo(Expression e
, Scope
* sc
, Type t
, Type att
= null)
1535 //printf("castTo(e: %s from: %s to: %s\n", e.toChars(), e.type.toChars(), t.toChars());
1537 Expression
visit(Expression e
)
1539 //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars());
1542 printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
1544 if (e
.type
.equals(t
))
1548 if (e
.type
.isTypeNoreturn() && e
.op
!= EXP
.type
)
1550 return specialNoreturnCast(e
, t
);
1552 if (auto ve
= e
.isVarExp())
1554 VarDeclaration v
= ve
.var
.isVarDeclaration();
1555 if (v
&& v
.storage_class
& STC
.manifest
)
1557 auto result
= e
.ctfeInterpret();
1558 /* https://issues.dlang.org/show_bug.cgi?id=18236
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
1565 return result
.castTo(sc
, t
);
1569 Type tob
= t
.toBasetype();
1570 Type t1b
= e
.type
.toBasetype();
1571 if (tob
.equals(t1b
))
1573 auto result
= e
.copy(); // because of COW for assignment to e.type
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().
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
);
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
);
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
);
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
);
1599 // Try casting the alias this member.
1600 // Return the expression if it succeeds, null otherwise.
1601 Expression
tryAliasThisCast()
1603 if (isRecursiveAliasThis(att
, t1b
))
1606 /* Forward the cast to our alias this member, rewrite to:
1607 * cast(to)e1.aliasthis
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
;
1616 if (AggregateDeclaration t1ad
= isAggregate(t1b
))
1618 AggregateDeclaration toad
= isAggregate(tob
);
1619 if (t1ad
!= toad
&& t1ad
.aliasthis
)
1621 if (t1b
.ty
== Tclass
&& tob
.ty
== Tclass
)
1623 ClassDeclaration t1cd
= t1b
.isClassHandle();
1624 ClassDeclaration tocd
= tob
.isClassHandle();
1626 if (tocd
.isBaseOf(t1cd
, &offset
))
1629 hasAliasThis
= true;
1632 else if (tob
.ty
== Tvector
&& t1b
.ty
!= Tvector
)
1634 if (t1b
.ty
== Tsarray
)
1636 // Casting static array to vector with same size, e.g. `cast(int4) int[4]`
1637 if (t1b
.size(e
.loc
) != tob
.size(e
.loc
))
1639 return new VectorExp(e
.loc
, e
, tob
).expressionSemantic(sc
);
1641 //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
1642 TypeVector tv
= tob
.isTypeVector();
1643 Expression result
= new CastExp(e
.loc
, e
, tv
.elementType());
1644 result
= new VectorExp(e
.loc
, result
, tob
);
1645 result
= result
.expressionSemantic(sc
);
1648 else if (tob
.ty
!= Tvector
&& t1b
.ty
== Tvector
)
1650 // T[n] <-- __vector(U[m])
1651 if (tob
.ty
== Tsarray
)
1653 if (t1b
.size(e
.loc
) == tob
.size(e
.loc
))
1658 else if (t1b
.implicitConvTo(tob
) == MATCH
.constant
&& t
.equals(e
.type
.constOf()))
1660 auto result
= e
.copy();
1665 // arithmetic values vs. other arithmetic values
1666 // arithmetic values vs. T*
1667 if (tob_isA
&& (t1b_isA || t1b
.ty
== Tpointer
) || t1b_isA
&& (tob_isA || tob
.ty
== Tpointer
))
1672 // arithmetic values vs. references or fat values
1673 if (tob_isA
&& (t1b_isR || t1b_isFV
) || t1b_isA
&& (tob_isR || tob_isFV
))
1678 // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
1679 if (tob_isFV
&& t1b_isFV
)
1683 auto result
= tryAliasThisCast();
1688 if (t1b
.size(e
.loc
) == tob
.size(e
.loc
))
1691 auto ts
= toAutoQualChars(e
.type
, t
);
1692 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s` because of different sizes",
1693 e
.toChars(), ts
[0], ts
[1]);
1694 return ErrorExp
.get();
1697 // Fat values vs. null or references
1698 if (tob_isFV
&& (t1b
.ty
== Tnull || t1b_isR
) || t1b_isFV
&& (tob
.ty
== Tnull || tob_isR
))
1700 if (tob
.ty
== Tpointer
&& t1b
.ty
== Tsarray
)
1703 // cast(U*)sa; // ==> cast(U*)sa.ptr;
1704 return new AddrExp(e
.loc
, e
, t
);
1706 if (tob
.ty
== Tarray
&& t1b
.ty
== Tsarray
)
1709 // cast(U[])sa; // ==> cast(U[])sa[];
1710 const fsize
= t1b
.nextOf().size();
1711 const tsize
= tob
.nextOf().size();
1712 if (fsize
== SIZE_INVALID || tsize
== SIZE_INVALID
)
1714 return ErrorExp
.get();
1718 const dim
= t1b
.isTypeSArray().dim
.toInteger();
1719 if (tsize
== 0 ||
(dim
* fsize
) % tsize
!= 0)
1721 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
1722 e
.toChars(), e
.type
.toChars(), t
.toChars());
1723 return ErrorExp
.get();
1731 /* For references, any reinterpret casts are allowed to same 'ty' type.
1733 * R1 function(P1) to R2 function(P2)
1734 * R1 delegate(P1) to R2 delegate(P2)
1737 * class/interface A to B (will be a dynamic cast if possible)
1739 if (tob
.ty
== t1b
.ty
&& tob_isR
&& t1b_isR
)
1742 // typeof(null) <-- non-null references or values
1743 if (tob
.ty
== Tnull
&& t1b
.ty
!= Tnull
)
1744 goto Lfail
; // https://issues.dlang.org/show_bug.cgi?id=14629
1745 // typeof(null) --> non-null references or arithmetic values
1746 if (t1b
.ty
== Tnull
&& tob
.ty
!= Tnull
)
1749 // Check size mismatch of references.
1750 // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
1751 if (tob_isFR
&& t1b_isR || t1b_isFR
&& tob_isR
)
1753 if (tob
.ty
== Tpointer
&& t1b
.ty
== Tarray
)
1756 // cast(U*)da; // ==> cast(U*)da.ptr;
1759 if (tob
.ty
== Tpointer
&& t1b
.ty
== Tdelegate
)
1761 // void delegate() dg;
1762 // cast(U*)dg; // ==> cast(U*)dg.ptr;
1763 // Note that it happens even when U is a Tfunction!
1764 deprecation(e
.loc
, "casting from %s to %s is deprecated", e
.type
.toChars(), t
.toChars());
1770 if (t1b
.ty
== Tvoid
&& tob
.ty
!= Tvoid
)
1773 /* if the cast cannot be performed, maybe there is an alias
1774 * this that can be used for casting.
1778 auto result
= tryAliasThisCast();
1782 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s`", e
.toChars(), e
.type
.toChars(), t
.toChars());
1783 return ErrorExp
.get();
1787 auto result
= new CastExp(e
.loc
, e
, t
);
1788 result
.type
= t
; // Don't call semantic()
1789 //printf("Returning: %s\n", result.toChars());
1793 Expression
visitError(ErrorExp e
)
1798 Expression
visitReal(RealExp e
)
1800 if (!e
.type
.equals(t
))
1802 if ((e
.type
.isreal() && t
.isreal()) ||
(e
.type
.isimaginary() && t
.isimaginary()))
1804 auto result
= e
.copy();
1814 Expression
visitComplex(ComplexExp e
)
1816 if (!e
.type
.equals(t
))
1818 if (e
.type
.iscomplex() && t
.iscomplex())
1820 auto result
= e
.copy();
1830 Expression
visitStructLiteral(StructLiteralExp e
)
1832 auto result
= visit(e
);
1833 if (auto sle
= result
.isStructLiteralExp())
1834 sle
.stype
= t
; // commit type
1838 Expression
visitString(StringExp e
)
1840 /* This follows copy-on-write; any changes to 'this'
1841 * will result in a copy.
1842 * The this.string member is considered immutable.
1846 //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
1848 if (!e
.committed
&& t
.ty
== Tpointer
&& t
.nextOf().ty
== Tvoid
&&
1849 (!sc ||
!(sc
.flags
& SCOPE
.Cfile
)))
1851 error(e
.loc
, "cannot convert string literal to `void*`");
1852 return ErrorExp
.get();
1859 auto result
= new CastExp(e
.loc
, se
, t
);
1860 result
.type
= t
; // so semantic() won't be run on e
1866 se
= e
.copy().isStringExp();
1867 se
.committed
= true;
1871 if (e
.type
.equals(t
))
1876 Type tb
= t
.toBasetype();
1877 Type typeb
= e
.type
.toBasetype();
1879 //printf("\ttype = %s\n", e.type.toChars());
1880 if (tb
.ty
== Tdelegate
&& typeb
.ty
!= Tdelegate
)
1885 if (typeb
.equals(tb
))
1889 se
= e
.copy().isStringExp();
1896 /* Handle reinterpret casts:
1897 * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
1898 * cast(wchar[2])"abcd"c --> [\u6261, \u6463]
1899 * cast(wchar[1])"abcd"c --> [\u6261]
1900 * cast(char[4])"a" --> ['a', 0, 0, 0]
1902 if (e
.committed
&& tb
.ty
== Tsarray
&& typeb
.ty
== Tarray
)
1904 se
= e
.copy().isStringExp();
1905 uinteger_t szx
= tb
.nextOf().size();
1907 se
.sz
= cast(ubyte)szx
;
1908 se
.len
= cast(size_t
)tb
.isTypeSArray().dim
.toInteger();
1909 se
.committed
= true;
1912 /* If larger than source, pad with zeros.
1914 const fullSize
= (se
.len
+ 1) * se
.sz
; // incl. terminating 0
1915 if (fullSize
> (e
.len
+ 1) * e
.sz
)
1917 void* s
= mem
.xmalloc(fullSize
);
1918 const srcSize
= e
.len
* e
.sz
;
1919 const data
= se
.peekData();
1920 memcpy(s
, data
.ptr
, srcSize
);
1921 memset(s
+ srcSize
, 0, fullSize
- srcSize
);
1922 se
.setData(s
, se
.len
, se
.sz
);
1927 if (tb
.ty
!= Tsarray
&& tb
.ty
!= Tarray
&& tb
.ty
!= Tpointer
)
1931 se
= e
.copy().isStringExp();
1936 if (typeb
.ty
!= Tsarray
&& typeb
.ty
!= Tarray
&& typeb
.ty
!= Tpointer
)
1940 se
= e
.copy().isStringExp();
1946 const nextSz
= typeb
.nextOf().size();
1947 if (nextSz
== SIZE_INVALID
)
1949 return ErrorExp
.get();
1951 if (nextSz
== tb
.nextOf().size())
1955 se
= e
.copy().isStringExp();
1958 if (tb
.ty
== Tsarray
)
1959 goto L2
; // handle possible change in static array dimension
1967 auto X(T
, U
)(T tf
, U tt
)
1969 return (cast(int)tf
* 256 + cast(int)tt
);
1975 int tfty
= typeb
.nextOf().toBasetype().ty
;
1976 int ttty
= tb
.nextOf().toBasetype().ty
;
1977 switch (X(tfty
, ttty
))
1979 case X(Tchar
, Tchar
):
1980 case X(Twchar
, Twchar
):
1981 case X(Tdchar
, Tdchar
):
1984 case X(Tchar
, Twchar
):
1985 for (size_t u
= 0; u
< e
.len
;)
1988 if (const s
= utf_decodeChar(se
.peekString(), u
, c
))
1989 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
1991 buffer
.writeUTF16(c
);
1993 newlen
= buffer
.length
/ 2;
1994 buffer
.writeUTF16(0);
1997 case X(Tchar
, Tdchar
):
1998 for (size_t u
= 0; u
< e
.len
;)
2001 if (const s
= utf_decodeChar(se
.peekString(), u
, c
))
2002 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
2009 case X(Twchar
, Tchar
):
2010 for (size_t u
= 0; u
< e
.len
;)
2013 if (const s
= utf_decodeWchar(se
.peekWstring(), u
, c
))
2014 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
2016 buffer
.writeUTF8(c
);
2018 newlen
= buffer
.length
;
2019 buffer
.writeUTF8(0);
2022 case X(Twchar
, Tdchar
):
2023 for (size_t u
= 0; u
< e
.len
;)
2026 if (const s
= utf_decodeWchar(se
.peekWstring(), u
, c
))
2027 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
2034 case X(Tdchar
, Tchar
):
2035 for (size_t u
= 0; u
< e
.len
; u
++)
2037 uint c
= se
.peekDstring()[u
];
2038 if (!utf_isValidDchar(c
))
2039 error(e
.loc
, "invalid UCS-32 char \\U%08x", c
);
2041 buffer
.writeUTF8(c
);
2044 newlen
= buffer
.length
;
2045 buffer
.writeUTF8(0);
2048 case X(Tdchar
, Twchar
):
2049 for (size_t u
= 0; u
< e
.len
; u
++)
2051 uint c
= se
.peekDstring()[u
];
2052 if (!utf_isValidDchar(c
))
2053 error(e
.loc
, "invalid UCS-32 char \\U%08x", c
);
2055 buffer
.writeUTF16(c
);
2058 newlen
= buffer
.length
/ 2;
2059 buffer
.writeUTF16(0);
2065 se
= e
.copy().isStringExp();
2070 uinteger_t szx
= tb
.nextOf().size();
2072 se
.setData(buffer
.extractSlice().ptr
, newlen
, cast(ubyte)szx
);
2077 assert(typeb
.nextOf().size() != tb
.nextOf().size());
2084 // See if need to truncate or extend the literal
2085 if (auto tsa
= tb
.isTypeSArray())
2087 size_t dim2
= cast(size_t
)tsa
.dim
.toInteger();
2088 //printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
2090 // Changing dimensions
2093 // Copy when changing the string literal
2094 const newsz
= se
.sz
;
2095 const d
= (dim2
< se
.len
) ? dim2
: se
.len
;
2096 void* s
= mem
.xmalloc((dim2
+ 1) * newsz
);
2097 memcpy(s
, se
.peekData().ptr
, d
* newsz
);
2098 // Extend with 0, add terminating 0
2099 memset(s
+ d
* newsz
, 0, (dim2
+ 1 - d
) * newsz
);
2100 se
.setData(s
, dim2
, newsz
);
2107 auto result
= new CastExp(e
.loc
, se
, t
);
2108 result
.type
= t
; // so semantic() won't be run on e
2112 Expression
visitAddr(AddrExp e
)
2116 printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2118 Type tb
= t
.toBasetype();
2119 Type typeb
= e
.type
.toBasetype();
2121 if (tb
.equals(typeb
))
2123 auto result
= e
.copy();
2128 // Look for pointers to functions where the functions are overloaded.
2129 if (e
.e1
.isOverExp() &&
2130 (tb
.ty
== Tpointer || tb
.ty
== Tdelegate
) && tb
.nextOf().ty
== Tfunction
)
2132 OverExp eo
= e
.e1
.isOverExp();
2133 FuncDeclaration f
= null;
2134 for (size_t i
= 0; i
< eo
.vars
.a
.length
; i
++)
2136 auto s
= eo
.vars
.a
[i
];
2137 auto f2
= s
.isFuncDeclaration();
2139 if (f2
.overloadExactMatch(tb
.nextOf()))
2143 /* Error if match in more than one overload set,
2144 * even if one is a 'better' match than the other.
2146 ScopeDsymbol
.multiplyDefined(e
.loc
, f
, f2
);
2155 auto se
= new SymOffExp(e
.loc
, f
, 0, false);
2156 auto se2
= se
.expressionSemantic(sc
);
2157 // Let SymOffExp::castTo() do the heavy lifting
2162 if (e
.e1
.isVarExp() &&
2163 typeb
.ty
== Tpointer
&& typeb
.nextOf().ty
== Tfunction
&&
2164 tb
.ty
== Tpointer
&& tb
.nextOf().ty
== Tfunction
)
2166 auto ve
= e
.e1
.isVarExp();
2167 auto f
= ve
.var
.isFuncDeclaration();
2170 assert(f
.isImportedSymbol());
2171 f
= f
.overloadExactMatch(tb
.nextOf());
2174 Expression result
= new VarExp(e
.loc
, f
, false);
2175 result
.type
= f
.type
;
2176 result
= new AddrExp(e
.loc
, result
, t
);
2182 if (auto f
= isFuncAddress(e
))
2184 if (f
.checkForwardRef(e
.loc
))
2186 return ErrorExp
.get();
2193 Expression
visitTuple(TupleExp e
)
2195 if (e
.type
.equals(t
))
2200 /* If target type is a tuple of same length, cast each expression to
2201 * the corresponding type in the tuple.
2204 if (auto tt
= t
.isTypeTuple())
2205 totuple
= e
.exps
.length
== tt
.arguments
.length ? tt
: null;
2207 TupleExp te
= e
.copy().isTupleExp();
2208 te
.e0
= e
.e0 ? e
.e0
.copy() : null;
2209 te
.exps
= e
.exps
.copy();
2210 for (size_t i
= 0; i
< te
.exps
.length
; i
++)
2212 Expression ex
= (*te
.exps
)[i
];
2213 ex
= ex
.castTo(sc
, totuple ?
(*totuple
.arguments
)[i
].type
: t
);
2220 /* Questionable behavior: In here, result.type is not set to t
2221 * if target type is not a tuple of same length.
2223 * TypeTuple!(int, int) values;
2224 * auto values2 = cast(long)values;
2225 * // typeof(values2) == TypeTuple!(int, int) !!
2227 * Only when the casted tuple is immediately expanded, it would work.
2228 * auto arr = [cast(long)values];
2229 * // typeof(arr) == long[]
2233 Expression
visitArrayLiteral(ArrayLiteralExp e
)
2237 printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2240 ArrayLiteralExp ae
= e
;
2242 Type tb
= t
.toBasetype();
2243 if (tb
.ty
== Tarray
)
2245 if (checkArrayLiteralEscape(sc
, ae
, false))
2247 return ErrorExp
.get();
2255 Type typeb
= e
.type
.toBasetype();
2257 if ((tb
.ty
== Tarray || tb
.ty
== Tsarray
) &&
2258 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
))
2260 if (tb
.nextOf().toBasetype().ty
== Tvoid
&& typeb
.nextOf().toBasetype().ty
!= Tvoid
)
2262 // Don't do anything to cast non-void[] to void[]
2264 else if (typeb
.ty
== Tsarray
&& typeb
.nextOf().toBasetype().ty
== Tvoid
)
2266 // Don't do anything for casting void[n] to others
2270 if (auto tsa
= tb
.isTypeSArray())
2272 if (e
.elements
.length
!= tsa
.dim
.toInteger())
2276 ae
= e
.copy().isArrayLiteralExp();
2278 ae
.basis
= e
.basis
.castTo(sc
, tb
.nextOf());
2279 ae
.elements
= e
.elements
.copy();
2280 for (size_t i
= 0; i
< e
.elements
.length
; i
++)
2282 Expression ex
= (*e
.elements
)[i
];
2285 ex
= ex
.castTo(sc
, tb
.nextOf());
2286 (*ae
.elements
)[i
] = ex
;
2292 else if (tb
.ty
== Tpointer
&& typeb
.ty
== Tsarray
)
2294 Type tp
= typeb
.nextOf().pointerTo();
2295 if (!tp
.equals(ae
.type
))
2297 ae
= e
.copy().isArrayLiteralExp();
2301 else if (tb
.ty
== Tvector
&& (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
))
2303 // Convert array literal to vector type
2304 TypeVector tv
= tb
.isTypeVector();
2305 TypeSArray tbase
= tv
.basetype
.isTypeSArray();
2306 assert(tbase
.ty
== Tsarray
);
2307 const edim
= e
.elements
.length
;
2308 const tbasedim
= tbase
.dim
.toInteger();
2309 if (edim
> tbasedim
)
2312 ae
= e
.copy().isArrayLiteralExp();
2313 ae
.type
= tbase
; // https://issues.dlang.org/show_bug.cgi?id=12642
2314 ae
.elements
= e
.elements
.copy();
2315 Type telement
= tv
.elementType();
2316 foreach (i
; 0 .. edim
)
2318 Expression ex
= (*e
.elements
)[i
];
2319 ex
= ex
.castTo(sc
, telement
);
2320 (*ae
.elements
)[i
] = ex
;
2322 // Fill in the rest with the default initializer
2323 ae
.elements
.setDim(cast(size_t
)tbasedim
);
2324 foreach (i
; edim
.. cast(size_t
)tbasedim
)
2326 Expression ex
= typeb
.nextOf
.defaultInitLiteral(e
.loc
);
2327 ex
= ex
.castTo(sc
, telement
);
2328 (*ae
.elements
)[i
] = ex
;
2330 Expression ev
= new VectorExp(e
.loc
, ae
, tb
);
2331 ev
= ev
.expressionSemantic(sc
);
2338 Expression
visitAssocArrayLiteral(AssocArrayLiteralExp e
)
2340 //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
2346 Type tb
= t
.toBasetype();
2347 Type typeb
= e
.type
.toBasetype();
2349 if (tb
.ty
== Taarray
&& typeb
.ty
== Taarray
&&
2350 tb
.nextOf().toBasetype().ty
!= Tvoid
)
2352 AssocArrayLiteralExp ae
= e
.copy().isAssocArrayLiteralExp();
2353 ae
.keys
= e
.keys
.copy();
2354 ae
.values
= e
.values
.copy();
2355 assert(e
.keys
.length
== e
.values
.length
);
2356 for (size_t i
= 0; i
< e
.keys
.length
; i
++)
2358 Expression ex
= (*e
.values
)[i
];
2359 ex
= ex
.castTo(sc
, tb
.nextOf());
2360 (*ae
.values
)[i
] = ex
;
2363 ex
= ex
.castTo(sc
, tb
.isTypeAArray().index
);
2372 Expression
visitSymOff(SymOffExp e
)
2376 printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2378 if (e
.type
== t
&& !e
.hasOverloads
)
2383 Type tb
= t
.toBasetype();
2384 Type typeb
= e
.type
.toBasetype();
2386 if (tb
.equals(typeb
))
2388 auto result
= e
.copy();
2390 result
.isSymOffExp().hasOverloads
= false;
2394 // Look for pointers to functions where the functions are overloaded.
2395 if (e
.hasOverloads
&&
2396 typeb
.ty
== Tpointer
&& typeb
.nextOf().ty
== Tfunction
&&
2397 (tb
.ty
== Tpointer || tb
.ty
== Tdelegate
) && tb
.nextOf().ty
== Tfunction
)
2399 FuncDeclaration f
= e
.var
.isFuncDeclaration();
2400 f
= f ? f
.overloadExactMatch(tb
.nextOf()) : null;
2404 if (tb
.ty
== Tdelegate
)
2406 if (f
.needThis() && hasThis(sc
))
2408 result
= new DelegateExp(e
.loc
, new ThisExp(e
.loc
), f
, false);
2409 result
= result
.expressionSemantic(sc
);
2411 else if (f
.needThis())
2413 error(e
.loc
, "no `this` to create delegate for `%s`", f
.toChars());
2414 return ErrorExp
.get();
2416 else if (f
.isNested())
2418 result
= new DelegateExp(e
.loc
, IntegerExp
.literal
!0, f
, false);
2419 result
= result
.expressionSemantic(sc
);
2423 error(e
.loc
, "cannot cast from function pointer to delegate");
2424 return ErrorExp
.get();
2429 result
= new SymOffExp(e
.loc
, f
, 0, false);
2437 if (auto f
= isFuncAddress(e
))
2439 if (f
.checkForwardRef(e
.loc
))
2441 return ErrorExp
.get();
2448 Expression
visitDelegate(DelegateExp e
)
2452 printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2454 static immutable msg
= "cannot form delegate due to covariant return type";
2456 Type tb
= t
.toBasetype();
2457 Type typeb
= e
.type
.toBasetype();
2459 if (tb
.equals(typeb
) && !e
.hasOverloads
)
2462 e
.func
.tookAddressOf
++;
2463 if (e
.func
.tintro
&& e
.func
.tintro
.nextOf().isBaseOf(e
.func
.type
.nextOf(), &offset
) && offset
)
2464 error(e
.loc
, "%s", msg
.ptr
);
2465 auto result
= e
.copy();
2470 // Look for delegates to functions where the functions are overloaded.
2471 if (typeb
.ty
== Tdelegate
&& tb
.ty
== Tdelegate
)
2475 auto f
= e
.func
.overloadExactMatch(tb
.nextOf());
2479 if (f
.tintro
&& f
.tintro
.nextOf().isBaseOf(f
.type
.nextOf(), &offset
) && offset
)
2480 error(e
.loc
, "%s", msg
.ptr
);
2481 if (f
!= e
.func
) // if address not already marked as taken
2483 auto result
= new DelegateExp(e
.loc
, e
.e1
, f
, false, e
.vthis2
);
2488 error(e
.loc
, "%s", msg
.ptr
);
2492 if (auto f
= isFuncAddress(e
))
2494 if (f
.checkForwardRef(e
.loc
))
2496 return ErrorExp
.get();
2503 Expression
visitFunc(FuncExp e
)
2505 //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars());
2507 if (e
.matchType(t
, sc
, &fe
, global
.errorSinkNull
) > MATCH
.nomatch
)
2514 Expression
visitCond(CondExp e
)
2516 if (!e
.type
.equals(t
))
2518 auto result
= new CondExp(e
.loc
, e
.econd
, e
.e1
.castTo(sc
, t
), e
.e2
.castTo(sc
, t
));
2525 Expression
visitComma(CommaExp e
)
2527 Expression e2c
= e
.e2
.castTo(sc
, t
);
2531 auto result
= new CommaExp(e
.loc
, e
.e1
, e2c
);
2532 result
.type
= e2c
.type
;
2542 Expression
visitSlice(SliceExp e
)
2544 //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars());
2546 Type tb
= t
.toBasetype();
2547 Type typeb
= e
.type
.toBasetype();
2549 if (e
.type
.equals(t
) || typeb
.ty
!= Tarray ||
2550 (tb
.ty
!= Tarray
&& tb
.ty
!= Tsarray
))
2555 if (tb
.ty
== Tarray
)
2557 if (typeb
.nextOf().equivalent(tb
.nextOf()))
2559 // T[] to const(T)[]
2560 auto result
= e
.copy();
2570 // Handle the cast from Tarray to Tsarray with CT-known slicing
2574 Type t
= toStaticArrayType(e
);
2575 tsa
= t ? t
.isTypeSArray() : null;
2578 if (tsa
&& tsa
.size(e
.loc
) == tb
.size(e
.loc
))
2580 /* Match if the sarray sizes are equal:
2581 * T[a .. b] to const(T)[b-a]
2582 * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
2584 * If a SliceExp has Tsarray, it will become lvalue.
2585 * That's handled in SliceExp::isLvalue and toLvalue
2587 auto result
= e
.copy();
2591 if (tsa
&& tsa
.dim
.equals(tb
.isTypeSArray().dim
))
2593 /* Match if the dimensions are equal
2594 * with the implicit conversion of e.e1:
2595 * cast(float[2]) [2.0, 1.0, 0.0][0..2];
2597 Type t1b
= e
.e1
.type
.toBasetype();
2598 if (t1b
.ty
== Tsarray
)
2599 t1b
= tb
.nextOf().sarrayOf(t1b
.isTypeSArray().dim
.toInteger());
2600 else if (t1b
.ty
== Tarray
)
2601 t1b
= tb
.nextOf().arrayOf();
2602 else if (t1b
.ty
== Tpointer
)
2603 t1b
= tb
.nextOf().pointerTo();
2606 if (e
.e1
.implicitConvTo(t1b
) > MATCH
.nomatch
)
2608 Expression e1x
= e
.e1
.implicitCastTo(sc
, t1b
);
2609 assert(e1x
.op
!= EXP
.error
);
2610 e
= e
.copy().isSliceExp();
2616 auto ts
= toAutoQualChars(tsa ? tsa
: e
.type
, t
);
2617 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s`",
2618 e
.toChars(), ts
[0], ts
[1]);
2619 return ErrorExp
.get();
2622 // Casting to noreturn isn't an actual cast
2623 // Rewrite cast(<qual> noreturn) <exp>
2624 // as <exp>, assert(false)
2625 if (t
.isTypeNoreturn())
2627 // Don't generate an unreachable assert(false) if e will abort
2628 if (e
.type
.isTypeNoreturn())
2630 // Paint e to accomodate for different type qualifiers
2635 auto ini
= t
.defaultInitLiteral(e
.loc
);
2636 return Expression
.combine(e
, ini
);
2641 default : return visit(e
);
2642 case EXP
.error
: return visitError(e
.isErrorExp());
2643 case EXP
.float64
: return visitReal(e
.isRealExp());
2644 case EXP
.complex80
: return visitComplex(e
.isComplexExp());
2645 case EXP
.structLiteral
: return visitStructLiteral(e
.isStructLiteralExp());
2646 case EXP
.string_
: return visitString(e
.isStringExp());
2647 case EXP
.address
: return visitAddr(e
.isAddrExp());
2648 case EXP
.tuple
: return visitTuple(e
.isTupleExp());
2649 case EXP
.arrayLiteral
: return visitArrayLiteral(e
.isArrayLiteralExp());
2650 case EXP
.assocArrayLiteral
: return visitAssocArrayLiteral(e
.isAssocArrayLiteralExp());
2651 case EXP
.symbolOffset
: return visitSymOff(e
.isSymOffExp());
2652 case EXP
.delegate_
: return visitDelegate(e
.isDelegateExp());
2653 case EXP
.function_
: return visitFunc(e
.isFuncExp());
2654 case EXP
.question
: return visitCond(e
.isCondExp());
2655 case EXP
.comma
: return visitComma(e
.isCommaExp());
2656 case EXP
.slice
: return visitSlice(e
.isSliceExp());
2660 /****************************************
2661 * Set type inference target
2663 * flag 1: don't put an error when inference fails
2665 Expression
inferType(Expression e
, Type t
, int flag
= 0)
2667 Expression
visitAle(ArrayLiteralExp ale
)
2669 Type tb
= t
.toBasetype();
2670 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
2672 Type tn
= tb
.nextOf();
2674 ale
.basis
= inferType(ale
.basis
, tn
, flag
);
2675 for (size_t i
= 0; i
< ale
.elements
.length
; i
++)
2677 if (Expression e
= (*ale
.elements
)[i
])
2679 e
= inferType(e
, tn
, flag
);
2680 (*ale
.elements
)[i
] = e
;
2687 Expression
visitAar(AssocArrayLiteralExp aale
)
2689 Type tb
= t
.toBasetype();
2690 if (auto taa
= tb
.isTypeAArray())
2692 Type ti
= taa
.index
;
2693 Type tv
= taa
.nextOf();
2694 for (size_t i
= 0; i
< aale
.keys
.length
; i
++)
2696 if (Expression e
= (*aale
.keys
)[i
])
2698 e
= inferType(e
, ti
, flag
);
2699 (*aale
.keys
)[i
] = e
;
2702 for (size_t i
= 0; i
< aale
.values
.length
; i
++)
2704 if (Expression e
= (*aale
.values
)[i
])
2706 e
= inferType(e
, tv
, flag
);
2707 (*aale
.values
)[i
] = e
;
2714 Expression
visitFun(FuncExp fe
)
2716 //printf("FuncExp::inferType('%s'), to=%s\n", fe.type ? fe.type.toChars() : "null", t.toChars());
2717 if (t
.ty
== Tdelegate || t
.ty
== Tpointer
&& t
.nextOf().ty
== Tfunction
)
2724 Expression
visitTer(CondExp ce
)
2726 Type tb
= t
.toBasetype();
2727 ce
.e1
= inferType(ce
.e1
, tb
, flag
);
2728 ce
.e2
= inferType(ce
.e2
, tb
, flag
);
2732 if (t
) switch (e
.op
)
2734 case EXP
.arrayLiteral
: return visitAle(e
.isArrayLiteralExp());
2735 case EXP
.assocArrayLiteral
: return visitAar(e
.isAssocArrayLiteralExp());
2736 case EXP
.function_
: return visitFun(e
.isFuncExp());
2737 case EXP
.question
: return visitTer(e
.isCondExp());
2743 /****************************************
2744 * Scale addition/subtraction to/from pointer.
2746 Expression
scaleFactor(BinExp be
, Scope
* sc
)
2748 Type t1b
= be
.e1
.type
.toBasetype();
2749 Type t2b
= be
.e2
.type
.toBasetype();
2752 if (t1b
.ty
== Tpointer
&& t2b
.isintegral())
2754 // Need to adjust operator by the stride
2755 // Replace (ptr + int) with (ptr + (int * stride))
2756 Type t
= Type
.tptrdiff_t
;
2758 uinteger_t stride
= t1b
.nextOf().size(be
.loc
);
2760 be
.e2
= be
.e2
.castTo(sc
, t
);
2762 be
.e2
= new MulExp(be
.loc
, be
.e2
, new IntegerExp(Loc
.initial
, stride
, t
));
2764 be
.type
= be
.e1
.type
;
2766 else if (t2b
.ty
== Tpointer
&& t1b
.isintegral())
2768 // Need to adjust operator by the stride
2769 // Replace (int + ptr) with (ptr + (int * stride))
2770 Type t
= Type
.tptrdiff_t
;
2773 uinteger_t stride
= t2b
.nextOf().size(be
.loc
);
2775 e
= be
.e1
.castTo(sc
, t
);
2779 e
= new MulExp(be
.loc
, e
, new IntegerExp(Loc
.initial
, stride
, t
));
2781 be
.type
= be
.e2
.type
;
2789 eoff
= eoff
.optimize(WANTvalue
);
2790 if (eoff
.op
== EXP
.int64
&& eoff
.toInteger() == 0)
2793 else if (sc
.setUnsafe(false, be
.loc
, "pointer arithmetic not allowed in @safe functions"))
2795 return ErrorExp
.get();
2801 /**************************************
2802 * Return true if e is an empty array literal with dimensionality
2803 * equal to or less than type of other array.
2804 * [], [[]], [[[]]], etc.
2805 * I.e., make sure that [1,2] is compatible with [],
2806 * [[1,2]] is compatible with [[]], etc.
2808 private bool isVoidArrayLiteral(Expression e
, Type other
)
2810 while (e
.op
== EXP
.arrayLiteral
&& e
.type
.ty
== Tarray
&& (e
.isArrayLiteralExp().elements
.length
== 1))
2812 auto ale
= e
.isArrayLiteralExp();
2814 if (other
.ty
== Tsarray || other
.ty
== Tarray
)
2815 other
= other
.nextOf();
2819 if (other
.ty
!= Tsarray
&& other
.ty
!= Tarray
)
2822 return (e
.op
== EXP
.arrayLiteral
&& t
.ty
== Tarray
&& t
.nextOf().ty
== Tvoid
&& e
.isArrayLiteralExp().elements
.length
== 0);
2826 * Merge types of `e1` and `e2` into a common subset
2828 * Parameters `e1` and `e2` will be rewritten in place as needed.
2831 * sc = Current scope
2832 * op = Operator such as `e1 op e2`. In practice, either EXP.question
2833 * or one of the binary operator.
2834 * pe1 = The LHS of the operation, will be rewritten
2835 * pe2 = The RHS of the operation, will be rewritten
2838 * The resulting type in case of success, `null` in case of error
2840 Type
typeMerge(Scope
* sc
, EXP op
, ref Expression pe1
, ref Expression pe2
)
2842 //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
2844 Expression e1
= pe1
;
2845 Expression e2
= pe2
;
2847 // ImportC: do array/function conversions
2850 e1
= e1
.arrayFuncConv(sc
);
2851 e2
= e2
.arrayFuncConv(sc
);
2854 Type
Lret(Type result
)
2861 printf("-typeMerge() %s op %s\n", e1
.toChars(), e2
.toChars());
2863 printf("\tt1 = %s\n", e1
.type
.toChars());
2865 printf("\tt2 = %s\n", e2
.type
.toChars());
2866 printf("\ttype = %s\n", result
.toChars());
2871 /// Converts one of the expression to the other
2872 Type
convert(ref Expression from
, Type to
)
2874 from
= from
.castTo(sc
, to
);
2878 /// Converts both expression to a third type
2879 Type
coerce(Type towards
)
2881 e1
= e1
.castTo(sc
, towards
);
2882 e2
= e2
.castTo(sc
, towards
);
2883 return Lret(towards
);
2886 Type t1b
= e1
.type
.toBasetype();
2887 Type t2b
= e2
.type
.toBasetype();
2889 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
2891 // Integral types can be implicitly converted to pointers
2892 if ((t1b
.ty
== Tpointer
) != (t2b
.ty
== Tpointer
))
2894 if (t1b
.isintegral())
2896 return convert(e1
, t2b
);
2898 else if (t2b
.isintegral())
2900 return convert(e2
, t1b
);
2905 if (op
!= EXP
.question || t1b
.ty
!= t2b
.ty
&& (t1b
.isTypeBasic() && t2b
.isTypeBasic()))
2907 if (op
== EXP
.question
&& t1b
.ty
.isSomeChar() && t2b
.ty
.isSomeChar())
2909 e1
= e1
.castTo(sc
, Type
.tdchar
);
2910 e2
= e2
.castTo(sc
, Type
.tdchar
);
2914 e1
= integralPromotions(e1
, sc
);
2915 e2
= integralPromotions(e2
, sc
);
2925 /* The start type of alias this type recursion.
2926 * In following case, we should save A, and stop recursion
2927 * if it appears again.
2928 * X -> Y -> [A] -> B -> A -> B -> ...
2933 if (t1
.mod
!= t2
.mod
&&
2934 t1
.ty
== Tenum
&& t2
.ty
== Tenum
&&
2935 t1
.isTypeEnum().sym
== t2
.isTypeEnum().sym
)
2937 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
2938 t1
= t1
.castMod(mod
);
2939 t2
= t2
.castMod(mod
);
2944 t1b
= t1
.toBasetype();
2945 t2b
= t2
.toBasetype();
2947 const ty
= implicitConvCommonTy(t1b
.ty
, t2b
.ty
);
2950 const ty1
= implicitConvTy1(t1b
.ty
, t2b
.ty
);
2951 const ty2
= implicitConvTy1(t2b
.ty
, t1b
.ty
);
2953 if (t1b
.ty
== ty1
) // if no promotions
2958 if (t1b
.equals(t2b
))
2962 t1
= Type
.basic
[ty1
];
2963 t2
= Type
.basic
[ty2
];
2967 e1
= e1
.castTo(sc
, t1
);
2968 e2
= e2
.castTo(sc
, t2
);
2969 return Lret(Type
.basic
[ty
]);
2975 if (t1
.ty
== Ttuple || t2
.ty
== Ttuple
)
2980 // merging can not result in new enum type
2986 if ((t1
.ty
== Tpointer
&& t2
.ty
== Tpointer
) ||
(t1
.ty
== Tdelegate
&& t2
.ty
== Tdelegate
))
2988 // Bring pointers to compatible type
2989 Type t1n
= t1
.nextOf();
2990 Type t2n
= t2
.nextOf();
2992 if (t1n
.equals(t2n
))
2995 if (t1n
.ty
== Tvoid
) // pointers to void are always compatible
2998 if (t2n
.ty
== Tvoid
)
3001 if (t1
.implicitConvTo(t2
))
3002 return convert(e1
, t2
);
3004 if (t2
.implicitConvTo(t1
))
3005 return convert(e2
, t1
);
3007 if (t1n
.ty
== Tfunction
&& t2n
.ty
== Tfunction
)
3009 TypeFunction tf1
= t1n
.isTypeFunction();
3010 TypeFunction tf2
= t2n
.isTypeFunction();
3014 TypeFunction d
= tf1
.syntaxCopy();
3016 if (tf1
.purity
!= tf2
.purity
)
3017 d
.purity
= PURE
.impure
;
3018 assert(d
.purity
!= PURE
.fwdref
);
3020 d
.isnothrow
= (tf1
.isnothrow
&& tf2
.isnothrow
);
3021 d
.isnogc
= (tf1
.isnogc
&& tf2
.isnogc
);
3023 if (tf1
.trust
== tf2
.trust
)
3024 d
.trust
= tf1
.trust
;
3025 else if (tf1
.trust
<= TRUST
.system || tf2
.trust
<= TRUST
.system
)
3026 d
.trust
= TRUST
.system
;
3028 d
.trust
= TRUST
.trusted
;
3030 Type tx
= (t1
.ty
== Tdelegate
) ?
new TypeDelegate(d
) : d
.pointerTo();
3031 tx
= tx
.typeSemantic(e1
.loc
, sc
);
3033 if (t1
.implicitConvTo(tx
) && t2
.implicitConvTo(tx
))
3038 if (t1n
.mod
!= t2n
.mod
)
3040 if (!t1n
.isImmutable() && !t2n
.isImmutable() && t1n
.isShared() != t2n
.isShared())
3042 ubyte mod
= MODmerge(t1n
.mod
, t2n
.mod
);
3043 t1
= t1n
.castMod(mod
).pointerTo();
3044 t2
= t2n
.castMod(mod
).pointerTo();
3049 if (t1n
.ty
== Tclass
&& t2n
.ty
== Tclass
)
3051 ClassDeclaration cd1
= t1n
.isClassHandle();
3052 ClassDeclaration cd2
= t2n
.isClassHandle();
3054 if (cd1
.isBaseOf(cd2
, &offset
))
3057 e2
= e2
.castTo(sc
, t
);
3061 if (cd2
.isBaseOf(cd1
, &offset
))
3064 e1
= e1
.castTo(sc
, t2
);
3071 t1
= t1n
.constOf().pointerTo();
3072 t2
= t2n
.constOf().pointerTo();
3073 if (t1
.implicitConvTo(t2
))
3074 return convert(e1
, t2
);
3075 if (t2
.implicitConvTo(t1
))
3076 return convert(e2
, t1
);
3080 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
)))
3082 /* (T[n] op void*) => T[]
3083 * (T[] op void*) => T[]
3084 * (T[n] op void[0]) => T[]
3085 * (T[] op void[0]) => T[]
3086 * (T[n] op void[]) => T[]
3087 * (T[] op void[]) => T[]
3089 return coerce(t1
.nextOf().arrayOf());
3092 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
)))
3094 /* (void* op T[n]) => T[]
3095 * (void* op T[]) => T[]
3096 * (void[0] op T[n]) => T[]
3097 * (void[0] op T[]) => T[]
3098 * (void[] op T[n]) => T[]
3099 * (void[] op T[]) => T[]
3101 return coerce(t2
.nextOf().arrayOf());
3104 if ((t1
.ty
== Tsarray || t1
.ty
== Tarray
) && (m
= t1
.implicitConvTo(t2
)) != MATCH
.nomatch
)
3106 // https://issues.dlang.org/show_bug.cgi?id=7285
3107 // Tsarray op [x, y, ...] should to be Tsarray
3108 // https://issues.dlang.org/show_bug.cgi?id=14737
3109 // Tsarray ~ [x, y, ...] should to be Tarray
3110 if (t1
.ty
== Tsarray
&& e2
.op
== EXP
.arrayLiteral
&& op
!= EXP
.concatenate
)
3111 return convert(e2
, t1
);
3112 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
))
3114 // Don't make the lvalue const
3117 return convert(e1
, t2
);
3120 if ((t2
.ty
== Tsarray || t2
.ty
== Tarray
) && t2
.implicitConvTo(t1
))
3122 // https://issues.dlang.org/show_bug.cgi?id=7285
3123 // https://issues.dlang.org/show_bug.cgi?id=14737
3124 if (t2
.ty
== Tsarray
&& e1
.op
== EXP
.arrayLiteral
&& op
!= EXP
.concatenate
)
3125 return convert(e1
, t2
);
3126 return convert(e2
, t1
);
3129 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
)
3131 /* If one is mutable and the other immutable, then retry
3132 * with both of them as const
3134 Type t1n
= t1
.nextOf();
3135 Type t2n
= t2
.nextOf();
3137 if (e1
.op
== EXP
.null_
&& e2
.op
!= EXP
.null_
)
3139 else if (e1
.op
!= EXP
.null_
&& e2
.op
== EXP
.null_
)
3141 else if (!t1n
.isImmutable() && !t2n
.isImmutable() && t1n
.isShared() != t2n
.isShared())
3144 mod
= MODmerge(t1n
.mod
, t2n
.mod
);
3146 if (t1
.ty
== Tpointer
)
3147 t1
= t1n
.castMod(mod
).pointerTo();
3149 t1
= t1n
.castMod(mod
).arrayOf();
3151 if (t2
.ty
== Tpointer
)
3152 t2
= t2n
.castMod(mod
).pointerTo();
3154 t2
= t2n
.castMod(mod
).arrayOf();
3159 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
3161 if (t1
.mod
!= t2
.mod
)
3164 if (e1
.op
== EXP
.null_
&& e2
.op
!= EXP
.null_
)
3166 else if (e1
.op
!= EXP
.null_
&& e2
.op
== EXP
.null_
)
3168 else if (!t1
.isImmutable() && !t2
.isImmutable() && t1
.isShared() != t2
.isShared())
3171 mod
= MODmerge(t1
.mod
, t2
.mod
);
3172 t1
= t1
.castMod(mod
);
3173 t2
= t2
.castMod(mod
);
3180 if (t1
.ty
== Tclass || t2
.ty
== Tclass
)
3185 MATCH i1woat
= MATCH
.exact
;
3186 MATCH i2woat
= MATCH
.exact
;
3188 if (auto t2c
= t2
.isTypeClass())
3189 i1woat
= t2c
.implicitConvToWithoutAliasThis(t1
);
3190 if (auto t1c
= t1
.isTypeClass())
3191 i2woat
= t1c
.implicitConvToWithoutAliasThis(t2
);
3193 MATCH i1
= e2
.implicitConvTo(t1
);
3194 MATCH i2
= e1
.implicitConvTo(t2
);
3198 // We have the case of class vs. void*, so pick class
3199 if (t1
.ty
== Tpointer
)
3201 else if (t2
.ty
== Tpointer
)
3205 // Match but without 'alias this' on classes
3211 // Here use implicitCastTo() instead of castTo() to try 'alias this' on classes
3212 Type
coerceImplicit(Type towards
)
3214 e1
= e1
.implicitCastTo(sc
, towards
);
3215 e2
= e2
.implicitCastTo(sc
, towards
);
3216 return Lret(towards
);
3219 // Implicit conversion with 'alias this'
3221 return coerceImplicit(t2
);
3223 return coerceImplicit(t1
);
3225 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
3227 TypeClass tc1
= t1
.isTypeClass();
3228 TypeClass tc2
= t2
.isTypeClass();
3230 /* Pick 'tightest' type
3232 ClassDeclaration cd1
= tc1
.sym
.baseClass
;
3233 ClassDeclaration cd2
= tc2
.sym
.baseClass
;
3236 t1
= cd1
.type
.castMod(t1
.mod
);
3237 t2
= cd2
.type
.castMod(t2
.mod
);
3246 else if (t1
.ty
== Tstruct
&& t1
.isTypeStruct().sym
.aliasthis
)
3248 if (isRecursiveAliasThis(att1
, e1
.type
))
3250 //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars());
3251 e1
= resolveAliasThis(sc
, e1
);
3255 else if (t2
.ty
== Tstruct
&& t2
.isTypeStruct().sym
.aliasthis
)
3257 if (isRecursiveAliasThis(att2
, e2
.type
))
3259 //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars());
3260 e2
= resolveAliasThis(sc
, e2
);
3269 if (t1
.ty
== Tstruct
&& t2
.ty
== Tstruct
)
3271 if (t1
.mod
!= t2
.mod
)
3273 if (!t1
.isImmutable() && !t2
.isImmutable() && t1
.isShared() != t2
.isShared())
3275 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
3276 t1
= t1
.castMod(mod
);
3277 t2
= t2
.castMod(mod
);
3282 TypeStruct ts1
= t1
.isTypeStruct();
3283 TypeStruct ts2
= t2
.isTypeStruct();
3284 if (ts1
.sym
!= ts2
.sym
)
3286 if (!ts1
.sym
.aliasthis
&& !ts2
.sym
.aliasthis
)
3289 MATCH i1
= MATCH
.nomatch
;
3290 MATCH i2
= MATCH
.nomatch
;
3292 Expression e1b
= null;
3293 Expression e2b
= null;
3294 if (ts2
.sym
.aliasthis
)
3296 if (isRecursiveAliasThis(att2
, e2
.type
))
3298 //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars());
3299 e2b
= resolveAliasThis(sc
, e2
);
3300 i1
= e2b
.implicitConvTo(t1
);
3302 if (ts1
.sym
.aliasthis
)
3304 if (isRecursiveAliasThis(att1
, e1
.type
))
3306 //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars());
3307 e1b
= resolveAliasThis(sc
, e1
);
3308 i2
= e1b
.implicitConvTo(t2
);
3314 return convert(e2
, t1
);
3316 return convert(e1
, t2
);
3321 t1
= e1b
.type
.toBasetype();
3326 t2
= e2b
.type
.toBasetype();
3333 if (t1
.ty
== Tstruct
&& t1
.isTypeStruct().sym
.aliasthis
)
3335 if (isRecursiveAliasThis(att1
, e1
.type
))
3337 //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
3338 e1
= resolveAliasThis(sc
, e1
);
3344 if (t2
.ty
== Tstruct
&& t2
.isTypeStruct().sym
.aliasthis
)
3346 if (isRecursiveAliasThis(att2
, e2
.type
))
3348 //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
3349 e2
= resolveAliasThis(sc
, e2
);
3355 if ((e1
.op
== EXP
.string_ || e1
.op
== EXP
.null_
) && e1
.implicitConvTo(t2
))
3356 return convert(e1
, t2
);
3357 if ((e2
.op
== EXP
.string_ || e2
.op
== EXP
.null_
) && e2
.implicitConvTo(t1
))
3358 return convert(e2
, t1
);
3359 if (t1
.ty
== Tsarray
&& t2
.ty
== Tsarray
&& e2
.implicitConvTo(t1
.nextOf().arrayOf()))
3360 return coerce(t1
.nextOf().arrayOf());
3361 if (t1
.ty
== Tsarray
&& t2
.ty
== Tsarray
&& e1
.implicitConvTo(t2
.nextOf().arrayOf()))
3362 return coerce(t2
.nextOf().arrayOf());
3364 if (t1
.ty
== Tvector
&& t2
.ty
== Tvector
)
3366 // https://issues.dlang.org/show_bug.cgi?id=13841
3367 // all vector types should have no common types between
3368 // different vectors, even though their sizes are same.
3369 auto tv1
= t1
.isTypeVector();
3370 auto tv2
= t2
.isTypeVector();
3371 if (!tv1
.basetype
.equals(tv2
.basetype
))
3377 if (t1
.ty
== Tvector
&& t2
.ty
!= Tvector
&& e2
.implicitConvTo(t1
))
3379 e2
= e2
.castTo(sc
, t1
);
3385 if (t2
.ty
== Tvector
&& t1
.ty
!= Tvector
&& e1
.implicitConvTo(t2
))
3387 e1
= e1
.castTo(sc
, t2
);
3393 if (t1
.isintegral() && t2
.isintegral())
3397 if (t1
.ty
== Tvector || t2
.ty
== Tvector
)
3399 e1
= integralPromotions(e1
, sc
);
3400 e2
= integralPromotions(e2
, sc
);
3405 assert(t1
.ty
== t2
.ty
);
3407 if (!t1
.isImmutable() && !t2
.isImmutable() && t1
.isShared() != t2
.isShared())
3409 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
3411 t1
= t1
.castMod(mod
);
3412 t2
= t2
.castMod(mod
);
3414 e1
= e1
.castTo(sc
, t
);
3415 e2
= e2
.castTo(sc
, t
);
3419 if (t1
.ty
== Tnull
&& t2
.ty
== Tnull
)
3421 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
3422 return coerce(t1
.castMod(mod
));
3425 if (t2
.ty
== Tnull
&& (t1
.ty
== Tpointer || t1
.ty
== Taarray || t1
.ty
== Tarray
))
3426 return convert(e2
, t1
);
3427 if (t1
.ty
== Tnull
&& (t2
.ty
== Tpointer || t2
.ty
== Taarray || t2
.ty
== Tarray
))
3428 return convert(e1
, t2
);
3430 /// Covers array operations for user-defined types
3431 Type
checkArrayOpType(Expression e1
, Expression e2
, EXP op
, Scope
*sc
)
3433 // scalar op scalar - we shouldn't be here
3434 if (e1
.type
.ty
!= Tarray
&& e1
.type
.ty
!= Tsarray
&& e2
.type
.ty
!= Tarray
&& e2
.type
.ty
!= Tsarray
)
3437 // only supporting slices and array literals
3438 if (!e1
.isSliceExp() && !e1
.isArrayLiteralExp() && !e2
.isSliceExp() && !e2
.isArrayLiteralExp())
3441 // start with e1 op e2 and if either one of e1 or e2 is a slice or array literal,
3442 // replace it with the first element of the array
3443 Expression lhs
= e1
;
3444 Expression rhs
= e2
;
3447 if (auto se1
= e1
.isSliceExp())
3448 lhs
= new IndexExp(Loc
.initial
, se1
.e1
, IntegerExp
.literal
!0);
3450 // [t1, t2, .. t3] op ?
3451 if (auto ale1
= e1
.isArrayLiteralExp())
3452 lhs
= ale1
.opIndex(0);
3455 if (auto se2
= e2
.isSliceExp())
3456 rhs
= new IndexExp(Loc
.initial
, se2
.e1
, IntegerExp
.literal
!0);
3458 // ? op [u1, u2, .. u3]
3459 if (auto ale2
= e2
.isArrayLiteralExp())
3460 rhs
= ale2
.opIndex(0);
3462 // create a new binary expression with the new lhs and rhs (at this stage, at least
3463 // one of lhs/rhs has been replaced with the 0'th element of the array it was before)
3468 exp
= new AddExp(Loc
.initial
, lhs
, rhs
); break;
3470 exp
= new MinExp(Loc
.initial
, lhs
, rhs
); break;
3472 exp
= new MulExp(Loc
.initial
, lhs
, rhs
); break;
3474 exp
= new DivExp(Loc
.initial
, lhs
, rhs
); break;
3476 exp
= new PowExp(Loc
.initial
, lhs
, rhs
); break;
3483 // if T op U is valid and has type V
3484 // then T[] op U and T op U[] should be valid and have type V[]
3485 Expression e
= exp
.trySemantic(sc
);
3487 return e
.type
.arrayOf
;
3493 if (t1
.ty
== Tarray
&& isBinArrayOp(op
) && isArrayOpOperand(e1
))
3495 if (e2
.implicitConvTo(t1
.nextOf()))
3499 e2
= e2
.castTo(sc
, t1
.nextOf());
3500 return Lret(t1
.nextOf().arrayOf());
3502 if (t1
.nextOf().implicitConvTo(e2
.type
))
3504 // (cast(T)U)[] op T (https://issues.dlang.org/show_bug.cgi?id=12780)
3505 // e1 is left as U[], it will be handled in arrayOp() later.
3506 return Lret(e2
.type
.arrayOf());
3508 if (t2
.ty
== Tarray
&& isArrayOpOperand(e2
))
3510 if (t1
.nextOf().implicitConvTo(t2
.nextOf()))
3512 // (cast(T)U)[] op T[] (https://issues.dlang.org/show_bug.cgi?id=12780)
3513 t
= t2
.nextOf().arrayOf();
3514 // if cast won't be handled in arrayOp() later
3515 if (!isArrayOpImplicitCast(t1
.isTypeDArray(), t2
.isTypeDArray()))
3516 e1
= e1
.castTo(sc
, t
);
3519 if (t2
.nextOf().implicitConvTo(t1
.nextOf()))
3521 // T[] op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780)
3522 // e2 is left as U[], it will be handled in arrayOp() later.
3523 t
= t1
.nextOf().arrayOf();
3524 // if cast won't be handled in arrayOp() later
3525 if (!isArrayOpImplicitCast(t2
.isTypeDArray(), t1
.isTypeDArray()))
3526 e2
= e2
.castTo(sc
, t
);
3531 t
= checkArrayOpType(e1
, e2
, op
, sc
);
3537 else if (t2
.ty
== Tarray
&& isBinArrayOp(op
) && isArrayOpOperand(e2
))
3539 if (e1
.implicitConvTo(t2
.nextOf()))
3543 e1
= e1
.castTo(sc
, t2
.nextOf());
3544 t
= t2
.nextOf().arrayOf();
3546 else if (t2
.nextOf().implicitConvTo(e1
.type
))
3548 // T op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780)
3549 // e2 is left as U[], it will be handled in arrayOp() later.
3550 t
= e1
.type
.arrayOf();
3554 t
= checkArrayOpType(e1
, e2
, op
, sc
);
3559 //printf("test %s\n", EXPtoString(op).ptr);
3560 e1
= e1
.optimize(WANTvalue
);
3561 if (isCommutative(op
) && e1
.isConst())
3563 /* Swap operands to minimize number of functions generated
3565 //printf("swap %s\n", EXPtoString(op).ptr);
3566 Expression tmp
= e1
;
3576 /************************************
3577 * Bring leaves to common type.
3579 * null on success, ErrorExp if error occurs
3581 Expression
typeCombine(BinExp be
, Scope
* sc
)
3583 Expression
errorReturn()
3585 Expression ex
= be
.incompatibleTypes();
3586 if (ex
.op
== EXP
.error
)
3588 return ErrorExp
.get();
3591 Type t1
= be
.e1
.type
.toBasetype();
3592 Type t2
= be
.e2
.type
.toBasetype();
3594 if (be
.op
== EXP
.min || be
.op
== EXP
.add)
3596 // struct+struct, and class+class are errors
3597 if (t1
.ty
== Tstruct
&& t2
.ty
== Tstruct
)
3598 return errorReturn();
3599 else if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
3600 return errorReturn();
3601 else if (t1
.ty
== Taarray
&& t2
.ty
== Taarray
)
3602 return errorReturn();
3605 if (auto result
= typeMerge(sc
, be
.op
, be
.e1
, be
.e2
))
3607 if (be
.type
is null)
3611 return errorReturn();
3613 // If the types have no value, return an error
3614 if (be
.e1
.op
== EXP
.error
)
3616 if (be
.e2
.op
== EXP
.error
)
3621 /***********************************
3622 * Do integral promotions (convertchk).
3623 * Don't convert <array of> to <pointer to>
3625 Expression
integralPromotions(Expression e
, Scope
* sc
)
3627 //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars());
3628 switch (e
.type
.toBasetype().ty
)
3631 error(e
.loc
, "void has no value");
3632 return ErrorExp
.get();
3641 e
= e
.castTo(sc
, Type
.tint32
);
3645 e
= e
.castTo(sc
, Type
.tuns32
);
3654 /******************************************************
3655 * This provides a transition from the non-promoting behavior
3656 * of unary + - ~ to the C-like integral promotion behavior.
3659 * ue = NegExp, UAddExp, or ComExp which is revised per rules
3661 * https://issues.dlang.org/show_bug.cgi?id=16997
3664 void fix16997(Scope
* sc
, UnaExp ue
)
3666 if (global
.params
.fix16997 || sc
.flags
& SCOPE
.Cfile
)
3667 ue
.e1
= integralPromotions(ue
.e1
, sc
); // desired C-like behavor
3670 switch (ue
.e1
.type
.toBasetype
.ty
)
3676 //case Tbool: // these operations aren't allowed on bool anyway
3680 deprecation(ue
.loc
, "integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`",
3681 ue
.toChars(), EXPtoString(ue
.op
).ptr
, ue
.e1
.toChars());
3690 /***********************************
3691 * See if both types are arrays that can be compared
3692 * for equality without any casting. Return true if so.
3693 * This is to enable comparing things like an immutable
3694 * array with a mutable one.
3696 extern (D
) bool arrayTypeCompatibleWithoutCasting(Type t1
, Type t2
)
3698 t1
= t1
.toBasetype();
3699 t2
= t2
.toBasetype();
3701 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray || t1
.ty
== Tpointer
) && t2
.ty
== t1
.ty
)
3703 if (t1
.nextOf().implicitConvTo(t2
.nextOf()) >= MATCH
.constant || t2
.nextOf().implicitConvTo(t1
.nextOf()) >= MATCH
.constant
)
3709 /******************************************************************/
3710 /* Determine the integral ranges of an expression.
3711 * This is used to determine if implicit narrowing conversions will
3715 IntRange
getIntRange(Expression e
)
3717 IntRange
visit(Expression e
)
3719 return IntRange
.fromType(e
.type
);
3722 IntRange
visitInteger(IntegerExp e
)
3724 return IntRange(SignExtendedNumber(e
.getInteger()))._cast(e
.type
);
3727 IntRange
visitCast(CastExp e
)
3729 return getIntRange(e
.e1
)._cast(e
.type
);
3732 IntRange
visitAdd(AddExp e
)
3734 IntRange ir1
= getIntRange(e
.e1
);
3735 IntRange ir2
= getIntRange(e
.e2
);
3736 return (ir1
+ ir2
)._cast(e
.type
);
3739 IntRange
visitMin(MinExp e
)
3741 IntRange ir1
= getIntRange(e
.e1
);
3742 IntRange ir2
= getIntRange(e
.e2
);
3743 return (ir1
- ir2
)._cast(e
.type
);
3746 IntRange
visitDiv(DivExp e
)
3748 IntRange ir1
= getIntRange(e
.e1
);
3749 IntRange ir2
= getIntRange(e
.e2
);
3751 return (ir1
/ ir2
)._cast(e
.type
);
3754 IntRange
visitMul(MulExp e
)
3756 IntRange ir1
= getIntRange(e
.e1
);
3757 IntRange ir2
= getIntRange(e
.e2
);
3759 return (ir1
* ir2
)._cast(e
.type
);
3762 IntRange
visitMod(ModExp e
)
3764 IntRange ir1
= getIntRange(e
.e1
);
3765 IntRange ir2
= getIntRange(e
.e2
);
3767 // Modding on 0 is invalid anyway.
3768 if (!ir2
.absNeg().imin
.negative
)
3772 return (ir1
% ir2
)._cast(e
.type
);
3775 IntRange
visitAnd(AndExp e
)
3778 bool hasResult
= false;
3779 result
.unionOrAssign(getIntRange(e
.e1
) & getIntRange(e
.e2
), hasResult
);
3782 return result
._cast(e
.type
);
3785 IntRange
visitOr(OrExp e
)
3788 bool hasResult
= false;
3789 result
.unionOrAssign(getIntRange(e
.e1
) |
getIntRange(e
.e2
), hasResult
);
3792 return result
._cast(e
.type
);
3795 IntRange
visitXor(XorExp e
)
3798 bool hasResult
= false;
3799 result
.unionOrAssign(getIntRange(e
.e1
) ^
getIntRange(e
.e2
), hasResult
);
3802 return result
._cast(e
.type
);
3805 IntRange
visitShl(ShlExp e
)
3807 IntRange ir1
= getIntRange(e
.e1
);
3808 IntRange ir2
= getIntRange(e
.e2
);
3810 return (ir1
<< ir2
)._cast(e
.type
);
3813 IntRange
visitShr(ShrExp e
)
3815 IntRange ir1
= getIntRange(e
.e1
);
3816 IntRange ir2
= getIntRange(e
.e2
);
3818 return (ir1
>> ir2
)._cast(e
.type
);
3821 IntRange
visitUshr(UshrExp e
)
3823 IntRange ir1
= getIntRange(e
.e1
).castUnsigned(e
.e1
.type
);
3824 IntRange ir2
= getIntRange(e
.e2
);
3826 return (ir1
>>> ir2
)._cast(e
.type
);
3829 IntRange
visitAssign(AssignExp e
)
3831 return getIntRange(e
.e2
)._cast(e
.type
);
3834 IntRange
visitCond(CondExp e
)
3836 // No need to check e.econd; assume caller has called optimize()
3837 IntRange ir1
= getIntRange(e
.e1
);
3838 IntRange ir2
= getIntRange(e
.e2
);
3839 return ir1
.unionWith(ir2
)._cast(e
.type
);
3842 IntRange
visitVar(VarExp e
)
3845 VarDeclaration vd
= e
.var
.isVarDeclaration();
3847 return vd
.range
._cast(e
.type
);
3848 else if (vd
&& vd
._init
&& !vd
.type
.isMutable() && (ie
= vd
.getConstInitializer()) !is null)
3849 return getIntRange(ie
);
3854 IntRange
visitComma(CommaExp e
)
3856 return getIntRange(e
.e2
);
3859 IntRange
visitCom(ComExp e
)
3861 IntRange ir
= getIntRange(e
.e1
);
3862 return IntRange(SignExtendedNumber(~ir
.imax
.value
, !ir
.imax
.negative
), SignExtendedNumber(~ir
.imin
.value
, !ir
.imin
.negative
))._cast(e
.type
);
3865 IntRange
visitNeg(NegExp e
)
3867 IntRange ir
= getIntRange(e
.e1
);
3868 return (-ir
)._cast(e
.type
);
3873 default : return visit(e
);
3874 case EXP
.int64
: return visitInteger(e
.isIntegerExp());
3875 case EXP
.cast_
: return visitCast(e
.isCastExp());
3876 case EXP
.add : return visitAdd(e
.isAddExp());
3877 case EXP
.min
: return visitMin(e
.isMinExp());
3878 case EXP
.div : return visitDiv(e
.isDivExp());
3879 case EXP
.mul : return visitMul(e
.isMulExp());
3880 case EXP
.mod
: return visitMod(e
.isModExp());
3881 case EXP
.and : return visitAnd(e
.isAndExp());
3882 case EXP
.or : return visitOr(e
.isOrExp());
3883 case EXP
.xor : return visitXor(e
.isXorExp());
3884 case EXP
.leftShift
: return visitShl(e
.isShlExp());
3885 case EXP
.rightShift
: return visitShr(e
.isShrExp());
3886 case EXP
.unsignedRightShift
: return visitUshr(e
.isUshrExp());
3887 case EXP
.blit
: return visitAssign(e
.isBlitExp());
3888 case EXP
.construct
: return visitAssign(e
.isConstructExp());
3889 case EXP
.assign
: return visitAssign(e
.isAssignExp());
3890 case EXP
.question
: return visitCond(e
.isCondExp());
3891 case EXP
.variable
: return visitVar(e
.isVarExp());
3892 case EXP
.comma
: return visitComma(e
.isCommaExp());
3893 case EXP
.tilde
: return visitCom(e
.isComExp());
3894 case EXP
.negate
: return visitNeg(e
.isNegExp());
3898 * A helper function to "cast" from expressions of type noreturn to
3899 * any other type - noreturn is implicitly convertible to any other type.
3900 * However, the dmd backend does not like a naive cast from a noreturn expression
3901 * (particularly an `assert(0)`) so this function generates:
3903 * `(assert(0), value)` instead of `cast(to)(assert(0))`.
3905 * `value` is currently `to.init` however it cannot be read so could be made simpler.
3907 * toBeCasted = Expression of type noreturn to cast
3908 * to = Type to cast the expression to.
3909 * Returns: A CommaExp, upon any failure ErrorExp will be returned.
3911 Expression
specialNoreturnCast(Expression toBeCasted
, Type to
)
3913 return Expression
.combine(toBeCasted
, to
.defaultInitLiteral(toBeCasted
.loc
));