2 * Semantic analysis for cast-expressions.
4 * Copyright: Copyright (C) 1999-2024 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
;
27 import dmd
.dsymbolsem
;
30 import dmd
.expression
;
31 import dmd
.expressionsem
;
43 import dmd
.root
.ctfloat
;
44 import dmd
.common
.outbuffer
;
53 * Attempt to implicitly cast the expression into type `t`.
55 * This routine will change `e`. To check the matching level,
56 * use `implicitConvTo`.
59 * e = Expression that is to be casted
61 * t = Expected resulting type
64 * The resulting casted expression (mutating `e`), or `ErrorExp`
65 * if such an implicit conversion is not possible.
67 Expression
implicitCastTo(Expression e
, Scope
* sc
, Type t
)
69 Expression
visit(Expression e
)
71 // 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 || typeb
.ty
== Tpointer
))
806 { // Tpointer because ImportC eagerly converts Tsarray to Tpointer
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
))
1491 if (tb
.isTypeVector() || typeb
.isTypeVector())
1492 return implicitConvTo(e
, t
); // permissive checking doesn't apply to vectors
1494 if ((typeb
.isintegral() || typeb
.isfloating()) &&
1495 (tb
.isintegral() || tb
.isfloating()))
1496 return MATCH
.convert
;
1497 if (tb
.ty
== Tpointer
&& typeb
.isintegral()) // C11 6.3.2.3-5
1498 return MATCH
.convert
;
1499 if (tb
.isintegral() && typeb
.ty
== Tpointer
) // C11 6.3.2.3-6
1500 return MATCH
.convert
;
1501 if (tb
.ty
== Tpointer
&& typeb
.ty
== Tpointer
) // C11 6.3.2.3-7
1502 return MATCH
.convert
;
1504 return implicitConvTo(e
, t
);
1507 /*****************************************
1509 Type
toStaticArrayType(SliceExp e
)
1513 // For the following code to work, e should be optimized beforehand.
1514 // (eg. $ in lwr and upr should be already resolved, if possible)
1515 Expression lwr
= e
.lwr
.optimize(WANTvalue
);
1516 Expression upr
= e
.upr
.optimize(WANTvalue
);
1517 if (lwr
.isConst() && upr
.isConst())
1519 size_t len
= cast(size_t
)(upr
.toUInteger() - lwr
.toUInteger());
1520 return e
.type
.toBasetype().nextOf().sarrayOf(len
);
1525 Type t1b
= e
.e1
.type
.toBasetype();
1526 if (t1b
.ty
== Tsarray
)
1532 /**************************************
1533 * Do an explicit cast.
1534 * Assume that the expression `e` does not have any indirections.
1535 * (Parameter 'att' is used to stop 'alias this' recursion)
1537 Expression
castTo(Expression e
, Scope
* sc
, Type t
, Type att
= null)
1539 //printf("castTo(e: %s from: %s to: %s\n", e.toChars(), e.type.toChars(), t.toChars());
1541 Expression
visit(Expression e
)
1543 //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars());
1546 printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
1548 if (e
.type
.equals(t
))
1552 if (e
.type
.isTypeNoreturn() && e
.op
!= EXP
.type
)
1554 return specialNoreturnCast(e
, t
);
1556 if (auto ve
= e
.isVarExp())
1558 VarDeclaration v
= ve
.var
.isVarDeclaration();
1559 if (v
&& v
.storage_class
& STC
.manifest
)
1561 auto result
= e
.ctfeInterpret();
1562 /* https://issues.dlang.org/show_bug.cgi?id=18236
1564 * The expression returned by ctfeInterpret points
1565 * to the line where the manifest constant was declared
1566 * so we need to update the location before trying to cast
1569 return result
.castTo(sc
, t
);
1573 Type tob
= t
.toBasetype();
1574 Type t1b
= e
.type
.toBasetype();
1575 if (tob
.equals(t1b
))
1577 auto result
= e
.copy(); // because of COW for assignment to e.type
1582 /* Make semantic error against invalid cast between concrete types.
1583 * Assume that 'e' is never be any placeholder expressions.
1584 * The result of these checks should be consistent with CastExp::toElem().
1588 const(bool) tob_isFV
= (tob
.ty
== Tstruct || tob
.ty
== Tsarray || tob
.ty
== Tvector
);
1589 const(bool) t1b_isFV
= (t1b
.ty
== Tstruct || t1b
.ty
== Tsarray || t1b
.ty
== Tvector
);
1591 // Fat Reference types
1592 const(bool) tob_isFR
= (tob
.ty
== Tarray || tob
.ty
== Tdelegate
);
1593 const(bool) t1b_isFR
= (t1b
.ty
== Tarray || t1b
.ty
== Tdelegate
);
1596 const(bool) tob_isR
= (tob_isFR || tob
.ty
== Tpointer || tob
.ty
== Taarray || tob
.ty
== Tclass
);
1597 const(bool) t1b_isR
= (t1b_isFR || t1b
.ty
== Tpointer || t1b
.ty
== Taarray || t1b
.ty
== Tclass
);
1599 // Arithmetic types (== valueable basic types)
1600 const(bool) tob_isA
= ((tob
.isintegral() || tob
.isfloating()) && tob
.ty
!= Tvector
);
1601 const(bool) t1b_isA
= ((t1b
.isintegral() || t1b
.isfloating()) && t1b
.ty
!= Tvector
);
1603 // Try casting the alias this member.
1604 // Return the expression if it succeeds, null otherwise.
1605 Expression
tryAliasThisCast()
1607 if (isRecursiveAliasThis(att
, t1b
))
1610 /* Forward the cast to our alias this member, rewrite to:
1611 * cast(to)e1.aliasthis
1613 auto exp
= resolveAliasThis(sc
, e
);
1614 const errors
= global
.startGagging();
1615 exp
= castTo(exp
, sc
, t
, att
);
1616 return global
.endGagging(errors
) ?
null : exp
;
1620 if (AggregateDeclaration t1ad
= isAggregate(t1b
))
1622 AggregateDeclaration toad
= isAggregate(tob
);
1623 if (t1ad
!= toad
&& t1ad
.aliasthis
)
1625 if (t1b
.ty
== Tclass
&& tob
.ty
== Tclass
)
1627 ClassDeclaration t1cd
= t1b
.isClassHandle();
1628 ClassDeclaration tocd
= tob
.isClassHandle();
1630 if (tocd
.isBaseOf(t1cd
, &offset
))
1633 hasAliasThis
= true;
1636 else if (tob
.ty
== Tvector
&& t1b
.ty
!= Tvector
)
1638 if (t1b
.ty
== Tsarray
)
1640 // Casting static array to vector with same size, e.g. `cast(int4) int[4]`
1641 if (t1b
.size(e
.loc
) != tob
.size(e
.loc
))
1643 return new VectorExp(e
.loc
, e
, tob
).expressionSemantic(sc
);
1645 //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
1646 TypeVector tv
= tob
.isTypeVector();
1647 Expression result
= new CastExp(e
.loc
, e
, tv
.elementType());
1648 result
= new VectorExp(e
.loc
, result
, tob
);
1649 result
= result
.expressionSemantic(sc
);
1652 else if (tob
.ty
!= Tvector
&& t1b
.ty
== Tvector
)
1654 // T[n] <-- __vector(U[m])
1655 if (tob
.ty
== Tsarray
)
1657 if (t1b
.size(e
.loc
) == tob
.size(e
.loc
))
1662 else if (t1b
.implicitConvTo(tob
) == MATCH
.constant
&& t
.equals(e
.type
.constOf()))
1664 auto result
= e
.copy();
1669 // arithmetic values vs. other arithmetic values
1670 // arithmetic values vs. T*
1671 if (tob_isA
&& (t1b_isA || t1b
.ty
== Tpointer
) || t1b_isA
&& (tob_isA || tob
.ty
== Tpointer
))
1676 // arithmetic values vs. references or fat values
1677 if (tob_isA
&& (t1b_isR || t1b_isFV
) || t1b_isA
&& (tob_isR || tob_isFV
))
1682 // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
1683 if (tob_isFV
&& t1b_isFV
)
1687 auto result
= tryAliasThisCast();
1692 if (t1b
.size(e
.loc
) == tob
.size(e
.loc
))
1695 auto ts
= toAutoQualChars(e
.type
, t
);
1696 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s` because of different sizes",
1697 e
.toChars(), ts
[0], ts
[1]);
1698 return ErrorExp
.get();
1701 // Fat values vs. null or references
1702 if (tob_isFV
&& (t1b
.ty
== Tnull || t1b_isR
) || t1b_isFV
&& (tob
.ty
== Tnull || tob_isR
))
1704 if (tob
.ty
== Tpointer
&& t1b
.ty
== Tsarray
)
1707 // cast(U*)sa; // ==> cast(U*)sa.ptr;
1708 return new AddrExp(e
.loc
, e
, t
);
1710 if (tob
.ty
== Tarray
&& t1b
.ty
== Tsarray
)
1713 // cast(U[])sa; // ==> cast(U[])sa[];
1714 const fsize
= t1b
.nextOf().size();
1715 const tsize
= tob
.nextOf().size();
1716 if (fsize
== SIZE_INVALID || tsize
== SIZE_INVALID
)
1718 return ErrorExp
.get();
1722 const dim
= t1b
.isTypeSArray().dim
.toInteger();
1723 if (tsize
== 0 ||
(dim
* fsize
) % tsize
!= 0)
1725 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
1726 e
.toChars(), e
.type
.toChars(), t
.toChars());
1727 return ErrorExp
.get();
1735 /* For references, any reinterpret casts are allowed to same 'ty' type.
1737 * R1 function(P1) to R2 function(P2)
1738 * R1 delegate(P1) to R2 delegate(P2)
1741 * class/interface A to B (will be a dynamic cast if possible)
1743 if (tob
.ty
== t1b
.ty
&& tob_isR
&& t1b_isR
)
1746 // typeof(null) <-- non-null references or values
1747 if (tob
.ty
== Tnull
&& t1b
.ty
!= Tnull
)
1748 goto Lfail
; // https://issues.dlang.org/show_bug.cgi?id=14629
1749 // typeof(null) --> non-null references or arithmetic values
1750 if (t1b
.ty
== Tnull
&& tob
.ty
!= Tnull
)
1753 // Check size mismatch of references.
1754 // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
1755 if (tob_isFR
&& t1b_isR || t1b_isFR
&& tob_isR
)
1757 if (tob
.ty
== Tpointer
&& t1b
.ty
== Tarray
)
1760 // cast(U*)da; // ==> cast(U*)da.ptr;
1763 if (tob
.ty
== Tpointer
&& t1b
.ty
== Tdelegate
)
1765 // void delegate() dg;
1766 // cast(U*)dg; // ==> cast(U*)dg.ptr;
1767 // Note that it happens even when U is a Tfunction!
1768 deprecation(e
.loc
, "casting from %s to %s is deprecated", e
.type
.toChars(), t
.toChars());
1774 if (t1b
.ty
== Tvoid
&& tob
.ty
!= Tvoid
)
1777 /* if the cast cannot be performed, maybe there is an alias
1778 * this that can be used for casting.
1782 auto result
= tryAliasThisCast();
1786 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s`", e
.toChars(), e
.type
.toChars(), t
.toChars());
1787 return ErrorExp
.get();
1791 auto result
= new CastExp(e
.loc
, e
, t
);
1792 result
.type
= t
; // Don't call semantic()
1793 //printf("Returning: %s\n", result.toChars());
1797 Expression
visitError(ErrorExp e
)
1802 Expression
visitReal(RealExp e
)
1804 if (!e
.type
.equals(t
))
1806 if ((e
.type
.isreal() && t
.isreal()) ||
(e
.type
.isimaginary() && t
.isimaginary()))
1808 auto result
= e
.copy();
1818 Expression
visitComplex(ComplexExp e
)
1820 if (!e
.type
.equals(t
))
1822 if (e
.type
.iscomplex() && t
.iscomplex())
1824 auto result
= e
.copy();
1834 Expression
visitStructLiteral(StructLiteralExp e
)
1836 auto result
= visit(e
);
1837 if (auto sle
= result
.isStructLiteralExp())
1838 sle
.stype
= t
; // commit type
1842 Expression
visitString(StringExp e
)
1844 /* This follows copy-on-write; any changes to 'this'
1845 * will result in a copy.
1846 * The this.string member is considered immutable.
1850 //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
1852 if (!e
.committed
&& t
.ty
== Tpointer
&& t
.nextOf().ty
== Tvoid
&&
1853 (!sc ||
!(sc
.flags
& SCOPE
.Cfile
)))
1855 error(e
.loc
, "cannot convert string literal to `void*`");
1856 return ErrorExp
.get();
1863 auto result
= new CastExp(e
.loc
, se
, t
);
1864 result
.type
= t
; // so semantic() won't be run on e
1870 se
= e
.copy().isStringExp();
1871 se
.committed
= true;
1875 if (e
.type
.equals(t
))
1880 Type tb
= t
.toBasetype();
1881 Type typeb
= e
.type
.toBasetype();
1883 //printf("\ttype = %s\n", e.type.toChars());
1884 if (tb
.ty
== Tdelegate
&& typeb
.ty
!= Tdelegate
)
1889 if (typeb
.equals(tb
))
1893 se
= e
.copy().isStringExp();
1900 /* Handle reinterpret casts:
1901 * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
1902 * cast(wchar[2])"abcd"c --> [\u6261, \u6463]
1903 * cast(wchar[1])"abcd"c --> [\u6261]
1904 * cast(char[4])"a" --> ['a', 0, 0, 0]
1906 if (e
.committed
&& tb
.ty
== Tsarray
&& typeb
.ty
== Tarray
)
1908 se
= e
.copy().isStringExp();
1909 uinteger_t szx
= tb
.nextOf().size();
1911 se
.sz
= cast(ubyte)szx
;
1912 se
.len
= cast(size_t
)tb
.isTypeSArray().dim
.toInteger();
1913 se
.committed
= true;
1916 /* If larger than source, pad with zeros.
1918 const fullSize
= (se
.len
+ 1) * se
.sz
; // incl. terminating 0
1919 if (fullSize
> (e
.len
+ 1) * e
.sz
)
1921 void* s
= mem
.xmalloc(fullSize
);
1922 const srcSize
= e
.len
* e
.sz
;
1923 const data
= se
.peekData();
1924 memcpy(s
, data
.ptr
, srcSize
);
1925 memset(s
+ srcSize
, 0, fullSize
- srcSize
);
1926 se
.setData(s
, se
.len
, se
.sz
);
1931 if (tb
.ty
!= Tsarray
&& tb
.ty
!= Tarray
&& tb
.ty
!= Tpointer
)
1935 se
= e
.copy().isStringExp();
1940 if (typeb
.ty
!= Tsarray
&& typeb
.ty
!= Tarray
&& typeb
.ty
!= Tpointer
)
1944 se
= e
.copy().isStringExp();
1950 const nextSz
= typeb
.nextOf().size();
1951 if (nextSz
== SIZE_INVALID
)
1953 return ErrorExp
.get();
1955 if (nextSz
== tb
.nextOf().size())
1959 se
= e
.copy().isStringExp();
1962 if (tb
.ty
== Tsarray
)
1963 goto L2
; // handle possible change in static array dimension
1971 auto X(T
, U
)(T tf
, U tt
)
1973 return (cast(int)tf
* 256 + cast(int)tt
);
1979 int tfty
= typeb
.nextOf().toBasetype().ty
;
1980 int ttty
= tb
.nextOf().toBasetype().ty
;
1981 switch (X(tfty
, ttty
))
1983 case X(Tchar
, Tchar
):
1984 case X(Twchar
, Twchar
):
1985 case X(Tdchar
, Tdchar
):
1988 case X(Tchar
, Twchar
):
1989 for (size_t u
= 0; u
< e
.len
;)
1992 if (const s
= utf_decodeChar(se
.peekString(), u
, c
))
1993 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
1995 buffer
.writeUTF16(c
);
1997 newlen
= buffer
.length
/ 2;
1998 buffer
.writeUTF16(0);
2001 case X(Tchar
, Tdchar
):
2002 for (size_t u
= 0; u
< e
.len
;)
2005 if (const s
= utf_decodeChar(se
.peekString(), u
, c
))
2006 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
2013 case X(Twchar
, Tchar
):
2014 for (size_t u
= 0; u
< e
.len
;)
2017 if (const s
= utf_decodeWchar(se
.peekWstring(), u
, c
))
2018 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
2020 buffer
.writeUTF8(c
);
2022 newlen
= buffer
.length
;
2023 buffer
.writeUTF8(0);
2026 case X(Twchar
, Tdchar
):
2027 for (size_t u
= 0; u
< e
.len
;)
2030 if (const s
= utf_decodeWchar(se
.peekWstring(), u
, c
))
2031 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
2038 case X(Tdchar
, Tchar
):
2039 for (size_t u
= 0; u
< e
.len
; u
++)
2041 uint c
= se
.peekDstring()[u
];
2042 if (!utf_isValidDchar(c
))
2043 error(e
.loc
, "invalid UCS-32 char \\U%08x", c
);
2045 buffer
.writeUTF8(c
);
2048 newlen
= buffer
.length
;
2049 buffer
.writeUTF8(0);
2052 case X(Tdchar
, Twchar
):
2053 for (size_t u
= 0; u
< e
.len
; u
++)
2055 uint c
= se
.peekDstring()[u
];
2056 if (!utf_isValidDchar(c
))
2057 error(e
.loc
, "invalid UCS-32 char \\U%08x", c
);
2059 buffer
.writeUTF16(c
);
2062 newlen
= buffer
.length
/ 2;
2063 buffer
.writeUTF16(0);
2069 se
= e
.copy().isStringExp();
2074 uinteger_t szx
= tb
.nextOf().size();
2076 se
.setData(buffer
.extractSlice().ptr
, newlen
, cast(ubyte)szx
);
2081 assert(typeb
.nextOf().size() != tb
.nextOf().size());
2088 // See if need to truncate or extend the literal
2089 if (auto tsa
= tb
.isTypeSArray())
2091 size_t dim2
= cast(size_t
)tsa
.dim
.toInteger();
2092 //printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
2094 // Changing dimensions
2097 // Copy when changing the string literal
2098 const newsz
= se
.sz
;
2099 const d
= (dim2
< se
.len
) ? dim2
: se
.len
;
2100 void* s
= mem
.xmalloc((dim2
+ 1) * newsz
);
2101 memcpy(s
, se
.peekData().ptr
, d
* newsz
);
2102 // Extend with 0, add terminating 0
2103 memset(s
+ d
* newsz
, 0, (dim2
+ 1 - d
) * newsz
);
2104 se
.setData(s
, dim2
, newsz
);
2111 auto result
= new CastExp(e
.loc
, se
, t
);
2112 result
.type
= t
; // so semantic() won't be run on e
2116 Expression
visitAddr(AddrExp e
)
2120 printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2122 Type tb
= t
.toBasetype();
2123 Type typeb
= e
.type
.toBasetype();
2125 if (tb
.equals(typeb
))
2127 auto result
= e
.copy();
2132 // Look for pointers to functions where the functions are overloaded.
2133 if (e
.e1
.isOverExp() &&
2134 (tb
.ty
== Tpointer || tb
.ty
== Tdelegate
) && tb
.nextOf().ty
== Tfunction
)
2136 OverExp eo
= e
.e1
.isOverExp();
2137 FuncDeclaration f
= null;
2138 for (size_t i
= 0; i
< eo
.vars
.a
.length
; i
++)
2140 auto s
= eo
.vars
.a
[i
];
2141 auto f2
= s
.isFuncDeclaration();
2143 if (f2
.overloadExactMatch(tb
.nextOf()))
2147 /* Error if match in more than one overload set,
2148 * even if one is a 'better' match than the other.
2150 ScopeDsymbol
.multiplyDefined(e
.loc
, f
, f2
);
2159 auto se
= new SymOffExp(e
.loc
, f
, 0, false);
2160 auto se2
= se
.expressionSemantic(sc
);
2161 // Let SymOffExp::castTo() do the heavy lifting
2166 if (e
.e1
.isVarExp() &&
2167 typeb
.ty
== Tpointer
&& typeb
.nextOf().ty
== Tfunction
&&
2168 tb
.ty
== Tpointer
&& tb
.nextOf().ty
== Tfunction
)
2170 auto ve
= e
.e1
.isVarExp();
2171 auto f
= ve
.var
.isFuncDeclaration();
2174 assert(f
.isImportedSymbol());
2175 f
= f
.overloadExactMatch(tb
.nextOf());
2178 Expression result
= new VarExp(e
.loc
, f
, false);
2179 result
.type
= f
.type
;
2180 result
= new AddrExp(e
.loc
, result
, t
);
2186 if (auto f
= isFuncAddress(e
))
2188 if (f
.checkForwardRef(e
.loc
))
2190 return ErrorExp
.get();
2197 Expression
visitTuple(TupleExp e
)
2199 if (e
.type
.equals(t
))
2204 /* If target type is a tuple of same length, cast each expression to
2205 * the corresponding type in the tuple.
2208 if (auto tt
= t
.isTypeTuple())
2209 totuple
= e
.exps
.length
== tt
.arguments
.length ? tt
: null;
2211 TupleExp te
= e
.copy().isTupleExp();
2212 te
.e0
= e
.e0 ? e
.e0
.copy() : null;
2213 te
.exps
= e
.exps
.copy();
2214 for (size_t i
= 0; i
< te
.exps
.length
; i
++)
2216 Expression ex
= (*te
.exps
)[i
];
2217 ex
= ex
.castTo(sc
, totuple ?
(*totuple
.arguments
)[i
].type
: t
);
2224 /* Questionable behavior: In here, result.type is not set to t
2225 * if target type is not a tuple of same length.
2227 * TypeTuple!(int, int) values;
2228 * auto values2 = cast(long)values;
2229 * // typeof(values2) == TypeTuple!(int, int) !!
2231 * Only when the casted tuple is immediately expanded, it would work.
2232 * auto arr = [cast(long)values];
2233 * // typeof(arr) == long[]
2237 Expression
visitArrayLiteral(ArrayLiteralExp e
)
2241 printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2244 ArrayLiteralExp ae
= e
;
2246 Type tb
= t
.toBasetype();
2247 if (tb
.ty
== Tarray
)
2249 if (checkArrayLiteralEscape(sc
, ae
, false))
2251 return ErrorExp
.get();
2259 Type typeb
= e
.type
.toBasetype();
2261 if ((tb
.ty
== Tarray || tb
.ty
== Tsarray
) &&
2262 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
))
2264 if (tb
.nextOf().toBasetype().ty
== Tvoid
&& typeb
.nextOf().toBasetype().ty
!= Tvoid
)
2266 // Don't do anything to cast non-void[] to void[]
2268 else if (typeb
.ty
== Tsarray
&& typeb
.nextOf().toBasetype().ty
== Tvoid
)
2270 // Don't do anything for casting void[n] to others
2274 if (auto tsa
= tb
.isTypeSArray())
2276 if (e
.elements
.length
!= tsa
.dim
.toInteger())
2280 ae
= e
.copy().isArrayLiteralExp();
2282 ae
.basis
= e
.basis
.castTo(sc
, tb
.nextOf());
2283 ae
.elements
= e
.elements
.copy();
2284 for (size_t i
= 0; i
< e
.elements
.length
; i
++)
2286 Expression ex
= (*e
.elements
)[i
];
2289 ex
= ex
.castTo(sc
, tb
.nextOf());
2290 (*ae
.elements
)[i
] = ex
;
2296 else if (tb
.ty
== Tpointer
&& typeb
.ty
== Tsarray
)
2298 Type tp
= typeb
.nextOf().pointerTo();
2299 if (!tp
.equals(ae
.type
))
2301 ae
= e
.copy().isArrayLiteralExp();
2305 else if (tb
.ty
== Tvector
&& (typeb
.ty
== Tarray || typeb
.ty
== Tsarray || typeb
.ty
== Tpointer
))
2307 // Convert array literal to vector type
2308 // The Tpointer case comes from C eagerly converting Tsarray to Tpointer
2309 TypeVector tv
= tb
.isTypeVector();
2310 TypeSArray tbase
= tv
.basetype
.isTypeSArray();
2311 assert(tbase
.ty
== Tsarray
);
2312 const edim
= e
.elements
.length
;
2313 const tbasedim
= tbase
.dim
.toInteger();
2314 if (edim
> tbasedim
)
2317 ae
= e
.copy().isArrayLiteralExp();
2318 ae
.type
= tbase
; // https://issues.dlang.org/show_bug.cgi?id=12642
2319 ae
.elements
= e
.elements
.copy();
2320 Type telement
= tv
.elementType();
2321 foreach (i
; 0 .. edim
)
2323 Expression ex
= (*e
.elements
)[i
];
2324 ex
= ex
.castTo(sc
, telement
);
2325 (*ae
.elements
)[i
] = ex
;
2327 // Fill in the rest with the default initializer
2328 ae
.elements
.setDim(cast(size_t
)tbasedim
);
2329 foreach (i
; edim
.. cast(size_t
)tbasedim
)
2331 Expression ex
= typeb
.nextOf
.defaultInitLiteral(e
.loc
);
2332 ex
= ex
.castTo(sc
, telement
);
2333 (*ae
.elements
)[i
] = ex
;
2335 Expression ev
= new VectorExp(e
.loc
, ae
, tb
);
2336 ev
= ev
.expressionSemantic(sc
);
2343 Expression
visitAssocArrayLiteral(AssocArrayLiteralExp e
)
2345 //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
2351 Type tb
= t
.toBasetype();
2352 Type typeb
= e
.type
.toBasetype();
2354 if (tb
.ty
== Taarray
&& typeb
.ty
== Taarray
&&
2355 tb
.nextOf().toBasetype().ty
!= Tvoid
)
2357 AssocArrayLiteralExp ae
= e
.copy().isAssocArrayLiteralExp();
2358 ae
.keys
= e
.keys
.copy();
2359 ae
.values
= e
.values
.copy();
2360 assert(e
.keys
.length
== e
.values
.length
);
2361 for (size_t i
= 0; i
< e
.keys
.length
; i
++)
2363 Expression ex
= (*e
.values
)[i
];
2364 ex
= ex
.castTo(sc
, tb
.nextOf());
2365 (*ae
.values
)[i
] = ex
;
2368 ex
= ex
.castTo(sc
, tb
.isTypeAArray().index
);
2377 Expression
visitSymOff(SymOffExp e
)
2381 printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2383 if (e
.type
== t
&& !e
.hasOverloads
)
2388 Type tb
= t
.toBasetype();
2389 Type typeb
= e
.type
.toBasetype();
2391 if (tb
.equals(typeb
))
2393 auto result
= e
.copy();
2395 result
.isSymOffExp().hasOverloads
= false;
2399 // Look for pointers to functions where the functions are overloaded.
2400 if (e
.hasOverloads
&&
2401 typeb
.ty
== Tpointer
&& typeb
.nextOf().ty
== Tfunction
&&
2402 (tb
.ty
== Tpointer || tb
.ty
== Tdelegate
) && tb
.nextOf().ty
== Tfunction
)
2404 FuncDeclaration f
= e
.var
.isFuncDeclaration();
2405 f
= f ? f
.overloadExactMatch(tb
.nextOf()) : null;
2409 if (tb
.ty
== Tdelegate
)
2411 if (f
.needThis() && hasThis(sc
))
2413 result
= new DelegateExp(e
.loc
, new ThisExp(e
.loc
), f
, false);
2414 result
= result
.expressionSemantic(sc
);
2416 else if (f
.needThis())
2418 error(e
.loc
, "no `this` to create delegate for `%s`", f
.toChars());
2419 return ErrorExp
.get();
2421 else if (f
.isNested())
2423 result
= new DelegateExp(e
.loc
, IntegerExp
.literal
!0, f
, false);
2424 result
= result
.expressionSemantic(sc
);
2428 error(e
.loc
, "cannot cast from function pointer to delegate");
2429 return ErrorExp
.get();
2434 result
= new SymOffExp(e
.loc
, f
, 0, false);
2442 if (auto f
= isFuncAddress(e
))
2444 if (f
.checkForwardRef(e
.loc
))
2446 return ErrorExp
.get();
2453 Expression
visitDelegate(DelegateExp e
)
2457 printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e
.toChars(), e
.type
.toChars(), t
.toChars());
2459 static immutable msg
= "cannot form delegate due to covariant return type";
2461 Type tb
= t
.toBasetype();
2462 Type typeb
= e
.type
.toBasetype();
2464 if (tb
.equals(typeb
) && !e
.hasOverloads
)
2467 e
.func
.tookAddressOf
++;
2468 if (e
.func
.tintro
&& e
.func
.tintro
.nextOf().isBaseOf(e
.func
.type
.nextOf(), &offset
) && offset
)
2469 error(e
.loc
, "%s", msg
.ptr
);
2470 auto result
= e
.copy();
2475 // Look for delegates to functions where the functions are overloaded.
2476 if (typeb
.ty
== Tdelegate
&& tb
.ty
== Tdelegate
)
2480 auto f
= e
.func
.overloadExactMatch(tb
.nextOf());
2484 if (f
.tintro
&& f
.tintro
.nextOf().isBaseOf(f
.type
.nextOf(), &offset
) && offset
)
2485 error(e
.loc
, "%s", msg
.ptr
);
2486 if (f
!= e
.func
) // if address not already marked as taken
2488 auto result
= new DelegateExp(e
.loc
, e
.e1
, f
, false, e
.vthis2
);
2493 error(e
.loc
, "%s", msg
.ptr
);
2497 if (auto f
= isFuncAddress(e
))
2499 if (f
.checkForwardRef(e
.loc
))
2501 return ErrorExp
.get();
2508 Expression
visitFunc(FuncExp e
)
2510 //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars());
2512 if (e
.matchType(t
, sc
, &fe
, global
.errorSinkNull
) > MATCH
.nomatch
)
2519 Expression
visitCond(CondExp e
)
2521 if (!e
.type
.equals(t
))
2523 auto result
= new CondExp(e
.loc
, e
.econd
, e
.e1
.castTo(sc
, t
), e
.e2
.castTo(sc
, t
));
2530 Expression
visitComma(CommaExp e
)
2532 Expression e2c
= e
.e2
.castTo(sc
, t
);
2536 auto result
= new CommaExp(e
.loc
, e
.e1
, e2c
);
2537 result
.type
= e2c
.type
;
2547 Expression
visitSlice(SliceExp e
)
2549 //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars());
2551 Type tb
= t
.toBasetype();
2552 Type typeb
= e
.type
.toBasetype();
2554 if (e
.type
.equals(t
) || typeb
.ty
!= Tarray ||
2555 (tb
.ty
!= Tarray
&& tb
.ty
!= Tsarray
))
2560 if (tb
.ty
== Tarray
)
2562 if (typeb
.nextOf().equivalent(tb
.nextOf()))
2564 // T[] to const(T)[]
2565 auto result
= e
.copy();
2575 // Handle the cast from Tarray to Tsarray with CT-known slicing
2579 Type t
= toStaticArrayType(e
);
2580 tsa
= t ? t
.isTypeSArray() : null;
2583 if (tsa
&& tsa
.size(e
.loc
) == tb
.size(e
.loc
))
2585 /* Match if the sarray sizes are equal:
2586 * T[a .. b] to const(T)[b-a]
2587 * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
2589 * If a SliceExp has Tsarray, it will become lvalue.
2590 * That's handled in SliceExp::isLvalue and toLvalue
2592 auto result
= e
.copy();
2596 if (tsa
&& tsa
.dim
.equals(tb
.isTypeSArray().dim
))
2598 /* Match if the dimensions are equal
2599 * with the implicit conversion of e.e1:
2600 * cast(float[2]) [2.0, 1.0, 0.0][0..2];
2602 Type t1b
= e
.e1
.type
.toBasetype();
2603 if (t1b
.ty
== Tsarray
)
2604 t1b
= tb
.nextOf().sarrayOf(t1b
.isTypeSArray().dim
.toInteger());
2605 else if (t1b
.ty
== Tarray
)
2606 t1b
= tb
.nextOf().arrayOf();
2607 else if (t1b
.ty
== Tpointer
)
2608 t1b
= tb
.nextOf().pointerTo();
2611 if (e
.e1
.implicitConvTo(t1b
) > MATCH
.nomatch
)
2613 Expression e1x
= e
.e1
.implicitCastTo(sc
, t1b
);
2614 assert(e1x
.op
!= EXP
.error
);
2615 e
= e
.copy().isSliceExp();
2621 auto ts
= toAutoQualChars(tsa ? tsa
: e
.type
, t
);
2622 error(e
.loc
, "cannot cast expression `%s` of type `%s` to `%s`",
2623 e
.toChars(), ts
[0], ts
[1]);
2624 return ErrorExp
.get();
2627 // Casting to noreturn isn't an actual cast
2628 // Rewrite cast(<qual> noreturn) <exp>
2629 // as <exp>, assert(false)
2630 if (t
.isTypeNoreturn())
2632 // Don't generate an unreachable assert(false) if e will abort
2633 if (e
.type
.isTypeNoreturn())
2635 // Paint e to accomodate for different type qualifiers
2640 auto ini
= t
.defaultInitLiteral(e
.loc
);
2641 return Expression
.combine(e
, ini
);
2646 default : return visit(e
);
2647 case EXP
.error
: return visitError(e
.isErrorExp());
2648 case EXP
.float64
: return visitReal(e
.isRealExp());
2649 case EXP
.complex80
: return visitComplex(e
.isComplexExp());
2650 case EXP
.structLiteral
: return visitStructLiteral(e
.isStructLiteralExp());
2651 case EXP
.string_
: return visitString(e
.isStringExp());
2652 case EXP
.address
: return visitAddr(e
.isAddrExp());
2653 case EXP
.tuple
: return visitTuple(e
.isTupleExp());
2654 case EXP
.arrayLiteral
: return visitArrayLiteral(e
.isArrayLiteralExp());
2655 case EXP
.assocArrayLiteral
: return visitAssocArrayLiteral(e
.isAssocArrayLiteralExp());
2656 case EXP
.symbolOffset
: return visitSymOff(e
.isSymOffExp());
2657 case EXP
.delegate_
: return visitDelegate(e
.isDelegateExp());
2658 case EXP
.function_
: return visitFunc(e
.isFuncExp());
2659 case EXP
.question
: return visitCond(e
.isCondExp());
2660 case EXP
.comma
: return visitComma(e
.isCommaExp());
2661 case EXP
.slice
: return visitSlice(e
.isSliceExp());
2665 /****************************************
2666 * Set type inference target
2668 * flag 1: don't put an error when inference fails
2670 Expression
inferType(Expression e
, Type t
, int flag
= 0)
2672 Expression
visitAle(ArrayLiteralExp ale
)
2674 Type tb
= t
.toBasetype();
2675 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
2677 Type tn
= tb
.nextOf();
2679 ale
.basis
= inferType(ale
.basis
, tn
, flag
);
2680 for (size_t i
= 0; i
< ale
.elements
.length
; i
++)
2682 if (Expression e
= (*ale
.elements
)[i
])
2684 e
= inferType(e
, tn
, flag
);
2685 (*ale
.elements
)[i
] = e
;
2692 Expression
visitAar(AssocArrayLiteralExp aale
)
2694 Type tb
= t
.toBasetype();
2695 if (auto taa
= tb
.isTypeAArray())
2697 Type ti
= taa
.index
;
2698 Type tv
= taa
.nextOf();
2699 for (size_t i
= 0; i
< aale
.keys
.length
; i
++)
2701 if (Expression e
= (*aale
.keys
)[i
])
2703 e
= inferType(e
, ti
, flag
);
2704 (*aale
.keys
)[i
] = e
;
2707 for (size_t i
= 0; i
< aale
.values
.length
; i
++)
2709 if (Expression e
= (*aale
.values
)[i
])
2711 e
= inferType(e
, tv
, flag
);
2712 (*aale
.values
)[i
] = e
;
2719 Expression
visitFun(FuncExp fe
)
2721 //printf("FuncExp::inferType('%s'), to=%s\n", fe.type ? fe.type.toChars() : "null", t.toChars());
2722 if (t
.ty
== Tdelegate || t
.ty
== Tpointer
&& t
.nextOf().ty
== Tfunction
)
2729 Expression
visitTer(CondExp ce
)
2731 Type tb
= t
.toBasetype();
2732 ce
.e1
= inferType(ce
.e1
, tb
, flag
);
2733 ce
.e2
= inferType(ce
.e2
, tb
, flag
);
2737 if (t
) switch (e
.op
)
2739 case EXP
.arrayLiteral
: return visitAle(e
.isArrayLiteralExp());
2740 case EXP
.assocArrayLiteral
: return visitAar(e
.isAssocArrayLiteralExp());
2741 case EXP
.function_
: return visitFun(e
.isFuncExp());
2742 case EXP
.question
: return visitTer(e
.isCondExp());
2748 /****************************************
2749 * Scale addition/subtraction to/from pointer.
2751 Expression
scaleFactor(BinExp be
, Scope
* sc
)
2753 Type t1b
= be
.e1
.type
.toBasetype();
2754 Type t2b
= be
.e2
.type
.toBasetype();
2757 if (t1b
.ty
== Tpointer
&& t2b
.isintegral())
2759 // Need to adjust operator by the stride
2760 // Replace (ptr + int) with (ptr + (int * stride))
2761 Type t
= Type
.tptrdiff_t
;
2763 uinteger_t stride
= t1b
.nextOf().size(be
.loc
);
2765 be
.e2
= be
.e2
.castTo(sc
, t
);
2767 be
.e2
= new MulExp(be
.loc
, be
.e2
, new IntegerExp(Loc
.initial
, stride
, t
));
2769 be
.type
= be
.e1
.type
;
2771 else if (t2b
.ty
== Tpointer
&& t1b
.isintegral())
2773 // Need to adjust operator by the stride
2774 // Replace (int + ptr) with (ptr + (int * stride))
2775 Type t
= Type
.tptrdiff_t
;
2778 uinteger_t stride
= t2b
.nextOf().size(be
.loc
);
2780 e
= be
.e1
.castTo(sc
, t
);
2784 e
= new MulExp(be
.loc
, e
, new IntegerExp(Loc
.initial
, stride
, t
));
2786 be
.type
= be
.e2
.type
;
2794 eoff
= eoff
.optimize(WANTvalue
);
2795 if (eoff
.op
== EXP
.int64
&& eoff
.toInteger() == 0)
2798 else if (sc
.setUnsafe(false, be
.loc
, "pointer arithmetic not allowed in @safe functions"))
2800 return ErrorExp
.get();
2806 /**************************************
2807 * Return true if e is an empty array literal with dimensionality
2808 * equal to or less than type of other array.
2809 * [], [[]], [[[]]], etc.
2810 * I.e., make sure that [1,2] is compatible with [],
2811 * [[1,2]] is compatible with [[]], etc.
2813 private bool isVoidArrayLiteral(Expression e
, Type other
)
2815 while (e
.op
== EXP
.arrayLiteral
&& e
.type
.ty
== Tarray
&& (e
.isArrayLiteralExp().elements
.length
== 1))
2817 auto ale
= e
.isArrayLiteralExp();
2819 if (other
.ty
== Tsarray || other
.ty
== Tarray
)
2820 other
= other
.nextOf();
2824 if (other
.ty
!= Tsarray
&& other
.ty
!= Tarray
)
2827 return (e
.op
== EXP
.arrayLiteral
&& t
.ty
== Tarray
&& t
.nextOf().ty
== Tvoid
&& e
.isArrayLiteralExp().elements
.length
== 0);
2831 * Merge types of `e1` and `e2` into a common subset
2833 * Parameters `e1` and `e2` will be rewritten in place as needed.
2836 * sc = Current scope
2837 * op = Operator such as `e1 op e2`. In practice, either EXP.question
2838 * or one of the binary operator.
2839 * pe1 = The LHS of the operation, will be rewritten
2840 * pe2 = The RHS of the operation, will be rewritten
2843 * The resulting type in case of success, `null` in case of error
2845 Type
typeMerge(Scope
* sc
, EXP op
, ref Expression pe1
, ref Expression pe2
)
2847 //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
2849 Expression e1
= pe1
;
2850 Expression e2
= pe2
;
2852 // ImportC: do array/function conversions
2855 e1
= e1
.arrayFuncConv(sc
);
2856 e2
= e2
.arrayFuncConv(sc
);
2859 Type
Lret(Type result
)
2866 printf("-typeMerge() %s op %s\n", e1
.toChars(), e2
.toChars());
2868 printf("\tt1 = %s\n", e1
.type
.toChars());
2870 printf("\tt2 = %s\n", e2
.type
.toChars());
2871 printf("\ttype = %s\n", result
.toChars());
2876 /// Converts one of the expression to the other
2877 Type
convert(ref Expression from
, Type to
)
2879 from
= from
.castTo(sc
, to
);
2883 /// Converts both expression to a third type
2884 Type
coerce(Type towards
)
2886 e1
= e1
.castTo(sc
, towards
);
2887 e2
= e2
.castTo(sc
, towards
);
2888 return Lret(towards
);
2891 Type t1b
= e1
.type
.toBasetype();
2892 Type t2b
= e2
.type
.toBasetype();
2894 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
2896 // Integral types can be implicitly converted to pointers
2897 if ((t1b
.ty
== Tpointer
) != (t2b
.ty
== Tpointer
))
2899 if (t1b
.isintegral())
2901 return convert(e1
, t2b
);
2903 else if (t2b
.isintegral())
2905 return convert(e2
, t1b
);
2910 if (op
!= EXP
.question || t1b
.ty
!= t2b
.ty
&& (t1b
.isTypeBasic() && t2b
.isTypeBasic()))
2912 if (op
== EXP
.question
&& t1b
.ty
.isSomeChar() && t2b
.ty
.isSomeChar())
2914 e1
= e1
.castTo(sc
, Type
.tdchar
);
2915 e2
= e2
.castTo(sc
, Type
.tdchar
);
2919 e1
= integralPromotions(e1
, sc
);
2920 e2
= integralPromotions(e2
, sc
);
2930 /* The start type of alias this type recursion.
2931 * In following case, we should save A, and stop recursion
2932 * if it appears again.
2933 * X -> Y -> [A] -> B -> A -> B -> ...
2938 if (t1
.mod
!= t2
.mod
&&
2939 t1
.ty
== Tenum
&& t2
.ty
== Tenum
&&
2940 t1
.isTypeEnum().sym
== t2
.isTypeEnum().sym
)
2942 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
2943 t1
= t1
.castMod(mod
);
2944 t2
= t2
.castMod(mod
);
2949 t1b
= t1
.toBasetype();
2950 t2b
= t2
.toBasetype();
2952 const ty
= implicitConvCommonTy(t1b
.ty
, t2b
.ty
);
2955 const ty1
= implicitConvTy1(t1b
.ty
, t2b
.ty
);
2956 const ty2
= implicitConvTy1(t2b
.ty
, t1b
.ty
);
2958 if (t1b
.ty
== ty1
) // if no promotions
2963 if (t1b
.equals(t2b
))
2967 t1
= Type
.basic
[ty1
];
2968 t2
= Type
.basic
[ty2
];
2972 e1
= e1
.castTo(sc
, t1
);
2973 e2
= e2
.castTo(sc
, t2
);
2974 return Lret(Type
.basic
[ty
]);
2980 if (t1
.ty
== Ttuple || t2
.ty
== Ttuple
)
2985 // merging can not result in new enum type
2991 if ((t1
.ty
== Tpointer
&& t2
.ty
== Tpointer
) ||
(t1
.ty
== Tdelegate
&& t2
.ty
== Tdelegate
))
2993 // Bring pointers to compatible type
2994 Type t1n
= t1
.nextOf();
2995 Type t2n
= t2
.nextOf();
2997 if (t1n
.equals(t2n
))
3000 if (t1n
.ty
== Tvoid
) // pointers to void are always compatible
3003 if (t2n
.ty
== Tvoid
)
3006 if (t1
.implicitConvTo(t2
))
3007 return convert(e1
, t2
);
3009 if (t2
.implicitConvTo(t1
))
3010 return convert(e2
, t1
);
3012 if (t1n
.ty
== Tfunction
&& t2n
.ty
== Tfunction
)
3014 TypeFunction tf1
= t1n
.isTypeFunction();
3015 TypeFunction tf2
= t2n
.isTypeFunction();
3019 TypeFunction d
= tf1
.syntaxCopy();
3021 if (tf1
.purity
!= tf2
.purity
)
3022 d
.purity
= PURE
.impure
;
3023 assert(d
.purity
!= PURE
.fwdref
);
3025 d
.isnothrow
= (tf1
.isnothrow
&& tf2
.isnothrow
);
3026 d
.isnogc
= (tf1
.isnogc
&& tf2
.isnogc
);
3028 if (tf1
.trust
== tf2
.trust
)
3029 d
.trust
= tf1
.trust
;
3030 else if (tf1
.trust
<= TRUST
.system || tf2
.trust
<= TRUST
.system
)
3031 d
.trust
= TRUST
.system
;
3033 d
.trust
= TRUST
.trusted
;
3035 Type tx
= (t1
.ty
== Tdelegate
) ?
new TypeDelegate(d
) : d
.pointerTo();
3036 tx
= tx
.typeSemantic(e1
.loc
, sc
);
3038 if (t1
.implicitConvTo(tx
) && t2
.implicitConvTo(tx
))
3043 if (t1n
.mod
!= t2n
.mod
)
3045 if (!t1n
.isImmutable() && !t2n
.isImmutable() && t1n
.isShared() != t2n
.isShared())
3047 ubyte mod
= MODmerge(t1n
.mod
, t2n
.mod
);
3048 t1
= t1n
.castMod(mod
).pointerTo();
3049 t2
= t2n
.castMod(mod
).pointerTo();
3054 if (t1n
.ty
== Tclass
&& t2n
.ty
== Tclass
)
3056 ClassDeclaration cd1
= t1n
.isClassHandle();
3057 ClassDeclaration cd2
= t2n
.isClassHandle();
3059 if (cd1
.isBaseOf(cd2
, &offset
))
3062 e2
= e2
.castTo(sc
, t
);
3066 if (cd2
.isBaseOf(cd1
, &offset
))
3069 e1
= e1
.castTo(sc
, t2
);
3076 t1
= t1n
.constOf().pointerTo();
3077 t2
= t2n
.constOf().pointerTo();
3078 if (t1
.implicitConvTo(t2
))
3079 return convert(e1
, t2
);
3080 if (t2
.implicitConvTo(t1
))
3081 return convert(e2
, t1
);
3085 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
)))
3087 /* (T[n] op void*) => T[]
3088 * (T[] op void*) => T[]
3089 * (T[n] op void[0]) => T[]
3090 * (T[] op void[0]) => T[]
3091 * (T[n] op void[]) => T[]
3092 * (T[] op void[]) => T[]
3094 return coerce(t1
.nextOf().arrayOf());
3097 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
)))
3099 /* (void* op T[n]) => T[]
3100 * (void* op T[]) => T[]
3101 * (void[0] op T[n]) => T[]
3102 * (void[0] op T[]) => T[]
3103 * (void[] op T[n]) => T[]
3104 * (void[] op T[]) => T[]
3106 return coerce(t2
.nextOf().arrayOf());
3109 if ((t1
.ty
== Tsarray || t1
.ty
== Tarray
) && (m
= t1
.implicitConvTo(t2
)) != MATCH
.nomatch
)
3111 // https://issues.dlang.org/show_bug.cgi?id=7285
3112 // Tsarray op [x, y, ...] should to be Tsarray
3113 // https://issues.dlang.org/show_bug.cgi?id=14737
3114 // Tsarray ~ [x, y, ...] should to be Tarray
3115 if (t1
.ty
== Tsarray
&& e2
.op
== EXP
.arrayLiteral
&& op
!= EXP
.concatenate
)
3116 return convert(e2
, t1
);
3117 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
))
3119 // Don't make the lvalue const
3122 return convert(e1
, t2
);
3125 if ((t2
.ty
== Tsarray || t2
.ty
== Tarray
) && t2
.implicitConvTo(t1
))
3127 // https://issues.dlang.org/show_bug.cgi?id=7285
3128 // https://issues.dlang.org/show_bug.cgi?id=14737
3129 if (t2
.ty
== Tsarray
&& e1
.op
== EXP
.arrayLiteral
&& op
!= EXP
.concatenate
)
3130 return convert(e1
, t2
);
3131 return convert(e2
, t1
);
3134 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
)
3136 /* If one is mutable and the other immutable, then retry
3137 * with both of them as const
3139 Type t1n
= t1
.nextOf();
3140 Type t2n
= t2
.nextOf();
3142 if (e1
.op
== EXP
.null_
&& e2
.op
!= EXP
.null_
)
3144 else if (e1
.op
!= EXP
.null_
&& e2
.op
== EXP
.null_
)
3146 else if (!t1n
.isImmutable() && !t2n
.isImmutable() && t1n
.isShared() != t2n
.isShared())
3149 mod
= MODmerge(t1n
.mod
, t2n
.mod
);
3151 if (t1
.ty
== Tpointer
)
3152 t1
= t1n
.castMod(mod
).pointerTo();
3154 t1
= t1n
.castMod(mod
).arrayOf();
3156 if (t2
.ty
== Tpointer
)
3157 t2
= t2n
.castMod(mod
).pointerTo();
3159 t2
= t2n
.castMod(mod
).arrayOf();
3164 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
3166 if (t1
.mod
!= t2
.mod
)
3169 if (e1
.op
== EXP
.null_
&& e2
.op
!= EXP
.null_
)
3171 else if (e1
.op
!= EXP
.null_
&& e2
.op
== EXP
.null_
)
3173 else if (!t1
.isImmutable() && !t2
.isImmutable() && t1
.isShared() != t2
.isShared())
3176 mod
= MODmerge(t1
.mod
, t2
.mod
);
3177 t1
= t1
.castMod(mod
);
3178 t2
= t2
.castMod(mod
);
3185 if (t1
.ty
== Tclass || t2
.ty
== Tclass
)
3190 MATCH i1woat
= MATCH
.exact
;
3191 MATCH i2woat
= MATCH
.exact
;
3193 if (auto t2c
= t2
.isTypeClass())
3194 i1woat
= t2c
.implicitConvToWithoutAliasThis(t1
);
3195 if (auto t1c
= t1
.isTypeClass())
3196 i2woat
= t1c
.implicitConvToWithoutAliasThis(t2
);
3198 MATCH i1
= e2
.implicitConvTo(t1
);
3199 MATCH i2
= e1
.implicitConvTo(t2
);
3203 // We have the case of class vs. void*, so pick class
3204 if (t1
.ty
== Tpointer
)
3206 else if (t2
.ty
== Tpointer
)
3210 // Match but without 'alias this' on classes
3216 // Here use implicitCastTo() instead of castTo() to try 'alias this' on classes
3217 Type
coerceImplicit(Type towards
)
3219 e1
= e1
.implicitCastTo(sc
, towards
);
3220 e2
= e2
.implicitCastTo(sc
, towards
);
3221 return Lret(towards
);
3224 // Implicit conversion with 'alias this'
3226 return coerceImplicit(t2
);
3228 return coerceImplicit(t1
);
3230 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
3232 TypeClass tc1
= t1
.isTypeClass();
3233 TypeClass tc2
= t2
.isTypeClass();
3235 /* Pick 'tightest' type
3237 ClassDeclaration cd1
= tc1
.sym
.baseClass
;
3238 ClassDeclaration cd2
= tc2
.sym
.baseClass
;
3241 t1
= cd1
.type
.castMod(t1
.mod
);
3242 t2
= cd2
.type
.castMod(t2
.mod
);
3251 else if (t1
.ty
== Tstruct
&& t1
.isTypeStruct().sym
.aliasthis
)
3253 if (isRecursiveAliasThis(att1
, e1
.type
))
3255 //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars());
3256 e1
= resolveAliasThis(sc
, e1
);
3260 else if (t2
.ty
== Tstruct
&& t2
.isTypeStruct().sym
.aliasthis
)
3262 if (isRecursiveAliasThis(att2
, e2
.type
))
3264 //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars());
3265 e2
= resolveAliasThis(sc
, e2
);
3274 if (t1
.ty
== Tstruct
&& t2
.ty
== Tstruct
)
3276 if (t1
.mod
!= t2
.mod
)
3278 if (!t1
.isImmutable() && !t2
.isImmutable() && t1
.isShared() != t2
.isShared())
3280 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
3281 t1
= t1
.castMod(mod
);
3282 t2
= t2
.castMod(mod
);
3287 TypeStruct ts1
= t1
.isTypeStruct();
3288 TypeStruct ts2
= t2
.isTypeStruct();
3289 if (ts1
.sym
!= ts2
.sym
)
3291 if (!ts1
.sym
.aliasthis
&& !ts2
.sym
.aliasthis
)
3294 MATCH i1
= MATCH
.nomatch
;
3295 MATCH i2
= MATCH
.nomatch
;
3297 Expression e1b
= null;
3298 Expression e2b
= null;
3299 if (ts2
.sym
.aliasthis
)
3301 if (isRecursiveAliasThis(att2
, e2
.type
))
3303 //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars());
3304 e2b
= resolveAliasThis(sc
, e2
);
3305 i1
= e2b
.implicitConvTo(t1
);
3307 if (ts1
.sym
.aliasthis
)
3309 if (isRecursiveAliasThis(att1
, e1
.type
))
3311 //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars());
3312 e1b
= resolveAliasThis(sc
, e1
);
3313 i2
= e1b
.implicitConvTo(t2
);
3319 return convert(e2
, t1
);
3321 return convert(e1
, t2
);
3326 t1
= e1b
.type
.toBasetype();
3331 t2
= e2b
.type
.toBasetype();
3338 if (t1
.ty
== Tstruct
&& t1
.isTypeStruct().sym
.aliasthis
)
3340 if (isRecursiveAliasThis(att1
, e1
.type
))
3342 //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
3343 e1
= resolveAliasThis(sc
, e1
);
3349 if (t2
.ty
== Tstruct
&& t2
.isTypeStruct().sym
.aliasthis
)
3351 if (isRecursiveAliasThis(att2
, e2
.type
))
3353 //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
3354 e2
= resolveAliasThis(sc
, e2
);
3360 if ((e1
.op
== EXP
.string_ || e1
.op
== EXP
.null_
) && e1
.implicitConvTo(t2
))
3361 return convert(e1
, t2
);
3362 if ((e2
.op
== EXP
.string_ || e2
.op
== EXP
.null_
) && e2
.implicitConvTo(t1
))
3363 return convert(e2
, t1
);
3364 if (t1
.ty
== Tsarray
&& t2
.ty
== Tsarray
&& e2
.implicitConvTo(t1
.nextOf().arrayOf()))
3365 return coerce(t1
.nextOf().arrayOf());
3366 if (t1
.ty
== Tsarray
&& t2
.ty
== Tsarray
&& e1
.implicitConvTo(t2
.nextOf().arrayOf()))
3367 return coerce(t2
.nextOf().arrayOf());
3369 if (t1
.ty
== Tvector
&& t2
.ty
== Tvector
)
3371 // https://issues.dlang.org/show_bug.cgi?id=13841
3372 // all vector types should have no common types between
3373 // different vectors, even though their sizes are same.
3374 auto tv1
= t1
.isTypeVector();
3375 auto tv2
= t2
.isTypeVector();
3376 if (!tv1
.basetype
.equals(tv2
.basetype
))
3382 if (t1
.ty
== Tvector
&& t2
.ty
!= Tvector
&& e2
.implicitConvTo(t1
))
3384 e2
= e2
.castTo(sc
, t1
);
3390 if (t2
.ty
== Tvector
&& t1
.ty
!= Tvector
&& e1
.implicitConvTo(t2
))
3392 e1
= e1
.castTo(sc
, t2
);
3398 if (t1
.isintegral() && t2
.isintegral())
3402 if (t1
.ty
== Tvector || t2
.ty
== Tvector
)
3404 e1
= integralPromotions(e1
, sc
);
3405 e2
= integralPromotions(e2
, sc
);
3410 assert(t1
.ty
== t2
.ty
);
3412 if (!t1
.isImmutable() && !t2
.isImmutable() && t1
.isShared() != t2
.isShared())
3414 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
3416 t1
= t1
.castMod(mod
);
3417 t2
= t2
.castMod(mod
);
3419 e1
= e1
.castTo(sc
, t
);
3420 e2
= e2
.castTo(sc
, t
);
3424 if (t1
.ty
== Tnull
&& t2
.ty
== Tnull
)
3426 ubyte mod
= MODmerge(t1
.mod
, t2
.mod
);
3427 return coerce(t1
.castMod(mod
));
3430 if (t2
.ty
== Tnull
&& (t1
.ty
== Tpointer || t1
.ty
== Taarray || t1
.ty
== Tarray
))
3431 return convert(e2
, t1
);
3432 if (t1
.ty
== Tnull
&& (t2
.ty
== Tpointer || t2
.ty
== Taarray || t2
.ty
== Tarray
))
3433 return convert(e1
, t2
);
3435 /// Covers array operations for user-defined types
3436 Type
checkArrayOpType(Expression e1
, Expression e2
, EXP op
, Scope
*sc
)
3438 // scalar op scalar - we shouldn't be here
3439 if (e1
.type
.ty
!= Tarray
&& e1
.type
.ty
!= Tsarray
&& e2
.type
.ty
!= Tarray
&& e2
.type
.ty
!= Tsarray
)
3442 // only supporting slices and array literals
3443 if (!e1
.isSliceExp() && !e1
.isArrayLiteralExp() && !e2
.isSliceExp() && !e2
.isArrayLiteralExp())
3446 // start with e1 op e2 and if either one of e1 or e2 is a slice or array literal,
3447 // replace it with the first element of the array
3448 Expression lhs
= e1
;
3449 Expression rhs
= e2
;
3452 if (auto se1
= e1
.isSliceExp())
3453 lhs
= new IndexExp(Loc
.initial
, se1
.e1
, IntegerExp
.literal
!0);
3455 // [t1, t2, .. t3] op ?
3456 if (auto ale1
= e1
.isArrayLiteralExp())
3457 lhs
= ale1
.opIndex(0);
3460 if (auto se2
= e2
.isSliceExp())
3461 rhs
= new IndexExp(Loc
.initial
, se2
.e1
, IntegerExp
.literal
!0);
3463 // ? op [u1, u2, .. u3]
3464 if (auto ale2
= e2
.isArrayLiteralExp())
3465 rhs
= ale2
.opIndex(0);
3467 // create a new binary expression with the new lhs and rhs (at this stage, at least
3468 // one of lhs/rhs has been replaced with the 0'th element of the array it was before)
3473 exp
= new AddExp(Loc
.initial
, lhs
, rhs
); break;
3475 exp
= new MinExp(Loc
.initial
, lhs
, rhs
); break;
3477 exp
= new MulExp(Loc
.initial
, lhs
, rhs
); break;
3479 exp
= new DivExp(Loc
.initial
, lhs
, rhs
); break;
3481 exp
= new PowExp(Loc
.initial
, lhs
, rhs
); break;
3488 // if T op U is valid and has type V
3489 // then T[] op U and T op U[] should be valid and have type V[]
3490 Expression e
= exp
.trySemantic(sc
);
3492 return e
.type
.arrayOf
;
3498 if (t1
.ty
== Tarray
&& isBinArrayOp(op
) && isArrayOpOperand(e1
))
3500 if (e2
.implicitConvTo(t1
.nextOf()))
3504 e2
= e2
.castTo(sc
, t1
.nextOf());
3505 return Lret(t1
.nextOf().arrayOf());
3507 if (t1
.nextOf().implicitConvTo(e2
.type
))
3509 // (cast(T)U)[] op T (https://issues.dlang.org/show_bug.cgi?id=12780)
3510 // e1 is left as U[], it will be handled in arrayOp() later.
3511 return Lret(e2
.type
.arrayOf());
3513 if (t2
.ty
== Tarray
&& isArrayOpOperand(e2
))
3515 if (t1
.nextOf().implicitConvTo(t2
.nextOf()))
3517 // (cast(T)U)[] op T[] (https://issues.dlang.org/show_bug.cgi?id=12780)
3518 t
= t2
.nextOf().arrayOf();
3519 // if cast won't be handled in arrayOp() later
3520 if (!isArrayOpImplicitCast(t1
.isTypeDArray(), t2
.isTypeDArray()))
3521 e1
= e1
.castTo(sc
, t
);
3524 if (t2
.nextOf().implicitConvTo(t1
.nextOf()))
3526 // T[] op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780)
3527 // e2 is left as U[], it will be handled in arrayOp() later.
3528 t
= t1
.nextOf().arrayOf();
3529 // if cast won't be handled in arrayOp() later
3530 if (!isArrayOpImplicitCast(t2
.isTypeDArray(), t1
.isTypeDArray()))
3531 e2
= e2
.castTo(sc
, t
);
3536 t
= checkArrayOpType(e1
, e2
, op
, sc
);
3542 else if (t2
.ty
== Tarray
&& isBinArrayOp(op
) && isArrayOpOperand(e2
))
3544 if (e1
.implicitConvTo(t2
.nextOf()))
3548 e1
= e1
.castTo(sc
, t2
.nextOf());
3549 t
= t2
.nextOf().arrayOf();
3551 else if (t2
.nextOf().implicitConvTo(e1
.type
))
3553 // T op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780)
3554 // e2 is left as U[], it will be handled in arrayOp() later.
3555 t
= e1
.type
.arrayOf();
3559 t
= checkArrayOpType(e1
, e2
, op
, sc
);
3564 //printf("test %s\n", EXPtoString(op).ptr);
3565 e1
= e1
.optimize(WANTvalue
);
3566 if (isCommutative(op
) && e1
.isConst())
3568 /* Swap operands to minimize number of functions generated
3570 //printf("swap %s\n", EXPtoString(op).ptr);
3571 Expression tmp
= e1
;
3581 /************************************
3582 * Bring leaves to common type.
3584 * null on success, ErrorExp if error occurs
3586 Expression
typeCombine(BinExp be
, Scope
* sc
)
3588 Expression
errorReturn()
3590 Expression ex
= be
.incompatibleTypes();
3591 if (ex
.op
== EXP
.error
)
3593 return ErrorExp
.get();
3596 Type t1
= be
.e1
.type
.toBasetype();
3597 Type t2
= be
.e2
.type
.toBasetype();
3599 if (be
.op
== EXP
.min || be
.op
== EXP
.add)
3601 // struct+struct, and class+class are errors
3602 if (t1
.ty
== Tstruct
&& t2
.ty
== Tstruct
)
3603 return errorReturn();
3604 else if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
3605 return errorReturn();
3606 else if (t1
.ty
== Taarray
&& t2
.ty
== Taarray
)
3607 return errorReturn();
3610 if (auto result
= typeMerge(sc
, be
.op
, be
.e1
, be
.e2
))
3612 if (be
.type
is null)
3616 return errorReturn();
3618 // If the types have no value, return an error
3619 if (be
.e1
.op
== EXP
.error
)
3621 if (be
.e2
.op
== EXP
.error
)
3626 /***********************************
3627 * Do integral promotions (convertchk).
3628 * Don't convert <array of> to <pointer to>
3630 Expression
integralPromotions(Expression e
, Scope
* sc
)
3632 //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars());
3633 switch (e
.type
.toBasetype().ty
)
3636 error(e
.loc
, "void has no value");
3637 return ErrorExp
.get();
3646 e
= e
.castTo(sc
, Type
.tint32
);
3650 e
= e
.castTo(sc
, Type
.tuns32
);
3659 /******************************************************
3660 * This provides a transition from the non-promoting behavior
3661 * of unary + - ~ to the C-like integral promotion behavior.
3664 * ue = NegExp, UAddExp, or ComExp which is revised per rules
3666 * https://issues.dlang.org/show_bug.cgi?id=16997
3669 void fix16997(Scope
* sc
, UnaExp ue
)
3671 if (global
.params
.fix16997 || sc
.flags
& SCOPE
.Cfile
)
3672 ue
.e1
= integralPromotions(ue
.e1
, sc
); // desired C-like behavor
3675 switch (ue
.e1
.type
.toBasetype
.ty
)
3681 //case Tbool: // these operations aren't allowed on bool anyway
3685 deprecation(ue
.loc
, "integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`",
3686 ue
.toChars(), EXPtoString(ue
.op
).ptr
, ue
.e1
.toChars());
3695 /***********************************
3696 * See if both types are arrays that can be compared
3697 * for equality without any casting. Return true if so.
3698 * This is to enable comparing things like an immutable
3699 * array with a mutable one.
3701 extern (D
) bool arrayTypeCompatibleWithoutCasting(Type t1
, Type t2
)
3703 t1
= t1
.toBasetype();
3704 t2
= t2
.toBasetype();
3706 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray || t1
.ty
== Tpointer
) && t2
.ty
== t1
.ty
)
3708 if (t1
.nextOf().implicitConvTo(t2
.nextOf()) >= MATCH
.constant || t2
.nextOf().implicitConvTo(t1
.nextOf()) >= MATCH
.constant
)
3714 /******************************************************************/
3715 /* Determine the integral ranges of an expression.
3716 * This is used to determine if implicit narrowing conversions will
3720 IntRange
getIntRange(Expression e
)
3722 IntRange
visit(Expression e
)
3724 return IntRange
.fromType(e
.type
);
3727 IntRange
visitInteger(IntegerExp e
)
3729 return IntRange(SignExtendedNumber(e
.getInteger()))._cast(e
.type
);
3732 IntRange
visitCast(CastExp e
)
3734 return getIntRange(e
.e1
)._cast(e
.type
);
3737 IntRange
visitAdd(AddExp e
)
3739 IntRange ir1
= getIntRange(e
.e1
);
3740 IntRange ir2
= getIntRange(e
.e2
);
3741 return (ir1
+ ir2
)._cast(e
.type
);
3744 IntRange
visitMin(MinExp e
)
3746 IntRange ir1
= getIntRange(e
.e1
);
3747 IntRange ir2
= getIntRange(e
.e2
);
3748 return (ir1
- ir2
)._cast(e
.type
);
3751 IntRange
visitDiv(DivExp e
)
3753 IntRange ir1
= getIntRange(e
.e1
);
3754 IntRange ir2
= getIntRange(e
.e2
);
3756 return (ir1
/ ir2
)._cast(e
.type
);
3759 IntRange
visitMul(MulExp e
)
3761 IntRange ir1
= getIntRange(e
.e1
);
3762 IntRange ir2
= getIntRange(e
.e2
);
3764 return (ir1
* ir2
)._cast(e
.type
);
3767 IntRange
visitMod(ModExp e
)
3769 IntRange ir1
= getIntRange(e
.e1
);
3770 IntRange ir2
= getIntRange(e
.e2
);
3772 // Modding on 0 is invalid anyway.
3773 if (!ir2
.absNeg().imin
.negative
)
3777 return (ir1
% ir2
)._cast(e
.type
);
3780 IntRange
visitAnd(AndExp e
)
3783 bool hasResult
= false;
3784 result
.unionOrAssign(getIntRange(e
.e1
) & getIntRange(e
.e2
), hasResult
);
3787 return result
._cast(e
.type
);
3790 IntRange
visitOr(OrExp e
)
3793 bool hasResult
= false;
3794 result
.unionOrAssign(getIntRange(e
.e1
) |
getIntRange(e
.e2
), hasResult
);
3797 return result
._cast(e
.type
);
3800 IntRange
visitXor(XorExp e
)
3803 bool hasResult
= false;
3804 result
.unionOrAssign(getIntRange(e
.e1
) ^
getIntRange(e
.e2
), hasResult
);
3807 return result
._cast(e
.type
);
3810 IntRange
visitShl(ShlExp e
)
3812 IntRange ir1
= getIntRange(e
.e1
);
3813 IntRange ir2
= getIntRange(e
.e2
);
3815 return (ir1
<< ir2
)._cast(e
.type
);
3818 IntRange
visitShr(ShrExp e
)
3820 IntRange ir1
= getIntRange(e
.e1
);
3821 IntRange ir2
= getIntRange(e
.e2
);
3823 return (ir1
>> ir2
)._cast(e
.type
);
3826 IntRange
visitUshr(UshrExp e
)
3828 IntRange ir1
= getIntRange(e
.e1
).castUnsigned(e
.e1
.type
);
3829 IntRange ir2
= getIntRange(e
.e2
);
3831 return (ir1
>>> ir2
)._cast(e
.type
);
3834 IntRange
visitAssign(AssignExp e
)
3836 return getIntRange(e
.e2
)._cast(e
.type
);
3839 IntRange
visitCond(CondExp e
)
3841 // No need to check e.econd; assume caller has called optimize()
3842 IntRange ir1
= getIntRange(e
.e1
);
3843 IntRange ir2
= getIntRange(e
.e2
);
3844 return ir1
.unionWith(ir2
)._cast(e
.type
);
3847 IntRange
visitVar(VarExp e
)
3850 VarDeclaration vd
= e
.var
.isVarDeclaration();
3852 return vd
.range
._cast(e
.type
);
3853 else if (vd
&& vd
._init
&& !vd
.type
.isMutable() && (ie
= vd
.getConstInitializer()) !is null)
3854 return getIntRange(ie
);
3859 IntRange
visitComma(CommaExp e
)
3861 return getIntRange(e
.e2
);
3864 IntRange
visitCom(ComExp e
)
3866 IntRange ir
= getIntRange(e
.e1
);
3867 return IntRange(SignExtendedNumber(~ir
.imax
.value
, !ir
.imax
.negative
), SignExtendedNumber(~ir
.imin
.value
, !ir
.imin
.negative
))._cast(e
.type
);
3870 IntRange
visitNeg(NegExp e
)
3872 IntRange ir
= getIntRange(e
.e1
);
3873 return (-ir
)._cast(e
.type
);
3878 default : return visit(e
);
3879 case EXP
.int64
: return visitInteger(e
.isIntegerExp());
3880 case EXP
.cast_
: return visitCast(e
.isCastExp());
3881 case EXP
.add : return visitAdd(e
.isAddExp());
3882 case EXP
.min
: return visitMin(e
.isMinExp());
3883 case EXP
.div : return visitDiv(e
.isDivExp());
3884 case EXP
.mul : return visitMul(e
.isMulExp());
3885 case EXP
.mod
: return visitMod(e
.isModExp());
3886 case EXP
.and : return visitAnd(e
.isAndExp());
3887 case EXP
.or : return visitOr(e
.isOrExp());
3888 case EXP
.xor : return visitXor(e
.isXorExp());
3889 case EXP
.leftShift
: return visitShl(e
.isShlExp());
3890 case EXP
.rightShift
: return visitShr(e
.isShrExp());
3891 case EXP
.unsignedRightShift
: return visitUshr(e
.isUshrExp());
3892 case EXP
.blit
: return visitAssign(e
.isBlitExp());
3893 case EXP
.construct
: return visitAssign(e
.isConstructExp());
3894 case EXP
.assign
: return visitAssign(e
.isAssignExp());
3895 case EXP
.question
: return visitCond(e
.isCondExp());
3896 case EXP
.variable
: return visitVar(e
.isVarExp());
3897 case EXP
.comma
: return visitComma(e
.isCommaExp());
3898 case EXP
.tilde
: return visitCom(e
.isComExp());
3899 case EXP
.negate
: return visitNeg(e
.isNegExp());
3903 * A helper function to "cast" from expressions of type noreturn to
3904 * any other type - noreturn is implicitly convertible to any other type.
3905 * However, the dmd backend does not like a naive cast from a noreturn expression
3906 * (particularly an `assert(0)`) so this function generates:
3908 * `(assert(0), value)` instead of `cast(to)(assert(0))`.
3910 * `value` is currently `to.init` however it cannot be read so could be made simpler.
3912 * toBeCasted = Expression of type noreturn to cast
3913 * to = Type to cast the expression to.
3914 * Returns: A CommaExp, upon any failure ErrorExp will be returned.
3916 Expression
specialNoreturnCast(Expression toBeCasted
, Type to
)
3918 return Expression
.combine(toBeCasted
, to
.defaultInitLiteral(toBeCasted
.loc
));