Skip to content

Commit 9fbac09

Browse files
committed
SI-8466 fix quasiquote crash on recursively iterable unlifting
In order to handle unquoting quasiquotes needs to know if type is iterable and whats the depth of the iterable nesting which is called rank. (e.g. List[List[Tree]] is rank 2 iterable of Tree) The logic that checks depth of iterable nesting didn't take a situation where T is in fact Iterable[T] which caused infinite recursion in stripIterable function. In order to fix it stripIterable now always recurs no more than non-optional limit times.
1 parent 8489be1 commit 9fbac09

File tree

3 files changed

+20
-5
lines changed

3 files changed

+20
-5
lines changed

src/compiler/scala/tools/reflect/quasiquotes/Holes.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ trait Holes { self: Quasiquotes =>
4343
tpe <:< NothingClass.tpe || tpe <:< NullClass.tpe
4444
private def extractIterableTParam(tpe: Type) =
4545
IterableTParam.asSeenFrom(tpe, IterableClass)
46-
private def stripIterable(tpe: Type, limit: Option[Rank] = None): (Rank, Type) =
47-
if (limit.map { _ == NoDot }.getOrElse { false }) (NoDot, tpe)
46+
private def stripIterable(tpe: Type, limit: Rank = DotDotDot): (Rank, Type) =
47+
if (limit == NoDot) (NoDot, tpe)
4848
else if (tpe != null && !isIterableType(tpe)) (NoDot, tpe)
4949
else if (isBottomType(tpe)) (NoDot, tpe)
5050
else {
5151
val targ = extractIterableTParam(tpe)
52-
val (rank, innerTpe) = stripIterable(targ, limit.map { _.pred })
52+
val (rank, innerTpe) = stripIterable(targ, limit.pred)
5353
(rank.succ, innerTpe)
5454
}
5555
private def iterableTypeFromRank(n: Rank, tpe: Type): Type = {
@@ -76,7 +76,7 @@ trait Holes { self: Quasiquotes =>
7676

7777
class ApplyHole(annotatedRank: Rank, unquotee: Tree) extends Hole {
7878
val (strippedTpe, tpe): (Type, Type) = {
79-
val (strippedRank, strippedTpe) = stripIterable(unquotee.tpe, limit = Some(annotatedRank))
79+
val (strippedRank, strippedTpe) = stripIterable(unquotee.tpe, limit = annotatedRank)
8080
if (isBottomType(strippedTpe)) cantSplice()
8181
else if (isNativeType(strippedTpe)) {
8282
if (strippedRank != NoDot && !(strippedTpe <:< treeType) && !isLiftableType(strippedTpe)) cantSplice()
@@ -193,7 +193,7 @@ trait Holes { self: Quasiquotes =>
193193
val (iterableRank, _) = stripIterable(tpe)
194194
if (iterableRank.value < rank.value)
195195
c.abort(pat.pos, s"Can't extract $tpe with $rank, consider using $iterableRank")
196-
val (_, strippedTpe) = stripIterable(tpe, limit = Some(rank))
196+
val (_, strippedTpe) = stripIterable(tpe, limit = rank)
197197
if (strippedTpe <:< treeType) treeNoUnlift
198198
else
199199
unlifters.spawn(strippedTpe, rank).map {

test/files/scalacheck/quasiquotes/LiftableProps.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,11 @@ object LiftableProps extends QuasiquoteProperties("liftable") {
164164
val right3: Either[Int, Int] = Right(1)
165165
assert(q"$right3" q"scala.util.Right(1)")
166166
}
167+
168+
property("lift xml comment") = test {
169+
implicit val liftXmlComment = Liftable[xml.Comment] { comment =>
170+
q"new _root_.scala.xml.Comment(${comment.commentText})"
171+
}
172+
assert(q"${xml.Comment("foo")}" q"<!--foo-->")
173+
}
167174
}

test/files/scalacheck/quasiquotes/UnliftableProps.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,12 @@ object UnliftableProps extends QuasiquoteProperties("unliftable") {
155155
assert(t21 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21))
156156
assert(t22 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22))
157157
}
158+
159+
property("unlift xml comment") = test {
160+
implicit val unliftXmlComment = Unliftable[xml.Comment] {
161+
case q"new _root_.scala.xml.Comment(${value: String})" => xml.Comment(value)
162+
}
163+
val q"${comment: xml.Comment}" = q"<!--foo-->"
164+
assert(comment.commentText == "foo")
165+
}
158166
}

0 commit comments

Comments
 (0)