Skip to content

Commit a42588d

Browse files
SethTisuedwijnand
andcommitted
Warn on lossy conversion of literals & constants
Co-authored-by: Dale Wijnand <[email protected]>
1 parent 29f0374 commit a42588d

File tree

5 files changed

+62
-2
lines changed

5 files changed

+62
-2
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID]:
174174
OverrideTypeMismatchErrorID,
175175
OverrideErrorID,
176176
MatchableWarningID,
177-
CannotExtendFunctionID
177+
CannotExtendFunctionID,
178+
LossyWideningConstantConversionID
178179

179180
def errorNumber = ordinal - 2
180181

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,13 @@ import transform.SymUtils._
807807
|"""
808808
}
809809

810+
class LossyWideningConstantConversion(sourceType: Type, targetType: Type)(using Context)
811+
extends Message(LossyWideningConstantConversionID):
812+
def kind = "Lossy Conversion"
813+
def msg = em"""|Widening conversion from $sourceType to $targetType loses precision.
814+
|Write `.to$targetType` instead.""".stripMargin
815+
def explain = ""
816+
810817
class PatternMatchExhaustivity(uncoveredFn: => String, hasMore: Boolean)(using Context)
811818
extends Message(PatternMatchExhaustivityID) {
812819
def kind = "Pattern Match Exhaustivity"

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,11 @@ class Typer extends Namer
719719
else if (target.isRef(defn.FloatClass))
720720
tree.kind match {
721721
case Whole(16) => // cant parse hex literal as float
722-
case _ => return lit(floatFromDigits(digits))
722+
case _ =>
723+
val float = floatFromDigits(digits)
724+
if digits.toIntOption.exists(_ != float.toInt) then
725+
report.warning(LossyWideningConstantConversion(defn.IntType, target), tree.srcPos)
726+
return lit(float)
723727
}
724728
else if (target.isRef(defn.DoubleClass))
725729
tree.kind match {
@@ -3733,6 +3737,12 @@ class Typer extends Namer
37333737
case ConstantType(x) =>
37343738
val converted = x.convertTo(pt)
37353739
if converted != null && (converted ne x) then
3740+
val cls = pt.classSymbol
3741+
if x.tag == IntTag && cls == defn.FloatClass && x.intValue.toFloat.toInt != x.intValue
3742+
|| x.tag == LongTag && cls == defn.FloatClass && x.longValue.toFloat.toLong != x.longValue
3743+
|| x.tag == LongTag && cls == defn.DoubleClass && x.longValue.toDouble.toLong != x.longValue
3744+
then
3745+
report.warning(LossyWideningConstantConversion(x.tpe, pt), tree.srcPos)
37363746
return adaptConstant(tree, ConstantType(converted))
37373747
case _ =>
37383748

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:2:19 -------------------------------
2+
2 | val f1: Float = 123456789 // error
3+
| ^^^^^^^^^
4+
| Widening conversion from Int to Float loses precision.
5+
| Write `.toFloat` instead.
6+
-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:3:19 -------------------------------
7+
3 | val d1: Double = 1234567890123456789L // error
8+
| ^^^^^^^^^^^^^^^^^^^^
9+
| Widening conversion from Long to Double loses precision.
10+
| Write `.toDouble` instead.
11+
-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:4:19 -------------------------------
12+
4 | val f2: Float = 123456789L // error
13+
| ^^^^^^^^^^
14+
| Widening conversion from Long to Float loses precision.
15+
| Write `.toFloat` instead.
16+
-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:10:21 ------------------------------
17+
10 | val f1_b: Float = i1 // error
18+
| ^^
19+
| Widening conversion from Int to Float loses precision.
20+
| Write `.toFloat` instead.
21+
-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:11:21 ------------------------------
22+
11 | val d1_b: Double = l1 // error
23+
| ^^
24+
| Widening conversion from Long to Double loses precision.
25+
| Write `.toDouble` instead.
26+
-- [E167] Lossy Conversion Error: tests/neg-custom-args/fatal-warnings/i11333.scala:12:21 ------------------------------
27+
12 | val f2_b: Float = l2 // error
28+
| ^^
29+
| Widening conversion from Long to Float loses precision.
30+
| Write `.toFloat` instead.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class C:
2+
val f1: Float = 123456789 // error
3+
val d1: Double = 1234567890123456789L // error
4+
val f2: Float = 123456789L // error
5+
6+
inline val i1 = 123456789
7+
inline val l1 = 1234567890123456789L
8+
inline val l2 = 123456789L
9+
10+
val f1_b: Float = i1 // error
11+
val d1_b: Double = l1 // error
12+
val f2_b: Float = l2 // error

0 commit comments

Comments
 (0)