From e88a7cb3d5c18a450ea5e6d3f652b6a393497b7f Mon Sep 17 00:00:00 2001 From: Fabian Page Date: Wed, 26 Feb 2020 13:28:40 +0100 Subject: [PATCH] Deprecate numeric widening of Numeric Literals which are not representable with Float/Double --- .../scala/reflect/internal/Constants.scala | 9 ++++++--- test/files/neg/deprecated_widening.check | 20 ++++++++++++++++++- test/files/neg/deprecated_widening.scala | 15 ++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/reflect/scala/reflect/internal/Constants.scala b/src/reflect/scala/reflect/internal/Constants.scala index ae50e1ef913f..c95cafb8f9d4 100644 --- a/src/reflect/scala/reflect/internal/Constants.scala +++ b/src/reflect/scala/reflect/internal/Constants.scala @@ -63,7 +63,10 @@ trait Constants extends api.Constants { def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue def isIntRange: Boolean = ByteTag <= tag && tag <= IntTag def isLongRange: Boolean = ByteTag <= tag && tag <= LongTag - def isFloatRange: Boolean = ByteTag <= tag && tag <= FloatTag + // Float has a Fraction of 23 Bits + 1 implicit leading Bit so the total precision is 24 Bit (see https://en.wikipedia.org/wiki/Single-precision_floating-point_format) + def isFloatRepresentable: Boolean = ByteTag <= tag && tag <= FloatTag && (tag != IntTag && tag != LongTag || longValue <= (1L << 24) && longValue >= -(1L << 24)) + // Double has a Fraction of 53 Bits + 1 implicit leading Bit => 54 Bit + def isDoubleRepresentable: Boolean = ByteTag <= tag && tag <= DoubleTag && (tag != LongTag || longValue <= (1L << 54) && longValue >= -(1L << 54)) def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag def isNonUnitAnyVal = BooleanTag <= tag && tag <= DoubleTag def isSuitableLiteralType = BooleanTag <= tag && tag <= NullTag @@ -218,9 +221,9 @@ trait Constants extends api.Constants { Constant(intValue) else if (target == LongClass && isLongRange) Constant(longValue) - else if (target == FloatClass && isFloatRange) + else if (target == FloatClass && isFloatRepresentable) Constant(floatValue) - else if (target == DoubleClass && isNumeric) + else if (target == DoubleClass && isDoubleRepresentable) Constant(doubleValue) else null diff --git a/test/files/neg/deprecated_widening.check b/test/files/neg/deprecated_widening.check index 262de21ada6d..c25c6d3cd612 100644 --- a/test/files/neg/deprecated_widening.check +++ b/test/files/neg/deprecated_widening.check @@ -7,6 +7,24 @@ deprecated_widening.scala:7: warning: Automatic conversion from Long to Float is deprecated_widening.scala:8: warning: Automatic conversion from Long to Double is deprecated (since 2.13.1) because it loses precision. Write `.toDouble` instead. val l_d: Double = l // deprecated ^ +deprecated_widening.scala:23: warning: Automatic conversion from Long to Float is deprecated (since 2.13.1) because it loses precision. Write `.toFloat` instead. + val truncatedPosFloat:Float = 16777217L // deprecated + ^ +deprecated_widening.scala:25: warning: Automatic conversion from Long to Float is deprecated (since 2.13.1) because it loses precision. Write `.toFloat` instead. + val truncatedNegFloat: Float = - 16777217L // deprecated + ^ +deprecated_widening.scala:28: warning: Automatic conversion from Int to Float is deprecated (since 2.13.1) because it loses precision. Write `.toFloat` instead. + val truncatedPosFloatI:Float = 16777217 // deprecated + ^ +deprecated_widening.scala:30: warning: Automatic conversion from Int to Float is deprecated (since 2.13.1) because it loses precision. Write `.toFloat` instead. + val truncatedNegFloatI: Float = - 16777217 // deprecated + ^ +deprecated_widening.scala:33: warning: Automatic conversion from Long to Double is deprecated (since 2.13.1) because it loses precision. Write `.toDouble` instead. + val truncatedPosDouble:Double = 18014398509481985L // deprecated + ^ +deprecated_widening.scala:35: warning: Automatic conversion from Long to Double is deprecated (since 2.13.1) because it loses precision. Write `.toDouble` instead. + val truncatedNegDouble: Double = - 18014398509481985L // deprecated + ^ deprecated_widening.scala:12: warning: method int2float in object Int is deprecated (since 2.13.1): Implicit conversion from Int to Float is dangerous because it loses precision. Write `.toFloat` instead. implicitly[Int => Float] // deprecated ^ @@ -17,5 +35,5 @@ deprecated_widening.scala:15: warning: method long2double in object Long is depr implicitly[Long => Double] // deprecated ^ error: No warnings can be incurred under -Werror. -6 warnings +12 warnings 1 error diff --git a/test/files/neg/deprecated_widening.scala b/test/files/neg/deprecated_widening.scala index 7fdd288a89ff..0da49396e740 100644 --- a/test/files/neg/deprecated_widening.scala +++ b/test/files/neg/deprecated_widening.scala @@ -18,4 +18,19 @@ object Test { // don't leak silent warning from float conversion val n = 42 def clean = n max 27 + + val posFloat:Float = 16777216L // OK + val truncatedPosFloat:Float = 16777217L // deprecated + val negFloat: Float = - 16777216L // OK + val truncatedNegFloat: Float = - 16777217L // deprecated + + val posFloatI:Float = 16777216 // OK + val truncatedPosFloatI:Float = 16777217 // deprecated + val negFloatI: Float = - 16777216 // OK + val truncatedNegFloatI: Float = - 16777217 // deprecated + + val posDouble:Double = 18014398509481984L// OK + val truncatedPosDouble:Double = 18014398509481985L // deprecated + val negDouble: Double = - 18014398509481984L // OK + val truncatedNegDouble: Double = - 18014398509481985L // deprecated }