Skip to content

Commit e0b4ec6

Browse files
committed
Add logic to decipher floating point implicit and explicit casts.
Logic is consistent with dmd with the exception that dmd seems to allow some casts *to* void which are not yet accounted for (if ever) Unit tests have been added.
1 parent aa64387 commit e0b4ec6

File tree

1 file changed

+116
-2
lines changed

1 file changed

+116
-2
lines changed

src/d/semantic/caster.d

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,9 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
299299
return CastKind.UPad;
300300
}
301301

302-
return CastKind.Invalid;
302+
return isFloat(bt)
303+
? CastKind.UnsignedToFloat
304+
: CastKind.Invalid;
303305

304306
case Char:
305307
t = integralOfChar(t);
@@ -319,6 +321,12 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
319321
return CastKind.IntToBool;
320322
}
321323

324+
if (isFloat(bt)) {
325+
return isSigned(t)
326+
? CastKind.SignedToFloat
327+
: CastKind.UnsignedToFloat;
328+
}
329+
322330
if (!isIntegral(bt)) {
323331
return CastKind.Invalid;
324332
}
@@ -336,7 +344,23 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
336344
}
337345

338346
case Float, Double, Real:
339-
assert(0, "Floating point casts are not implemented");
347+
// cast from a float to a float
348+
if (isFloat(bt)) {
349+
assert(bt != t);
350+
return bt < t ? CastKind.FloatTrunc : CastKind.FloatExtend;
351+
}
352+
353+
if (isExplicit) {
354+
if (isIntegral(bt) && canConvertToIntegral(bt)) {
355+
return isSigned(isChar(bt) ? integralOfChar(bt) : bt)
356+
? CastKind.FloatToSigned
357+
: CastKind.FloatToUnsigned;
358+
} else {
359+
return CastKind.Invalid;
360+
}
361+
} else {
362+
return bailout(t);
363+
}
340364

341365
case Null:
342366
return CastKind.Invalid;
@@ -650,3 +674,93 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
650674
return CastKind.Invalid;
651675
}
652676
}
677+
678+
version(unittest) {
679+
BuiltinType[] floatTypes =
680+
[BuiltinType.Float, BuiltinType.Double, BuiltinType.Real];
681+
BuiltinType[] signedTypes =
682+
[BuiltinType.Byte, BuiltinType.Short, BuiltinType.Int, BuiltinType.Long,
683+
BuiltinType.Cent];
684+
BuiltinType[] unsignedTypes =
685+
[BuiltinType.Ubyte, BuiltinType.Ushort, BuiltinType.Uint,
686+
BuiltinType.Ulong, BuiltinType.Ucent];
687+
void checkCastKind(
688+
const BuiltinType from,
689+
const BuiltinType to,
690+
const CastKind explicitShouldBe,
691+
const CastKind implicitShouldBe
692+
) {
693+
Type fromAsType = Type.get(from);
694+
Type toAsType = Type.get(to);
695+
import std.format : format;
696+
const explicitResult = explicitCastFrom(null, fromAsType, toAsType);
697+
assert(
698+
explicitResult == explicitShouldBe,
699+
format("Explicit cast yielded `%s`, when `%s` was expected",
700+
explicitResult, explicitShouldBe)
701+
);
702+
const implicitResult = implicitCastFrom(null, fromAsType, toAsType);
703+
assert(
704+
implicitResult == implicitShouldBe,
705+
format("Implicit cast yielded `%s`, when `%s` was expected",
706+
implicitResult, implicitShouldBe)
707+
);
708+
}
709+
}
710+
711+
@("Float to float casts")
712+
unittest {
713+
foreach (from; floatTypes)
714+
foreach (to; floatTypes) {
715+
const shouldBe = from == to
716+
? CastKind.Exact
717+
: (from < to ? CastKind.FloatExtend : CastKind.FloatTrunc);
718+
checkCastKind(from, to, shouldBe, shouldBe);
719+
}
720+
}
721+
722+
@("Bools can be casted to floats")
723+
unittest {
724+
foreach (to; floatTypes) {
725+
checkCastKind(BuiltinType.Bool, to, CastKind.UnsignedToFloat,
726+
CastKind.UnsignedToFloat);
727+
}
728+
}
729+
730+
@("Signed types can be casted to floats")
731+
unittest {
732+
foreach (from; signedTypes) {
733+
foreach (to; floatTypes) {
734+
checkCastKind(from, to, CastKind.SignedToFloat,
735+
CastKind.SignedToFloat);
736+
}
737+
}
738+
}
739+
740+
@("Unsigned types can be casted to floats")
741+
unittest {
742+
foreach (from; unsignedTypes) {
743+
foreach (to; floatTypes) {
744+
checkCastKind(from, to, CastKind.UnsignedToFloat,
745+
CastKind.UnsignedToFloat);
746+
}
747+
}
748+
}
749+
750+
@("Float casts to signed types")
751+
unittest {
752+
foreach (from; floatTypes) {
753+
foreach (to; signedTypes) {
754+
checkCastKind(from, to, CastKind.FloatToSigned, CastKind.Invalid);
755+
}
756+
}
757+
}
758+
759+
@("Float casts to unsigned types")
760+
unittest {
761+
foreach (from; floatTypes) {
762+
foreach (to; unsignedTypes) {
763+
checkCastKind(from, to, CastKind.FloatToUnsigned, CastKind.Invalid);
764+
}
765+
}
766+
}

0 commit comments

Comments
 (0)