From 35d159a2b16f9a9251be69e21020c555bc81ea1a Mon Sep 17 00:00:00 2001 From: odersky Date: Sat, 25 Jun 2022 18:44:39 +0200 Subject: [PATCH 1/2] Fix #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. --- .../dotty/tools/dotc/parsing/Parsers.scala | 4 ++-- .../dotty/tools/dotc/parsing/Scanners.scala | 23 +++++++++++-------- tests/pos/i15514.scala | 4 ++++ 3 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 tests/pos/i15514.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index e8ecf1c88f8c..3ac6f06432d2 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3957,8 +3957,8 @@ object Parsers { */ def selfType(): ValDef = if (in.isIdent || in.token == THIS) - && in.lookahead.isColon && followingIsSelfType() - || in.lookahead.token == ARROW + && (in.lookahead.isColon && followingIsSelfType() + || in.lookahead.token == ARROW) then atSpan(in.offset) { val selfName = diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 12d6e34c1e98..6c69e1934ce1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -662,7 +662,7 @@ object Scanners { true else token == COLONfollow && (inTemplate || fewerBracesEnabled) if enabled then - lookAhead() + peekAhead() val atEOL = isAfterLineEnd || token == EOF reset() if atEOL then token = COLONeol @@ -690,15 +690,14 @@ object Scanners { insert(OUTDENT, offset) case _ => - def lookAhead() = + def peekAhead() = prev.copyFrom(this) getNextToken(token) if token == END && !isEndMarker then token = IDENTIFIER - def reset() = { + def reset() = next.copyFrom(this) this.copyFrom(prev) - } def closeIndented() = currentRegion match case r: Indented if !r.isOutermost => insert(OUTDENT, offset) @@ -717,12 +716,12 @@ object Scanners { } (token: @switch) match { case CASE => - lookAhead() + peekAhead() if (token == CLASS) fuse(CASECLASS) else if (token == OBJECT) fuse(CASEOBJECT) else reset() case SEMI => - lookAhead() + peekAhead() if (token != ELSE) reset() case COMMA => def isEnclosedInParens(r: Region): Boolean = r match @@ -733,7 +732,7 @@ object Scanners { case r: Indented if isEnclosedInParens(r.outer) => insert(OUTDENT, offset) case _ => - lookAhead() + peekAhead() if isAfterLineEnd && currentRegion.commasExpected && (token == RPAREN || token == RBRACKET || token == RBRACE || token == OUTDENT) @@ -1083,11 +1082,14 @@ object Scanners { * The token is computed via fetchToken, so complex two word * tokens such as CASECLASS are not recognized. * Newlines and indent/unindent tokens are skipped. - * + * Restriction: `lookahead` is illegal if the current token is INTERPOLATIONID */ - def lookahead: TokenData = + def lookahead: TokenData = if next.token == EMPTY then - lookAhead() + assert(token != INTERPOLATIONID) + // INTERPOLATONIDs are followed by a string literal, which can set next + // in peekAhead(). In that case, the following reset() would forget that token. + peekAhead() reset() next @@ -1279,6 +1281,7 @@ object Scanners { putChar(ch) ; nextRawChar() loopRest() else + assert(next.token == EMPTY) finishNamedToken(IDENTIFIER, target = next) end loopRest setStrVal() diff --git a/tests/pos/i15514.scala b/tests/pos/i15514.scala new file mode 100644 index 000000000000..2b9ed1dd31f4 --- /dev/null +++ b/tests/pos/i15514.scala @@ -0,0 +1,4 @@ + +object Main { s"Hello $Main.toStr!" } + +object Alt { s"Hello ${Alt}.toStr!" } From 626122a2f88a9f61fce9e55711fdbc1c0a79c8b9 Mon Sep 17 00:00:00 2001 From: odersky Date: Sat, 25 Jun 2022 18:54:00 +0200 Subject: [PATCH 2/2] Update compiler/src/dotty/tools/dotc/parsing/Scanners.scala --- compiler/src/dotty/tools/dotc/parsing/Scanners.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 6c69e1934ce1..bf1fe4194c96 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -1281,7 +1281,6 @@ object Scanners { putChar(ch) ; nextRawChar() loopRest() else - assert(next.token == EMPTY) finishNamedToken(IDENTIFIER, target = next) end loopRest setStrVal()