Skip to content

Commit 17d68bc

Browse files
committed
Fix #6432: Refine positions of string interpolator string parts
From ```scala s"abc${"123"}xyz${1}fgh" ^^^^^ ^^^^ ^^^^ ``` to ```scala s"abc${"123"}xyz${1}fgh" ^^^ ^^^ ^^^ ```
1 parent d87a89e commit 17d68bc

File tree

7 files changed

+83
-6
lines changed

7 files changed

+83
-6
lines changed

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ object Parsers {
717717
* @param negOffset The offset of a preceding `-' sign, if any.
718718
* If the literal is not negated, negOffset = in.offset.
719719
*/
720-
def literal(negOffset: Int = in.offset, inPattern: Boolean = false): Tree = {
720+
def literal(negOffset: Int = in.offset, inPattern: Boolean = false, inStringInterpolation: Boolean = false): Tree = {
721721

722722
def literalOf(token: Token): Literal = {
723723
val isNegated = negOffset < in.offset
@@ -738,7 +738,19 @@ object Parsers {
738738
Literal(Constant(value))
739739
}
740740

741-
atSpan(negOffset) {
741+
if (inStringInterpolation) {
742+
val t = in.token match {
743+
case STRINGLIT | STRINGPART =>
744+
val value = in.strVal
745+
atSpan(negOffset, negOffset, negOffset + value.length) { Literal(Constant(value)) }
746+
case _ =>
747+
syntaxErrorOrIncomplete(IllegalLiteral())
748+
atSpan(negOffset) { Literal(Constant(null)) }
749+
}
750+
in.nextToken()
751+
t
752+
}
753+
else atSpan(negOffset) {
742754
if (in.token == QUOTEID) {
743755
if ((staged & StageKind.Spliced) != 0 && isIdentifierStart(in.name(0))) {
744756
val t = atSpan(in.offset + 1) {
@@ -775,10 +787,11 @@ object Parsers {
775787
private def interpolatedString(inPattern: Boolean = false): Tree = atSpan(in.offset) {
776788
val segmentBuf = new ListBuffer[Tree]
777789
val interpolator = in.name
790+
val isTripleQuoted = in.buf(in.charOffset) == '"' && in.buf(in.charOffset + 1) == '"'
778791
in.nextToken()
779-
while (in.token == STRINGPART) {
792+
def nextSegment(literalOffset: Offset) =
780793
segmentBuf += Thicket(
781-
literal(inPattern = inPattern),
794+
literal(literalOffset, inPattern = inPattern, inStringInterpolation = true),
782795
atSpan(in.offset) {
783796
if (in.token == IDENTIFIER)
784797
termIdent()
@@ -798,8 +811,14 @@ object Parsers {
798811
EmptyTree
799812
}
800813
})
801-
}
802-
if (in.token == STRINGLIT) segmentBuf += literal(inPattern = inPattern)
814+
815+
if (in.token == STRINGPART)
816+
nextSegment(in.offset + (if (isTripleQuoted) 3 else 1))
817+
while (in.token == STRINGPART)
818+
nextSegment(in.offset)
819+
if (in.token == STRINGLIT)
820+
segmentBuf += literal(inPattern = inPattern, negOffset = in.offset, inStringInterpolation = true)
821+
803822
InterpolatedString(interpolator, segmentBuf.toList)
804823
}
805824

tests/neg-macros/i6432.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[61..64] in Test_2.scala
2+
fgh
3+
[50..53] in Test_2.scala
4+
xyz
5+
[39..42] in Test_2.scala
6+
abc

tests/neg-macros/i6432/Macro_1.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
import scala.quoted._
3+
import scala.quoted.autolift._
4+
import scala.quoted.matching._
5+
6+
object Macro {
7+
inline def (sc: => StringContext) foo (args: String*): Unit = ${ impl('sc) }
8+
9+
def impl(sc: Expr[StringContext])(implicit reflect: tasty.Reflection): Expr[Unit] = {
10+
import reflect._
11+
sc match {
12+
case '{ StringContext(${ExprSeq(parts)}: _*) } =>
13+
for (part @ Const(s) <- parts)
14+
error(s, part.unseal.pos)
15+
}
16+
'{}
17+
}
18+
}

tests/neg-macros/i6432/Test_2.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
object TestA {
3+
import Macro._
4+
foo"abc${"123"}xyz${"456"}fgh" // error // error // error
5+
}

tests/neg-macros/i6432b.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[63..66] in Test_2.scala
2+
fgh
3+
[52..55] in Test_2.scala
4+
xyz
5+
[41..44] in Test_2.scala
6+
abc

tests/neg-macros/i6432b/Macro_1.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
import scala.quoted._
3+
import scala.quoted.autolift._
4+
import scala.quoted.matching._
5+
6+
object Macro {
7+
inline def (sc: => StringContext) foo (args: String*): Unit = ${ impl('sc) }
8+
9+
def impl(sc: Expr[StringContext])(implicit reflect: tasty.Reflection): Expr[Unit] = {
10+
import reflect._
11+
sc match {
12+
case '{ StringContext(${ExprSeq(parts)}: _*) } =>
13+
for (part @ Const(s) <- parts)
14+
error(s, part.unseal.pos)
15+
}
16+
'{}
17+
}
18+
}

tests/neg-macros/i6432b/Test_2.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
object TestA {
3+
import Macro._
4+
foo"""abc${"123"}xyz${"456"}fgh""" // error // error // error
5+
}

0 commit comments

Comments
 (0)