Skip to content

Commit 35d159a

Browse files
committed
Fix scala#15514 in Parser
There was a missing set of parentheses in parser which caused a lookahead from INTERPOLATIONID, which should be illegal, since the lookahead then migth set the next TokenData which is subsequently overwritten by reset. We now demand that lookahead cannot be called if the current token is a INTERPOLATIONID. There were two many variants `lookahead` in the Scanner, which only differered in camelCase or not. Rename one to`peekAhead` to make the code clearer.
1 parent 0059d1d commit 35d159a

File tree

3 files changed

+19
-12
lines changed

3 files changed

+19
-12
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3957,8 +3957,8 @@ object Parsers {
39573957
*/
39583958
def selfType(): ValDef =
39593959
if (in.isIdent || in.token == THIS)
3960-
&& in.lookahead.isColon && followingIsSelfType()
3961-
|| in.lookahead.token == ARROW
3960+
&& (in.lookahead.isColon && followingIsSelfType()
3961+
|| in.lookahead.token == ARROW)
39623962
then
39633963
atSpan(in.offset) {
39643964
val selfName =

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ object Scanners {
662662
true
663663
else token == COLONfollow && (inTemplate || fewerBracesEnabled)
664664
if enabled then
665-
lookAhead()
665+
peekAhead()
666666
val atEOL = isAfterLineEnd || token == EOF
667667
reset()
668668
if atEOL then token = COLONeol
@@ -690,15 +690,14 @@ object Scanners {
690690
insert(OUTDENT, offset)
691691
case _ =>
692692

693-
def lookAhead() =
693+
def peekAhead() =
694694
prev.copyFrom(this)
695695
getNextToken(token)
696696
if token == END && !isEndMarker then token = IDENTIFIER
697697

698-
def reset() = {
698+
def reset() =
699699
next.copyFrom(this)
700700
this.copyFrom(prev)
701-
}
702701

703702
def closeIndented() = currentRegion match
704703
case r: Indented if !r.isOutermost => insert(OUTDENT, offset)
@@ -717,12 +716,12 @@ object Scanners {
717716
}
718717
(token: @switch) match {
719718
case CASE =>
720-
lookAhead()
719+
peekAhead()
721720
if (token == CLASS) fuse(CASECLASS)
722721
else if (token == OBJECT) fuse(CASEOBJECT)
723722
else reset()
724723
case SEMI =>
725-
lookAhead()
724+
peekAhead()
726725
if (token != ELSE) reset()
727726
case COMMA =>
728727
def isEnclosedInParens(r: Region): Boolean = r match
@@ -733,7 +732,7 @@ object Scanners {
733732
case r: Indented if isEnclosedInParens(r.outer) =>
734733
insert(OUTDENT, offset)
735734
case _ =>
736-
lookAhead()
735+
peekAhead()
737736
if isAfterLineEnd
738737
&& currentRegion.commasExpected
739738
&& (token == RPAREN || token == RBRACKET || token == RBRACE || token == OUTDENT)
@@ -1083,11 +1082,14 @@ object Scanners {
10831082
* The token is computed via fetchToken, so complex two word
10841083
* tokens such as CASECLASS are not recognized.
10851084
* Newlines and indent/unindent tokens are skipped.
1086-
*
1085+
* Restriction: `lookahead` is illegal if the current token is INTERPOLATIONID
10871086
*/
1088-
def lookahead: TokenData =
1087+
def lookahead: TokenData =
10891088
if next.token == EMPTY then
1090-
lookAhead()
1089+
assert(token != INTERPOLATIONID)
1090+
// INTERPOLATONIDs are followed by a string literal, which can set next
1091+
// in peekAhead(). In that case, the following reset() would forget that token.
1092+
peekAhead()
10911093
reset()
10921094
next
10931095

@@ -1279,6 +1281,7 @@ object Scanners {
12791281
putChar(ch) ; nextRawChar()
12801282
loopRest()
12811283
else
1284+
assert(next.token == EMPTY)
12821285
finishNamedToken(IDENTIFIER, target = next)
12831286
end loopRest
12841287
setStrVal()

tests/pos/i15514.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
object Main { s"Hello $Main.toStr!" }
3+
4+
object Alt { s"Hello ${Alt}.toStr!" }

0 commit comments

Comments
 (0)