Skip to content

Commit cff1907

Browse files
committed
Forward port lint 1l and getNumber tweak
An additional message is emitted on `0_x` because it asks to continue, but that is helpful.
1 parent e46e2e7 commit cff1907

File tree

3 files changed

+41
-32
lines changed

3 files changed

+41
-32
lines changed

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import config.Feature.migrateTo3
2121
import config.SourceVersion.`3.0`
2222
import reporting.{NoProfile, Profile}
2323

24+
import java.lang.Character.isDigit
25+
2426
object Scanners {
2527

2628
/** Offset into source character array */
@@ -152,9 +154,9 @@ object Scanners {
152154
strVal = litBuf.toString
153155
litBuf.clear()
154156

155-
@inline def isNumberSeparator(c: Char): Boolean = c == '_'
157+
inline def isNumberSeparator(c: Char): Boolean = c == '_'
156158

157-
@inline def removeNumberSeparators(s: String): String = if (s.indexOf('_') == -1) s else s.replace("_", "")
159+
inline def removeNumberSeparators(s: String): String = if s.indexOf('_') == -1 then s else s.replace("_", "")
158160

159161
// disallow trailing numeric separator char, but continue lexing
160162
def checkNoTrailingSeparator(): Unit =
@@ -887,7 +889,7 @@ object Scanners {
887889
//case 'b' | 'B' => base = 2 ; nextChar()
888890
case _ => base = 10 ; putChar('0')
889891
}
890-
if (base != 10 && !isNumberSeparator(ch) && digit2int(ch, base) < 0)
892+
if base != 10 && !isNumberSeparator(ch) && digit2int(ch, base) < 0 then
891893
error("invalid literal number")
892894
}
893895
fetchLeadingZero()
@@ -967,7 +969,7 @@ object Scanners {
967969
case '.' =>
968970
nextChar()
969971
if ('0' <= ch && ch <= '9') {
970-
putChar('.'); getFraction(); setStrVal()
972+
putChar('.'); getFraction()
971973
}
972974
else
973975
token = DOT
@@ -1427,7 +1429,7 @@ object Scanners {
14271429
/** read fractional part and exponent of floating point number
14281430
* if one is present.
14291431
*/
1430-
protected def getFraction(): Unit = {
1432+
protected def getFraction(): Unit =
14311433
token = DECILIT
14321434
while ('0' <= ch && ch <= '9' || isNumberSeparator(ch)) {
14331435
putChar(ch)
@@ -1465,41 +1467,44 @@ object Scanners {
14651467
token = FLOATLIT
14661468
}
14671469
checkNoLetter()
1468-
}
1470+
setStrVal()
1471+
end getFraction
14691472
def checkNoLetter(): Unit =
14701473
if (isIdentifierPart(ch) && ch >= ' ')
14711474
error("Invalid literal number")
14721475

14731476
/** Read a number into strVal and set base
14741477
*/
1475-
protected def getNumber(): Unit = {
1476-
while (isNumberSeparator(ch) || digit2int(ch, base) >= 0) {
1477-
putChar(ch)
1478-
nextChar()
1479-
}
1480-
checkNoTrailingSeparator()
1481-
token = INTLIT
1482-
if (base == 10 && ch == '.') {
1483-
val lch = lookaheadChar()
1484-
if ('0' <= lch && lch <= '9') {
1485-
putChar('.')
1486-
nextChar()
1487-
getFraction()
1488-
}
1489-
}
1490-
else (ch: @switch) match {
1491-
case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' =>
1492-
if (base == 10) getFraction()
1493-
case 'l' | 'L' =>
1478+
protected def getNumber(): Unit =
1479+
def consumeDigits(): Unit =
1480+
while isNumberSeparator(ch) || digit2int(ch, base) >= 0 do
1481+
putChar(ch)
14941482
nextChar()
1495-
token = LONGLIT
1496-
case _ =>
1497-
}
1483+
// at dot with digit following
1484+
def restOfNonIntegralNumber(): Unit =
1485+
putChar('.')
1486+
nextChar()
1487+
getFraction()
1488+
// 1l is an acknowledged bad practice
1489+
def lintel(): Unit =
1490+
if ch == 'l' then
1491+
val msg = "Lowercase el for long is not recommended because it is easy to confuse with numeral 1; use uppercase L instead"
1492+
report.deprecationWarning(msg, sourcePos(offset + litBuf.length))
1493+
// after int: 5e7f, 42L, 42.toDouble but not 42b.
1494+
def restOfNumber(): Unit =
1495+
ch match
1496+
case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' => getFraction()
1497+
case 'l' | 'L' => lintel() ; token = LONGLIT ; setStrVal() ; nextChar()
1498+
case _ => token = INTLIT ; setStrVal() ; checkNoLetter()
1499+
1500+
// consume leading digits
1501+
consumeDigits()
14981502

14991503
checkNoTrailingSeparator()
15001504

1501-
setStrVal()
1502-
}
1505+
val detectedFloat: Boolean = base == 10 && ch == '.' && isDigit(lookaheadChar())
1506+
if detectedFloat then restOfNonIntegralNumber() else restOfNumber()
1507+
end getNumber
15031508

15041509
private def finishCharLit(): Unit = {
15051510
nextChar()

tests/neg/t6124.check

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,13 @@
4343
| ^
4444
| trailing separator is not allowed
4545
-- Error: tests/neg/t6124.scala:24:12 ----------------------------------------------------------------------------------
46-
24 | val x5 = 0_x52 // error
46+
24 | val x5 = 0_x52 // error // error
4747
| ^
4848
| trailing separator is not allowed
49+
-- Error: tests/neg/t6124.scala:24:11 ----------------------------------------------------------------------------------
50+
24 | val x5 = 0_x52 // error // error
51+
| ^
52+
| Invalid literal number
4953
-- Error: tests/neg/t6124.scala:26:13 ----------------------------------------------------------------------------------
5054
26 | val x8 = 0x52_ // error
5155
| ^

tests/neg/t6124.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ trait T {
2121
val x1 = _52 // error
2222
val x3 = 52_ // error
2323

24-
val x5 = 0_x52 // error
24+
val x5 = 0_x52 // error // error
2525
val x6 = 0x_52
2626
val x8 = 0x52_ // error
2727
val x9 = 0_52

0 commit comments

Comments
 (0)