summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala2
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala41
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala28
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala25
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala6
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala84
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala54
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala18
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala4
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala72
-rw-r--r--test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala2
12 files changed, 228 insertions, 110 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 5dadbd0825..8271363527 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2492,7 +2492,7 @@ self =>
def mkDefs(p: Tree, tp: Tree, rhs: Tree): List[Tree] = {
val trees = {
val pat = if (tp.isEmpty) p else Typed(p, tp) setPos (p.pos union tp.pos)
- gen.mkPatDef(newmods, pat, rhs)
+ makePatDef(newmods, pat, rhs)
}
if (newmods.isDeferred) {
trees match {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 525dcffb0c..6e5a3f6ef7 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -168,4 +168,6 @@ abstract class TreeBuilder {
vparamss ::: List(evidenceParams)
}
}
+
+ def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = gen.mkPatDef(mods, pat, rhs)
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index 9f6807fe17..301e7051df 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -14,6 +14,7 @@ import scala.util.Try
*/
trait Parsers { self: Quasiquotes =>
import global.{Try => _, _}
+ import build.implodePatDefs
abstract class Parser extends {
val global: self.global.type = self.global
@@ -61,12 +62,10 @@ trait Parsers { self: Quasiquotes =>
override implicit def fresh: FreshNameCreator = parser.fresh
// q"(..$xs)"
- override def makeTupleTerm(trees: List[Tree]): Tree =
- Apply(Ident(nme.QUASIQUOTE_TUPLE), trees)
+ override def makeTupleTerm(trees: List[Tree]): Tree = TuplePlaceholder(trees)
// tq"(..$xs)"
- override def makeTupleType(trees: List[Tree]): Tree =
- AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), trees)
+ override def makeTupleType(trees: List[Tree]): Tree = TupleTypePlaceholder(trees)
// q"{ $x }"
override def makeBlock(stats: List[Tree]): Tree = stats match {
@@ -75,30 +74,32 @@ trait Parsers { self: Quasiquotes =>
}
// tq"$a => $b"
- override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
- AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), argtpes :+ restpe)
+ override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = FunctionTypePlaceholder(argtpes, restpe)
+
+ // make q"val (x: T) = rhs" be equivalent to q"val x: T = rhs" for sake of bug compatibility (SI-8211)
+ override def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = pat match {
+ case TuplePlaceholder(inParensPat :: Nil) => super.makePatDef(mods, inParensPat, rhs)
+ case _ => super.makePatDef(mods, pat, rhs)
+ }
}
import treeBuilder.{global => _, unit => _, _}
- def quasiquoteParam(name: Name, flags: FlagSet = NoFlags) =
- ValDef(Modifiers(flags), name.toTermName, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree)
-
// q"def foo($x)"
override def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef =
if (isHole && lookingAhead { in.token == COMMA || in.token == RPAREN }) {
- quasiquoteParam(ident(), implicitmod)
+ ParamPlaceholder(implicitmod, ident())
} else super.param(owner, implicitmod, caseParam)
// q"($x) => ..." && q"class X { selfie => }
override def convertToParam(tree: Tree): ValDef = tree match {
- case Ident(name) if isHole(name) => quasiquoteParam(name)
+ case Ident(name) if isHole(name) => ParamPlaceholder(NoFlags, name)
case _ => super.convertToParam(tree)
}
// q"foo match { case $x }"
override def caseClause(): CaseDef =
if (isHole && lookingAhead { in.token == CASE || in.token == RBRACE || in.token == SEMI }) {
- val c = makeCaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), List(Ident(ident()))), EmptyTree, EmptyTree)
+ val c = CasePlaceholder(ident())
while (in.token == SEMI) in.nextToken()
c
} else
@@ -132,7 +133,7 @@ trait Parsers { self: Quasiquotes =>
in.nextToken()
annot :: readAnnots(annot)
case _ if isHole && lookingAhead { isAnnotation || isModifier || isDefIntro || isIdent || isStatSep || in.token == LPAREN } =>
- val ann = Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(in.name.toString))))
+ val ann = ModsPlaceholder(in.name)
in.nextToken()
ann :: readAnnots(annot)
case _ =>
@@ -141,13 +142,13 @@ trait Parsers { self: Quasiquotes =>
override def refineStat(): List[Tree] =
if (isHole && !isDclIntro) {
- val result = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_REFINE_STAT), EmptyTree) :: Nil
+ val result = RefineStatPlaceholder(in.name) :: Nil
in.nextToken()
result
} else super.refineStat()
override def ensureEarlyDef(tree: Tree) = tree match {
- case Ident(name: TermName) if isHole(name) => ValDef(NoMods | Flag.PRESUPER, name, Ident(tpnme.QUASIQUOTE_EARLY_DEF), EmptyTree)
+ case Ident(name: TermName) if isHole(name) => EarlyDefPlaceholder(name)
case _ => super.ensureEarlyDef(tree)
}
@@ -158,14 +159,14 @@ trait Parsers { self: Quasiquotes =>
override def topStat = super.topStat.orElse {
case _ if isHole =>
- val stats = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) :: Nil
+ val stats = PackageStatPlaceholder(in.name) :: Nil
in.nextToken()
stats
}
override def enumerator(isFirst: Boolean, allowNestedIf: Boolean = true) =
if (isHole && lookingAhead { in.token == EOF || in.token == RPAREN || isStatSep }) {
- val res = build.SyntacticValFrom(Bind(in.name, Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) :: Nil
+ val res = ForEnumPlaceholder(in.name) :: Nil
in.nextToken()
res
} else super.enumerator(isFirst, allowNestedIf)
@@ -182,7 +183,7 @@ trait Parsers { self: Quasiquotes =>
}
object TermParser extends Parser {
- def entryPoint = parser => Q(gen.mkTreeOrBlock(parser.templateOrTopStatSeq()))
+ def entryPoint = parser => Q(implodePatDefs(gen.mkTreeOrBlock(parser.templateOrTopStatSeq())))
}
object TypeParser extends Parser {
@@ -195,7 +196,7 @@ trait Parsers { self: Quasiquotes =>
}
object CaseParser extends Parser {
- def entryPoint = _.caseClause()
+ def entryPoint = parser => implodePatDefs(parser.caseClause())
}
object PatternParser extends Parser {
@@ -209,7 +210,7 @@ trait Parsers { self: Quasiquotes =>
def entryPoint = { parser =>
val enums = parser.enumerator(isFirst = false, allowNestedIf = false)
assert(enums.length == 1)
- enums.head
+ implodePatDefs(enums.head)
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index 825d0c04f3..130a01332b 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -100,6 +100,8 @@ trait Placeholders { self: Quasiquotes =>
}
object ModsPlaceholder extends HolePlaceholder {
+ def apply(name: Name) =
+ Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(name.toString))))
def matching = {
case Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(s: String)))) => TermName(s)
}
@@ -112,12 +114,16 @@ trait Placeholders { self: Quasiquotes =>
}
object ParamPlaceholder extends HolePlaceholder {
+ def apply(flags: FlagSet, name: Name) =
+ ValDef(Modifiers(flags), nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree)
def matching = {
- case ValDef(_, name, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree) => name
+ case ValDef(_, nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree) => name
}
}
object TuplePlaceholder {
+ def apply(args: List[Tree]) =
+ Apply(Ident(nme.QUASIQUOTE_TUPLE), args)
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case Apply(Ident(nme.QUASIQUOTE_TUPLE), args) => Some(args)
case _ => None
@@ -125,6 +131,8 @@ trait Placeholders { self: Quasiquotes =>
}
object TupleTypePlaceholder {
+ def apply(args: List[Tree]) =
+ AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args)
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args) => Some(args)
case _ => None
@@ -132,6 +140,8 @@ trait Placeholders { self: Quasiquotes =>
}
object FunctionTypePlaceholder {
+ def apply(args: List[Tree], res: Tree) =
+ AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res)
def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res) => Some((args, res))
case _ => None
@@ -146,6 +156,8 @@ trait Placeholders { self: Quasiquotes =>
}
object CasePlaceholder {
+ def apply(name: Name) =
+ CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), Ident(name) :: Nil), EmptyTree, EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
case CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), List(Placeholder(hole))), EmptyTree, EmptyTree) => Some(hole)
case _ => None
@@ -153,27 +165,35 @@ trait Placeholders { self: Quasiquotes =>
}
object RefineStatPlaceholder {
+ def apply(name: Name) =
+ ValDef(NoMods, nme.QUASIQUOTE_REFINE_STAT, Ident(name), EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(_, Placeholder(hole), Ident(tpnme.QUASIQUOTE_REFINE_STAT), _) => Some(hole)
+ case ValDef(_, nme.QUASIQUOTE_REFINE_STAT, Ident(Placeholder(hole)), _) => Some(hole)
case _ => None
}
}
object EarlyDefPlaceholder {
+ def apply(name: Name) =
+ ValDef(Modifiers(Flag.PRESUPER), nme.QUASIQUOTE_EARLY_DEF, Ident(name), EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(_, Placeholder(hole), Ident(tpnme.QUASIQUOTE_EARLY_DEF), _) => Some(hole)
+ case ValDef(_, nme.QUASIQUOTE_EARLY_DEF, Ident(Placeholder(hole)), _) => Some(hole)
case _ => None
}
}
object PackageStatPlaceholder {
+ def apply(name: Name) =
+ ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(name), EmptyTree)
def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(NoMods, Placeholder(hole), Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) => Some(hole)
+ case ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(Placeholder(hole)), EmptyTree) => Some(hole)
case _ => None
}
}
object ForEnumPlaceholder {
+ def apply(name: Name) =
+ build.SyntacticValFrom(Bind(name, Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM))
def unapply(tree: Tree): Option[Hole] = tree match {
case build.SyntacticValFrom(Bind(Placeholder(hole), Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) =>
Some(hole)
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 017e966f63..70580adbce 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -194,8 +194,8 @@ trait Reifiers { self: Quasiquotes =>
reifyBuildCall(nme.SyntacticEmptyTypeTree)
case SyntacticImport(expr, selectors) =>
reifyBuildCall(nme.SyntacticImport, expr, selectors)
- case Q(Placeholder(Hole(tree, DotDot))) =>
- mirrorBuildCall(nme.SyntacticBlock, tree)
+ case Q(tree) if fillListHole.isDefinedAt(tree) =>
+ mirrorBuildCall(nme.SyntacticBlock, fillListHole(tree))
case Q(other) =>
reifyTree(other)
// Syntactic block always matches so we have to be careful
@@ -311,11 +311,7 @@ trait Reifiers { self: Quasiquotes =>
*/
def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree
- /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put
- * in the correct position. Fallbacks to regular reification for non-high cardinality
- * elements.
- */
- override def reifyList(xs: List[Any]): Tree = reifyMultiCardinalityList(xs) {
+ val fillListHole: PartialFunction[Any, Tree] = {
case Placeholder(Hole(tree, DotDot)) => tree
case CasePlaceholder(Hole(tree, DotDot)) => tree
case RefineStatPlaceholder(h @ Hole(_, DotDot)) => reifyRefineStat(h)
@@ -323,12 +319,23 @@ trait Reifiers { self: Quasiquotes =>
case PackageStatPlaceholder(h @ Hole(_, DotDot)) => reifyPackageStat(h)
case ForEnumPlaceholder(Hole(tree, DotDot)) => tree
case ParamPlaceholder(Hole(tree, DotDot)) => tree
+ case SyntacticPatDef(mods, pat, tpt, rhs) =>
+ reifyBuildCall(nme.SyntacticPatDef, mods, pat, tpt, rhs)
+ case SyntacticValDef(mods, p @ Placeholder(h: ApplyHole), tpt, rhs) if h.tpe <:< treeType =>
+ mirrorBuildCall(nme.SyntacticPatDef, reify(mods), h.tree, reify(tpt), reify(rhs))
+ }
+
+ val fillListOfListsHole: PartialFunction[Any, Tree] = {
case List(ParamPlaceholder(Hole(tree, DotDotDot))) => tree
case List(Placeholder(Hole(tree, DotDotDot))) => tree
- } {
- reify(_)
}
+ /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put
+ * in the correct position. Fallbacks to regular reification for non-high cardinality
+ * elements.
+ */
+ override def reifyList(xs: List[Any]): Tree = reifyMultiCardinalityList(xs)(fillListHole.orElse(fillListOfListsHole))(reify)
+
def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
case AnnotPlaceholder(h @ Hole(_, DotDot)) => reifyAnnotation(h)
} {
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index ec20a89a10..57dc7da6cc 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -220,6 +220,12 @@ private[reflect] trait BuildUtils { self: Universe =>
def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)]
}
+ val SyntacticPatDef: SyntacticPatDefExtractor
+
+ trait SyntacticPatDefExtractor {
+ def apply(mods: Modifiers, pat: Tree, tpt: Tree, rhs: Tree): List[ValDef]
+ }
+
val SyntacticAssign: SyntacticAssignExtractor
trait SyntacticAssignExtractor {
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index c5581601de..6f1e4d2e32 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -193,9 +193,9 @@ trait BuildUtils { self: SymbolTable =>
// recover constructor contents generated by gen.mkTemplate
protected object UnCtor {
def unapply(tree: Tree): Option[(Modifiers, List[List[ValDef]], List[Tree])] = tree match {
- case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, Block(lvdefs, _)) =>
+ case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, SyntacticBlock(lvdefs :+ _)) =>
Some((mods | Flag.TRAIT, Nil, lvdefs))
- case DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, _, Block(lvdefs :+ _, _)) =>
+ case DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, _, SyntacticBlock(lvdefs :+ _ :+ _)) =>
Some((mods, vparamss, lvdefs))
case _ => None
}
@@ -474,10 +474,9 @@ trait BuildUtils { self: SymbolTable =>
}
protected class SyntacticValDefBase(isMutable: Boolean) extends SyntacticValDefExtractor {
- def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) = {
- val mods1 = if (isMutable) mods | MUTABLE else mods
- ValDef(mods1, name, tpt, rhs)
- }
+ def modifiers(mods: Modifiers): Modifiers = if (isMutable) mods | MUTABLE else mods
+
+ def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef = ValDef(modifiers(mods), name, tpt, rhs)
def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)] = tree match {
case ValDef(mods, name, tpt, rhs) if mods.hasFlag(MUTABLE) == isMutable =>
@@ -547,25 +546,57 @@ trait BuildUtils { self: SymbolTable =>
// match a sequence of desugared `val $pat = $value`
protected object UnPatSeq {
- def unapply(trees: List[Tree]): Option[List[(Tree, Tree)]] = trees match {
- case Nil => Some(Nil)
- // case q"$mods val ${_}: ${_} = ${MaybeUnchecked(value)} match { case $pat => (..$ids) }" :: tail
- case ValDef(mods, _, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, SyntacticTuple(ids)) :: Nil)) :: tail
+ def unapply(trees: List[Tree]): Option[List[(Tree, Tree)]] = {
+ val imploded = implodePatDefs(trees)
+ val patvalues = imploded.flatMap {
+ case SyntacticPatDef(_, pat, EmptyTree, rhs) => Some((pat, rhs))
+ case ValDef(_, name, SyntacticEmptyTypeTree(), rhs) => Some((Bind(name, self.Ident(nme.WILDCARD)), rhs))
+ case ValDef(_, name, tpt, rhs) => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), rhs))
+ case _ => None
+ }
+ if (patvalues.length == imploded.length) Some(patvalues) else None
+ }
+ }
+
+ // implode multiple-statement desugaring of pattern definitions
+ // into single-statement valdefs with nme.QUASIQUOTE_PAT_DEF name
+ object implodePatDefs extends Transformer {
+ override def transform(tree: Tree) = tree match {
+ case templ: Template => deriveTemplate(templ)(transformStats)
+ case block: Block =>
+ val Block(init, last) = block
+ Block(transformStats(init), transform(last)).copyAttrs(block)
+ case ValDef(mods, name1, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil))
+ if name1 == name2 =>
+ ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value))
+ case _ =>
+ super.transform(tree)
+ }
+ def transformStats(trees: List[Tree]): List[Tree] = trees match {
+ case Nil => Nil
+ case ValDef(mods, _, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, SyntacticTuple(ids)) :: Nil)) :: tail
if mods.hasFlag(SYNTHETIC) && mods.hasFlag(ARTIFACT) =>
- tail.drop(ids.length) match {
- case UnPatSeq(rest) => Some((pat, value) :: rest)
- case _ => None
+ ids match {
+ case Nil =>
+ ValDef(NoMods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail)
+ case _ =>
+ val mods = tail.take(1).head.asInstanceOf[ValDef].mods
+ ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail.drop(ids.length))
}
- // case q"${_} val $name1: ${_} = ${MaybeUnchecked(value)} match { case $pat => ${Ident(name2)} }" :: UnPatSeq(rest)
- case ValDef(_, name1, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil)) :: UnPatSeq(rest)
- if name1 == name2 =>
- Some((pat, value) :: rest)
- // case q"${_} val $name: ${SyntacticEmptyTypeTree()} = $value" :: UnPatSeq(rest) =>
- case ValDef(_, name, SyntacticEmptyTypeTree(), value) :: UnPatSeq(rest) =>
- Some((Bind(name, self.Ident(nme.WILDCARD)), value) :: rest)
- // case q"${_} val $name: $tpt = $value" :: UnPatSeq(rest) =>
- case ValDef(_, name, tpt, value) :: UnPatSeq(rest) =>
- Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), value) :: rest)
+ case other :: tail =>
+ transform(other) :: transformStats(tail)
+ }
+ def apply(tree: Tree) = transform(tree)
+ def apply(trees: List[Tree]) = transformStats(trees)
+ }
+
+ object SyntacticPatDef extends SyntacticPatDefExtractor {
+ def apply(mods: Modifiers, pat: Tree, tpt: Tree, rhs: Tree): List[ValDef] = tpt match {
+ case SyntacticEmptyTypeTree() => gen.mkPatDef(mods, pat, rhs)
+ case _ => gen.mkPatDef(mods, Typed(pat, tpt), rhs)
+ }
+ def unapply(tree: Tree): Option[(Modifiers, Tree, Tree, Tree)] = tree match {
+ case ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), rhs) => Some((mods, pat, tpt, rhs))
case _ => None
}
}
@@ -746,6 +777,13 @@ trait BuildUtils { self: SymbolTable =>
}
}
+ protected object MaybeTyped {
+ def unapply(tree: Tree): Some[(Tree, Tree)] = tree match {
+ case Typed(v, tpt) => Some((v, tpt))
+ case v => Some((v, SyntacticEmptyTypeTree()))
+ }
+ }
+
protected def mkCases(cases: List[Tree]): List[CaseDef] = cases.map {
case c: CaseDef => c
case tree => throw new IllegalArgumentException("$tree is not valid representation of pattern match case")
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index 519d1047a6..26db97b725 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -33,10 +33,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
def qowner = quotedName(sym.owner.name.dropLocal, decoded)
def qsymbol = quotedName(sym.nameString)
- if (sym.name.toTermName == nme.ERROR)
- s"<$qname: error>"
- else if (sym == null || sym == NoSymbol)
+ if (sym == null || sym == NoSymbol)
qname
+ else if (sym.isErroneous)
+ s"<$qname: error>"
else if (sym.isMixinConstructor)
s"/*$qowner*/$qsymbol"
else
@@ -128,10 +128,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
body
if (condition) print(")")
}
-
- protected def printImplicitInParamsList(vds: List[ValDef]) =
+
+ protected def printImplicitInParamsList(vds: List[ValDef]) =
if (vds.nonEmpty) printFlags(vds.head.mods.flags & IMPLICIT, "")
-
+
def printValueParams(ts: List[ValDef], inParentheses: Boolean = true): Unit =
parenthesize(inParentheses){
printImplicitInParamsList(ts)
@@ -191,7 +191,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
private var currentOwner: Symbol = NoSymbol
private var selectorType: Type = NoType
-
+
protected def printPackageDef(tree: PackageDef, separator: String) = {
val PackageDef(packaged, stats) = tree
printAnnotations(tree)
@@ -511,7 +511,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
out.print(if (arg == null) "null" else arg.toString)
}
}
-
+
// it's the printer for trees after parser and before typer phases
class ParsedTreePrinter(out: PrintWriter) extends TreePrinter(out) {
override def withTypes = this
@@ -537,13 +537,13 @@ trait Printers extends api.Printers { self: SymbolTable =>
import Chars._
val decName = name.decoded
val bslash = '\\'
- val brackets = List('[',']','(',')','{','}')
+ val brackets = List('[',']','(',')','{','}')
def addBackquotes(s: String) =
- if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch)) ||
+ if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch)) ||
(name.isOperatorName && decName.exists(isOperatorPart) && decName.exists(isScalaLetter) && !decName.contains(bslash))))
s"`$s`" else s
-
+
if (name == nme.CONSTRUCTOR) "this"
else addBackquotes(quotedName(name, decoded))
}
@@ -556,7 +556,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
qualIsIntLit && name.isOperatorName
}
- protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true,
+ protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true,
insideTry: Boolean = true, insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true) = {
parent match {
case _: If => insideIf
@@ -572,10 +572,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
protected def checkForBlank(cond: Boolean) = if (cond) " " else ""
protected def blankForOperatorName(name: Name) = checkForBlank(name.isOperatorName)
protected def blankForName(name: Name) = checkForBlank(name.isOperatorName || name.endsWith("_"))
-
+
protected def resolveSelect(t: Tree): String = {
t match {
- // case for: 1) (if (a) b else c).meth1.meth2 or 2) 1 + 5 should be represented as (1).+(5)
+ // case for: 1) (if (a) b else c).meth1.meth2 or 2) 1 + 5 should be represented as (1).+(5)
case Select(qual, name) if (name.isTermName && needsParentheses(qual)(insideLabelDef = false)) || isIntLitWithDecodedOp(qual, name) => s"(${resolveSelect(qual)}).${printedName(name)}"
case Select(qual, name) if name.isTermName => s"${resolveSelect(qual)}.${printedName(name)}"
case Select(qual, name) if name.isTypeName => s"${resolveSelect(qual)}#${blankForOperatorName(name)}%${printedName(name)}"
@@ -591,7 +591,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
trees match {
case Nil => trees
case init :+ last => last match {
- case Select(Ident(sc), name) if traitsToRemove.contains(name) && sc == nme.scala_ =>
+ case Select(Ident(sc), name) if traitsToRemove.contains(name) && sc == nme.scala_ =>
removeDefaultTraitsFromList(init, traitsToRemove)
case _ => trees
}
@@ -637,7 +637,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
val mutableOrOverride = mods.isOverride || mods.isMutable
val hideCtorMods = mods.isParamAccessor && mods.isPrivateLocal && !mutableOrOverride
val hideCaseCtorMods = mods.isCaseAccessor && mods.isPublic && !mutableOrOverride
-
+
if (primaryCtorParam && !(hideCtorMods || hideCaseCtorMods)) {
printModifiers(mods, primaryCtorParam)
print(if (mods.isMutable) "var " else "val ");
@@ -657,14 +657,14 @@ trait Printers extends api.Printers { self: SymbolTable =>
printParam(tree, primaryCtorParam = false)
}
- protected def printArgss(argss: List[List[Tree]]) =
+ protected def printArgss(argss: List[List[Tree]]) =
argss foreach {x: List[Tree] => if (!(x.isEmpty && argss.size == 1)) printRow(x, "(", ", ", ")")}
-
+
override def printAnnotations(tree: MemberDef) = {
val annots = tree.mods.annotations
annots foreach {annot => printAnnot(annot); print(" ")}
}
-
+
protected def printAnnot(tree: Tree) = {
tree match {
case treeInfo.Applied(core, _, argss) =>
@@ -675,10 +675,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
printArgss(argss)
case _ => super.printTree(tree)
- }
+ }
}
- override def printTree(tree: Tree): Unit = {
+ override def printTree(tree: Tree): Unit = {
parentsStack.push(tree)
tree match {
case cl @ ClassDef(mods, name, tparams, impl) =>
@@ -809,15 +809,15 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
case _ => None
}
-
+
if (printedParents.nonEmpty) {
val (clParent :: traits) = printedParents
print(clParent)
val constrArgss = ap match {
case Some(treeInfo.Applied(_, _, argss)) => argss
- case _ => Nil
- }
+ case _ => Nil
+ }
printArgss(constrArgss)
if (traits.nonEmpty) {
printRow(traits, " with ", " with ", "")
@@ -907,7 +907,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case Apply(fun, vargs) =>
tree match {
// processing methods ending on colons (x \: list)
- case Apply(Block(l1 @ List(sVD: ValDef), a1 @ Apply(Select(_, methodName), l2 @ List(Ident(iVDName)))), l3)
+ case Apply(Block(l1 @ List(sVD: ValDef), a1 @ Apply(Select(_, methodName), l2 @ List(Ident(iVDName)))), l3)
if sVD.mods.isSynthetic && treeInfo.isLeftAssoc(methodName) && sVD.name == iVDName =>
val printBlock = Block(l1, Apply(a1, l3))
print(printBlock)
@@ -972,7 +972,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case AppliedTypeTree(tp, args) =>
// it's possible to have (=> String) => String type but Function1[=> String, String] is not correct
val containsByNameTypeParam = args exists treeInfo.isByNameParamType
-
+
if (containsByNameTypeParam) {
print("(")
printRow(args.init, "(", ", ", ")")
@@ -1093,7 +1093,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case self.pendingSuperCall =>
print("pendingSuperCall")
case tree: Tree =>
- val hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol
+ def hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol
val isError = hasSymbolField && (tree.symbol.name string_== nme.ERROR)
printProduct(
tree,
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 923102a049..9fd2199c19 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -253,12 +253,8 @@ trait StdNames {
final val Quasiquote: NameType = "Quasiquote"
// quasiquote-specific names
- final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$"
final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$"
final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
- final val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$"
- final val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$"
- final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
// Annotation simple names, used in Namer
@@ -331,12 +327,17 @@ trait StdNames {
val REIFY_FREE_THIS_SUFFIX: NameType = "$this"
val REIFY_FREE_VALUE_SUFFIX: NameType = "$value"
val REIFY_SYMDEF_PREFIX: NameType = "symdef$"
- val QUASIQUOTE_PREFIX: String = "qq$"
- val QUASIQUOTE_NAME_PREFIX: String = "nn$"
- val QUASIQUOTE_FILE: String = "<quasiquote>"
- val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
val QUASIQUOTE_CASE: NameType = "$quasiquote$case$"
+ val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$"
+ val QUASIQUOTE_FILE: String = "<quasiquote>"
val QUASIQUOTE_FOR_ENUM: NameType = "$quasiquote$for$enum$"
+ val QUASIQUOTE_NAME_PREFIX: String = "nn$"
+ val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$"
+ val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$"
+ val QUASIQUOTE_PAT_DEF: NameType = "$quasiquote$pat$def$"
+ val QUASIQUOTE_PREFIX: String = "qq$"
+ val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
+ val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
val QUASIQUOTE_UNLIFT_HELPER: String = "$quasiquote$unlift$helper$"
val MIXIN_CONSTRUCTOR: NameType = "$init$"
val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
@@ -615,6 +616,7 @@ trait StdNames {
val SyntacticNew: NameType = "SyntacticNew"
val SyntacticObjectDef: NameType = "SyntacticObjectDef"
val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef"
+ val SyntacticPatDef: NameType = "SyntacticPatDef"
val SyntacticTraitDef: NameType = "SyntacticTraitDef"
val SyntacticTry: NameType = "SyntacticTry"
val SyntacticTuple: NameType = "SyntacticTuple"
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index 29fdba2781..e7675eb4bf 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -691,11 +691,11 @@ abstract class TreeGen extends macros.TreeBuilder {
}
/** Create tree for pattern definition <val pat0 = rhs> */
- def mkPatDef(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] =
+ def mkPatDef(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] =
mkPatDef(Modifiers(0), pat, rhs)
/** Create tree for pattern definition <mods val pat0 = rhs> */
- def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] = matchVarPattern(pat) match {
+ def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] = matchVarPattern(pat) match {
case Some((name, tpt)) =>
List(atPos(pat.pos union rhs.pos) {
ValDef(mods, name.toTermName, tpt, rhs)
diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
index dcd4f63a4d..5f22925335 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
@@ -7,21 +7,22 @@ object DefinitionConstructionProps
with TraitConstruction
with TypeDefConstruction
with ValDefConstruction
+ with PatDefConstruction
with DefConstruction
- with PackageConstruction
+ with PackageConstruction
with ImportConstruction {
- property("SI-6842") = test {
- val x: Tree = q"val x: Int"
- assertEqAst(q"def f($x) = 0", "def f(x: Int) = 0")
- assertEqAst(q"class C($x)", "class C(val x: Int)")
- assertEqAst(q"class C { $x => }", "class C { x: Int => }")
- assertEqAst(q"trait B { $x => }", "trait B { x: Int => }")
- assertEqAst(q"object A { $x => }", "object A { x: Int => }")
- val t: Tree = q"type T"
- assertEqAst(q"def f[$t] = 0", "def f[T] = 0")
- assertEqAst(q"class C[$t]", "class C[T]")
- assertEqAst(q"trait B[$t]", "trait B[T]")
- }
+
+ val x: Tree = q"val x: Int"
+ property("SI-6842 a1") = test { assertEqAst(q"def f($x) = 0", "def f(x: Int) = 0") }
+ property("SI-6842 a2") = test { assertEqAst(q"class C($x)", "class C(val x: Int)") }
+ property("SI-6842 a3") = test { assertEqAst(q"class C { $x => }", "class C { x: Int => }") }
+ property("SI-6842 a4") = test { assertEqAst(q"trait B { $x => }", "trait B { x: Int => }") }
+ property("SI-6842 a5") = test { assertEqAst(q"object A { $x => }", "object A { x: Int => }") }
+
+ val t: Tree = q"type T"
+ property("SI-6842 b1") = test { assertEqAst(q"def f[$t] = 0", "def f[T] = 0") }
+ property("SI-6842 b2") = test { assertEqAst(q"class C[$t]", "class C[T]") }
+ property("SI-6842 b3") = test { assertEqAst(q"trait B[$t]", "trait B[T]") }
}
trait ClassConstruction { self: QuasiquoteProperties =>
@@ -200,13 +201,54 @@ trait TypeDefConstruction { self: QuasiquoteProperties =>
}
trait ValDefConstruction { self: QuasiquoteProperties =>
- property("splice term name into val") = forAll { (name: TermName, tpt: Tree, rhs: Tree) =>
+ property("splice into val") = forAll { (name: TermName, tpt: Tree, rhs: Tree) =>
q"val $name: $tpt = $rhs" ≈ ValDef(Modifiers(), name, tpt, rhs)
}
- property("splice term name into var") = forAll { (name: TermName, tpt: Tree, rhs: Tree) =>
+ property("splice into var") = forAll { (name: TermName, tpt: Tree, rhs: Tree) =>
q"var $name: $tpt = $rhs" ≈ ValDef(Modifiers(MUTABLE), name, tpt, rhs)
}
+
+ // left tree is not a pattern due to Si-8211
+ property("SI-8202") = test {
+ assertEqAst(q"val (x: Int) = 1", "val x: Int = 1")
+ }
+}
+
+trait PatDefConstruction { self: QuasiquoteProperties =>
+ property("splice pattern into pat def") = test {
+ val pat = pq"(a, b)"
+ assertEqAst(q"val $pat = (1, 2)", "val (a, b) = (1, 2)")
+ val tpt = tq"(Int, Int)"
+ assertEqAst(q"val $pat: $tpt = (1, 2)", "val (a, b): (Int, Int) = (1, 2)")
+ }
+
+ property("splice pattern into pat def within other pattern (1)") = test {
+ val pat = pq"(a, b)"
+ assertEqAst(q"val Foo($pat) = Foo((1, 2))", "val Foo((a, b)) = Foo((1, 2))")
+ val tpt = tq"Foo"
+ assertEqAst(q"val Foo($pat): $tpt = Foo((1, 2))", "val Foo((a, b)): Foo = Foo((1, 2))")
+ }
+
+ property("splice patterns into pat def within other pattern (2)") = test {
+ val pat1 = pq"(a, b)"; val pat2 = pq"(c, d)"
+ assertEqAst(q"val ($pat1, $pat2) = ((1, 2), (3, 4))", "val ((a, b), (c, d)) = ((1, 2), (3, 4))")
+ val tpt = tq"((Int, Int), (Int, Int))"
+ assertEqAst(q"val ($pat1, $pat2): $tpt = ((1, 2), (3, 4))", "val ((a, b), (c, d)): ((Int, Int), (Int, Int)) = ((1, 2), (3, 4))")
+ }
+
+ property("splice pattern without free vars into pat def") = test {
+ val pat = pq"((1, 2), 3)"
+ assertEqAst(q"val $pat = ((1, 2), 3)", "{ val ((1, 2), 3) = ((1, 2), 3) }")
+ val tpt = tq"((Int, Int), Int)"
+ assertEqAst(q"val $pat: $tpt = ((1, 2), 3)","{ val ((1, 2), 3): ((Int, Int), Int) = ((1, 2), 3) }")
+ }
+
+ // won't result into pattern match due to SI-8211
+ property("splice typed pat into pat def") = test {
+ val pat = pq"x: Int"
+ assertEqAst(q"val $pat = 2", "{ val x: Int = 2 }")
+ }
}
trait MethodConstruction { self: QuasiquoteProperties =>
diff --git a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala
index 589b8d4d72..5d84984514 100644
--- a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala
+++ b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala
@@ -28,7 +28,7 @@ trait Helpers {
override def transform(tree: Tree): Tree = tree match {
case Ident(SimplifiedName(name)) => Ident(name)
- case ValDef(mods, SimplifiedName(name), tpt, rhs) => ValDef(mods, name, tpt, rhs)
+ case ValDef(mods, SimplifiedName(name), tpt, rhs) => ValDef(mods, name, transform(tpt), transform(rhs))
case Bind(SimplifiedName(name), rhs) => Bind(name, rhs)
case _ =>
super.transform(tree)