Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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.
  • Loading branch information...
commit 9fbac09b6ec7fcb1b2df75fcbc04bc795eccd669 1 parent 8489be1
@densh densh authored
View
10 src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
@@ -43,13 +43,13 @@ trait Holes { self: Quasiquotes =>
tpe <:< NothingClass.tpe || tpe <:< NullClass.tpe
private def extractIterableTParam(tpe: Type) =
IterableTParam.asSeenFrom(tpe, IterableClass)
- private def stripIterable(tpe: Type, limit: Option[Rank] = None): (Rank, Type) =
- if (limit.map { _ == NoDot }.getOrElse { false }) (NoDot, tpe)
+ private def stripIterable(tpe: Type, limit: Rank = DotDotDot): (Rank, Type) =
+ if (limit == NoDot) (NoDot, tpe)
else if (tpe != null && !isIterableType(tpe)) (NoDot, tpe)
else if (isBottomType(tpe)) (NoDot, tpe)
else {
val targ = extractIterableTParam(tpe)
- val (rank, innerTpe) = stripIterable(targ, limit.map { _.pred })
+ val (rank, innerTpe) = stripIterable(targ, limit.pred)
(rank.succ, innerTpe)
}
private def iterableTypeFromRank(n: Rank, tpe: Type): Type = {
@@ -76,7 +76,7 @@ trait Holes { self: Quasiquotes =>
class ApplyHole(annotatedRank: Rank, unquotee: Tree) extends Hole {
val (strippedTpe, tpe): (Type, Type) = {
- val (strippedRank, strippedTpe) = stripIterable(unquotee.tpe, limit = Some(annotatedRank))
+ val (strippedRank, strippedTpe) = stripIterable(unquotee.tpe, limit = annotatedRank)
if (isBottomType(strippedTpe)) cantSplice()
else if (isNativeType(strippedTpe)) {
if (strippedRank != NoDot && !(strippedTpe <:< treeType) && !isLiftableType(strippedTpe)) cantSplice()
@@ -193,7 +193,7 @@ trait Holes { self: Quasiquotes =>
val (iterableRank, _) = stripIterable(tpe)
if (iterableRank.value < rank.value)
c.abort(pat.pos, s"Can't extract $tpe with $rank, consider using $iterableRank")
- val (_, strippedTpe) = stripIterable(tpe, limit = Some(rank))
+ val (_, strippedTpe) = stripIterable(tpe, limit = rank)
if (strippedTpe <:< treeType) treeNoUnlift
else
unlifters.spawn(strippedTpe, rank).map {
View
7 test/files/scalacheck/quasiquotes/LiftableProps.scala
@@ -164,4 +164,11 @@ object LiftableProps extends QuasiquoteProperties("liftable") {
val right3: Either[Int, Int] = Right(1)
assert(q"$right3" ≈ q"scala.util.Right(1)")
}
+
+ property("lift xml comment") = test {
+ implicit val liftXmlComment = Liftable[xml.Comment] { comment =>
+ q"new _root_.scala.xml.Comment(${comment.commentText})"
+ }
+ assert(q"${xml.Comment("foo")}" ≈ q"<!--foo-->")
+ }
}
View
8 test/files/scalacheck/quasiquotes/UnliftableProps.scala
@@ -155,4 +155,12 @@ object UnliftableProps extends QuasiquoteProperties("unliftable") {
assert(t21 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21))
assert(t22 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22))
}
+
+ property("unlift xml comment") = test {
+ implicit val unliftXmlComment = Unliftable[xml.Comment] {
+ case q"new _root_.scala.xml.Comment(${value: String})" => xml.Comment(value)
+ }
+ val q"${comment: xml.Comment}" = q"<!--foo-->"
+ assert(comment.commentText == "foo")
+ }
}
Please sign in to comment.
Something went wrong with that request. Please try again.