Skip to content

Commit 3be948b

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 a37cef8 commit 3be948b

File tree

3 files changed

+41
-32
lines changed

3 files changed

+41
-32
lines changed

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

+35-30
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import config.Feature
2020
import config.Feature.migrateTo3
2121
import config.SourceVersion.`3.0`
2222

23+
import java.lang.Character.isDigit
24+
2325
object Scanners {
2426

2527
/** Offset into source character array */
@@ -156,9 +158,9 @@ object Scanners {
156158
strVal = litBuf.toString
157159
litBuf.clear()
158160

159-
@inline def isNumberSeparator(c: Char): Boolean = c == '_'
161+
inline def isNumberSeparator(c: Char): Boolean = c == '_'
160162

161-
@inline def removeNumberSeparators(s: String): String = if (s.indexOf('_') == -1) s else s.replace("_", "")
163+
inline def removeNumberSeparators(s: String): String = if s.indexOf('_') == -1 then s else s.replace("_", "")
162164

163165
// disallow trailing numeric separator char, but continue lexing
164166
def checkNoTrailingSeparator(): Unit =
@@ -849,7 +851,7 @@ object Scanners {
849851
//case 'b' | 'B' => base = 2 ; nextChar()
850852
case _ => base = 10 ; putChar('0')
851853
}
852-
if (base != 10 && !isNumberSeparator(ch) && digit2int(ch, base) < 0)
854+
if base != 10 && !isNumberSeparator(ch) && digit2int(ch, base) < 0 then
853855
error("invalid literal number")
854856
}
855857
fetchLeadingZero()
@@ -929,7 +931,7 @@ object Scanners {
929931
case '.' =>
930932
nextChar()
931933
if ('0' <= ch && ch <= '9') {
932-
putChar('.'); getFraction(); setStrVal()
934+
putChar('.'); getFraction()
933935
}
934936
else
935937
token = DOT
@@ -1389,7 +1391,7 @@ object Scanners {
13891391
/** read fractional part and exponent of floating point number
13901392
* if one is present.
13911393
*/
1392-
protected def getFraction(): Unit = {
1394+
protected def getFraction(): Unit =
13931395
token = DECILIT
13941396
while ('0' <= ch && ch <= '9' || isNumberSeparator(ch)) {
13951397
putChar(ch)
@@ -1427,41 +1429,44 @@ object Scanners {
14271429
token = FLOATLIT
14281430
}
14291431
checkNoLetter()
1430-
}
1432+
setStrVal()
1433+
end getFraction
14311434
def checkNoLetter(): Unit =
14321435
if (isIdentifierPart(ch) && ch >= ' ')
14331436
error("Invalid literal number")
14341437

14351438
/** Read a number into strVal and set base
14361439
*/
1437-
protected def getNumber(): Unit = {
1438-
while (isNumberSeparator(ch) || digit2int(ch, base) >= 0) {
1439-
putChar(ch)
1440-
nextChar()
1441-
}
1442-
checkNoTrailingSeparator()
1443-
token = INTLIT
1444-
if (base == 10 && ch == '.') {
1445-
val lch = lookaheadChar()
1446-
if ('0' <= lch && lch <= '9') {
1447-
putChar('.')
1448-
nextChar()
1449-
getFraction()
1450-
}
1451-
}
1452-
else (ch: @switch) match {
1453-
case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' =>
1454-
if (base == 10) getFraction()
1455-
case 'l' | 'L' =>
1440+
protected def getNumber(): Unit =
1441+
def consumeDigits(): Unit =
1442+
while isNumberSeparator(ch) || digit2int(ch, base) >= 0 do
1443+
putChar(ch)
14561444
nextChar()
1457-
token = LONGLIT
1458-
case _ =>
1459-
}
1445+
// at dot with digit following
1446+
def restOfNonIntegralNumber(): Unit =
1447+
putChar('.')
1448+
nextChar()
1449+
getFraction()
1450+
// 1l is an acknowledged bad practice
1451+
def lintel(): Unit =
1452+
if ch == 'l' then
1453+
val msg = "Lowercase el for long is not recommended because it is easy to confuse with numeral 1; use uppercase L instead"
1454+
report.deprecationWarning(msg, sourcePos(offset + litBuf.length))
1455+
// after int: 5e7f, 42L, 42.toDouble but not 42b.
1456+
def restOfNumber(): Unit =
1457+
ch match
1458+
case 'e' | 'E' | 'f' | 'F' | 'd' | 'D' => getFraction()
1459+
case 'l' | 'L' => lintel() ; token = LONGLIT ; setStrVal() ; nextChar()
1460+
case _ => token = INTLIT ; setStrVal() ; checkNoLetter()
1461+
1462+
// consume leading digits
1463+
consumeDigits()
14601464

14611465
checkNoTrailingSeparator()
14621466

1463-
setStrVal()
1464-
}
1467+
val detectedFloat: Boolean = base == 10 && ch == '.' && isDigit(lookaheadChar())
1468+
if detectedFloat then restOfNonIntegralNumber() else restOfNumber()
1469+
end getNumber
14651470

14661471
private def finishCharLit(): Unit = {
14671472
nextChar()

tests/neg/t6124.check

+5-1
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

+1-1
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)