Skip to content

Commit

Permalink
Add logic to decipher floating point implicit and explicit casts.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
maxhaton committed Feb 26, 2023
1 parent 03fa0f9 commit 64abded
Showing 1 changed file with 121 additions and 2 deletions.
123 changes: 121 additions & 2 deletions src/d/semantic/caster.d
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
return CastKind.UPad;
}

return CastKind.Invalid;
t = Ubyte;
goto case Byte;

case Char:
t = integralOfChar(t);
Expand All @@ -319,6 +320,12 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
return CastKind.IntToBool;
}

if (isFloat(bt)) {
return isSigned(t)
? CastKind.SignedToFloat
: CastKind.UnsignedToFloat;
}

if (!isIntegral(bt)) {
return CastKind.Invalid;
}
Expand All @@ -336,7 +343,26 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
}

case Float, Double, Real:
assert(0, "Floating point casts are not implemented");
// cast from a float to a float
if (isFloat(bt)) {
assert(bt != t);
return bt < t ? CastKind.FloatTrunc : CastKind.FloatExtend;
}

if (isExplicit) {
if (isIntegral(bt) || canConvertToIntegral(bt)) {
const equivalentIntegral =
isChar(bt) ? integralOfChar(bt) : bt;
return isSigned(equivalentIntegral)
? CastKind.FloatToSigned
: CastKind.FloatToUnsigned;
} else {
// TODO: dmd considers a cast to void valid for some reason.
return CastKind.Invalid;
}
} else {
return bailout(t);
}

case Null:
return CastKind.Invalid;
Expand Down Expand Up @@ -650,3 +676,96 @@ struct Caster(bool isExplicit, alias bailoutOverride = null) {
return CastKind.Invalid;
}
}

@("Test implicit casts of floats to/from BasicTypes")
unittest {
import source.location;
with (BuiltinType) {
void assertCastKind(const CastKind ck, const CastKind shouldBe) {
if (ck != shouldBe) {
import std.format;
assert(
0,
format("Cast yielded `%s`, when `%s` was expected", ck,
shouldBe)
);
}
}

BuiltinType[] floatTypes = [Float, Double, Real];

// bool to float
foreach (floatType; floatTypes) {
Type from = Type.get(Bool);
Type to = Type.get(floatType);

const implicit = implicitCastFrom(null, from, to);
assertCastKind(implicit, CastKind.UnsignedToFloat);
}
// float to float casts
foreach (floatType; floatTypes) {
foreach (toThisFloat; floatTypes) {
Type from = Type.get(floatType);
Type to = Type.get(toThisFloat);

const implicit = implicitCastFrom(null, from, to);
with (CastKind) {
const shouldBe = floatType == toThisFloat
? Exact
: (floatType < toThisFloat ? FloatExtend : FloatTrunc);
assertCastKind(implicit, shouldBe);
}
}
}

BuiltinType[] signedCastToFloating = [Byte, Short, Int, Long, Cent];
BuiltinType[] unsignedCastToFloating =
[Ubyte, Ushort, Uint, Ulong, Ucent];

foreach (floatType; floatTypes) {
foreach (signed; signedCastToFloating) {
Type from = Type.get(signed);
Type to = Type.get(floatType);

const implicit = implicitCastFrom(null, from, to);
assertCastKind(implicit, CastKind.SignedToFloat);
}
}

foreach (floatType; floatTypes) {
foreach (unsigned; unsignedCastToFloating) {
Type from = Type.get(unsigned);
Type to = Type.get(floatType);

const implicit = implicitCastFrom(null, from, to);
assertCastKind(implicit, CastKind.UnsignedToFloat);
}
}

foreach (floatType; floatTypes) {
foreach (signed; signedCastToFloating) {
Type to = Type.get(signed);
Type from = Type.get(floatType);

const implicit = implicitCastFrom(null, from, to);
const explicit = explicitCastFrom(null, from, to);

assertCastKind(implicit, CastKind.Invalid);
assertCastKind(explicit, CastKind.FloatToSigned);
}
}

foreach (floatType; floatTypes) {
foreach (unsigned; unsignedCastToFloating) {
Type to = Type.get(unsigned);
Type from = Type.get(floatType);

const implicit = implicitCastFrom(null, from, to);
const explicit = explicitCastFrom(null, from, to);

assertCastKind(implicit, CastKind.Invalid);
assertCastKind(explicit, CastKind.FloatToUnsigned);
}
}
}
}

0 comments on commit 64abded

Please sign in to comment.