diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2014-02-16 16:16:49 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-02-16 16:16:49 +0100 |
commit | b0ac4da8a300f3a2c73423ec6f783d1bfb708843 (patch) | |
tree | d4f4b5d1acb4f60d0a0ef532093a3d662499306a /src/compiler | |
parent | 23326def4bf5bcfb7f5286707eed2f57a5da731d (diff) | |
parent | 8a27336c0e896d3fee6213068c77f23e62a0cd18 (diff) | |
download | scala-b0ac4da8a300f3a2c73423ec6f783d1bfb708843.tar.gz scala-b0ac4da8a300f3a2c73423ec6f783d1bfb708843.tar.bz2 scala-b0ac4da8a300f3a2c73423ec6f783d1bfb708843.zip |
Merge pull request #3455 from densh/topic/patdef
Fix SI-8202 and improve support for splicing patterns into vals
Diffstat (limited to 'src/compiler')
5 files changed, 64 insertions, 34 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) } { |