diff options
7 files changed, 110 insertions, 54 deletions
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index aa27f6030f..d5a310668e 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -123,7 +123,7 @@ trait Reifiers { self: Quasiquotes => case TuplePlaceholder(args) => reifyTuple(args) case TupleTypePlaceholder(args) => reifyTupleType(args) case FunctionTypePlaceholder(argtpes, restpe) => reifyFunctionType(argtpes, restpe) - case CasePlaceholder(tree, location, _) => reifyCase(tree, location) + case CasePlaceholder(tree, _, _) => tree case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree) case EarlyDefPlaceholder(tree, _, _) => reifyEarlyDef(tree) case PackageStatPlaceholder(tree, _, _) => reifyPackageStat(tree) @@ -175,6 +175,10 @@ trait Reifiers { self: Quasiquotes => reifyTree(other) case Block(stats, last) => reifyBuildCall(nme.SyntacticBlock, stats :+ last) + case Try(block, catches, finalizer) => + reifyBuildCall(nme.SyntacticTry, block, catches, finalizer) + case Match(selector, cases) => + reifyBuildCall(nme.SyntacticMatch, selector, cases) // parser emits trees with scala package symbol to ensure // that some names hygienically point to various scala package // members; we need to preserve this symbol to preserve @@ -199,11 +203,6 @@ trait Reifiers { self: Quasiquotes => super.reifyName(name) } - def reifyCase(tree: Tree, location: Location) = { - if (holesHaveTypes && !(location.tpe <:< caseDefType)) c.abort(tree.pos, s"$caseDefType expected but ${location.tpe} found") - tree - } - def reifyTuple(args: List[Tree]) = args match { case Nil => reify(Literal(Constant(()))) case List(hole @ Placeholder(_, _, NoDot)) => reify(hole) diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 673cf0d0b4..d2b9cd20fd 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -125,9 +125,9 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticClassDef: SyntacticClassDefExtractor trait SyntacticClassDefExtractor { - def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], - constrMods: Modifiers, vparamss: List[List[ValDef]], earlyDefs: List[Tree], - parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef + def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], + constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree], + parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]], List[Tree], List[Tree], ValDef, List[Tree])] } @@ -135,8 +135,8 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticTraitDef: SyntacticTraitDefExtractor trait SyntacticTraitDefExtractor { - def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], - earlyDefs: List[Tree], parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef + def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], + earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], List[Tree], List[Tree], ValDef, List[Tree])] } @@ -145,7 +145,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree + parents: List[Tree], selfType: Tree, body: List[Tree]): Tree def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -153,7 +153,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree + parents: List[Tree], selfType: Tree, body: List[Tree]): Tree def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -175,7 +175,7 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticNew: SyntacticNewExtractor trait SyntacticNewExtractor { - def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree + def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): Tree def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])] } @@ -189,7 +189,7 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticFunction: SyntacticFunctionExtractor trait SyntacticFunctionExtractor { - def apply(params: List[ValDef], body: Tree): Tree + def apply(params: List[Tree], body: Tree): Tree def unapply(tree: Tree): Option[(List[ValDef], Tree)] } @@ -197,7 +197,7 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticDefDef: SyntacticDefDefExtractor trait SyntacticDefDefExtractor { - def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef + def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)] } @@ -246,6 +246,18 @@ private[reflect] trait BuildUtils { self: Universe => def unapply(tree: Tree): Option[(List[Tree], Tree)] } + val SyntacticMatch: SyntacticMatchExtractor + trait SyntacticMatchExtractor { + def apply(selector: Tree, cases: List[Tree]): Match + def unapply(tree: Match): Option[(Tree, List[CaseDef])] + } + + val SyntacticTry: SyntacticTryExtractor + trait SyntacticTryExtractor { + def apply(block: Tree, catches: List[Tree], finalizer: Tree): Try + def unapply(tree: Try): Option[(Tree, List[CaseDef], Tree)] + } + val SyntacticIdent: SyntacticIdentExtractor trait SyntacticIdentExtractor { def apply(name: Name, isBackquoted: Boolean = false): Ident diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 22c10520b5..22e2bf4cad 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -71,12 +71,16 @@ trait BuildUtils { self: SymbolTable => def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation) - def mkVparamss(argss: List[List[ValDef]]): List[List[ValDef]] = argss.map(_.map(mkParam)) + def mkVparamss(argss: List[List[Tree]]): List[List[ValDef]] = argss.map(_.map(mkParam)) - def mkParam(vd: ValDef): ValDef = { - var newmods = (vd.mods | PARAM) & (~DEFERRED) - if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM - copyValDef(vd)(mods = newmods) + def mkParam(tree: Tree): ValDef = tree match { + case vd: ValDef => + var newmods = (vd.mods | PARAM) & (~DEFERRED) + if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM + copyValDef(vd)(mods = newmods) + case _ => + throw new IllegalArgumentException(s"$tree is not valid represenation of function parameter, " + + """consider reformatting it into q"val $name: $T = $default" shape""") } def mkTparams(tparams: List[Tree]): List[TypeDef] = @@ -218,12 +222,25 @@ trait BuildUtils { self: SymbolTable => } } + protected def mkSelfType(tree: Tree) = tree match { + case vd: ValDef => + require(vd.rhs.isEmpty, "self types must have empty right hand side") + copyValDef(vd)(mods = (vd.mods | PRIVATE) & (~DEFERRED)) + case _ => + throw new IllegalArgumentException(s"$tree is not a valid representation of self type, " + + """consider reformatting into q"val $self: $T" shape""") + } + object SyntacticClassDef extends SyntacticClassDefExtractor { - def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], - constrMods: Modifiers, vparamss: List[List[ValDef]], earlyDefs: List[Tree], - parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef = { + def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], + constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree], + parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = { val extraFlags = PARAMACCESSOR | (if (mods.isCase) CASEACCESSOR else 0L) - val vparamss0 = vparamss.map { _.map { vd => copyValDef(vd)(mods = (vd.mods | extraFlags) & (~DEFERRED)) } } + val vparamss0 = vparamss.map { _.map { + case vd: ValDef => copyValDef(vd)(mods = (vd.mods | extraFlags) & (~DEFERRED)) + case tree => throw new IllegalArgumentException(s"$tree is not valid representation of class parameter, " + + """consider reformatting it into q"val $name: $T = $default" shape""") + } } val tparams0 = mkTparams(tparams) val parents0 = gen.mkParents(mods, if (mods.isCase) parents.filter { @@ -232,7 +249,8 @@ trait BuildUtils { self: SymbolTable => } else parents ) val body0 = earlyDefs ::: body - val templ = gen.mkTemplate(parents0, selfType, constrMods, vparamss0, body0) + val selfType0 = mkSelfType(selfType) + val templ = gen.mkTemplate(parents0, selfType0, constrMods, vparamss0, body0) gen.mkClassDef(mods, name, tparams0, templ) } @@ -247,10 +265,10 @@ trait BuildUtils { self: SymbolTable => } object SyntacticTraitDef extends SyntacticTraitDefExtractor { - def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], earlyDefs: List[Tree], - parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef = { + def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], earlyDefs: List[Tree], + parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = { val mods0 = mods | TRAIT | ABSTRACT - val templ = gen.mkTemplate(parents, selfType, Modifiers(TRAIT), Nil, earlyDefs ::: body) + val templ = gen.mkTemplate(parents, mkSelfType(selfType), Modifiers(TRAIT), Nil, earlyDefs ::: body) gen.mkClassDef(mods0, name, mkTparams(tparams), templ) } @@ -265,8 +283,8 @@ trait BuildUtils { self: SymbolTable => object SyntacticObjectDef extends SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: ValDef, body: List[Tree]) = - ModuleDef(mods, name, gen.mkTemplate(parents, selfType, NoMods, Nil, earlyDefs ::: body)) + parents: List[Tree], selfType: Tree, body: List[Tree]) = + ModuleDef(mods, name, gen.mkTemplate(parents, mkSelfType(selfType), NoMods, Nil, earlyDefs ::: body)) def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { case ModuleDef(mods, name, UnMkTemplate(parents, selfType, _, _, earlyDefs, body)) => @@ -278,7 +296,7 @@ trait BuildUtils { self: SymbolTable => object SyntacticPackageObjectDef extends SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree = + parents: List[Tree], selfType: Tree, body: List[Tree]): Tree = gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfType, body)) def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { @@ -368,11 +386,9 @@ trait BuildUtils { self: SymbolTable => } object SyntacticFunction extends SyntacticFunctionExtractor { - def apply(params: List[ValDef], body: Tree): Tree = { - val params0 = params.map { arg => - require(arg.rhs.isEmpty, "anonymous functions don't support default values") - mkParam(arg) - } + def apply(params: List[Tree], body: Tree): Tree = { + val params0 :: Nil = mkVparamss(params :: Nil) + require(params0.forall { _.rhs.isEmpty }, "anonymous functions don't support default values") Function(params0, body) } @@ -383,8 +399,8 @@ trait BuildUtils { self: SymbolTable => } object SyntacticNew extends SyntacticNewExtractor { - def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree = - gen.mkNew(parents, selfType, earlyDefs ::: body, NoPosition, NoPosition) + def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): Tree = + gen.mkNew(parents, mkSelfType(selfType), earlyDefs ::: body, NoPosition, NoPosition) def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])] = tree match { case SyntacticApplied(Select(New(SyntacticTypeApplied(ident, targs)), nme.CONSTRUCTOR), argss) => @@ -398,7 +414,7 @@ trait BuildUtils { self: SymbolTable => } object SyntacticDefDef extends SyntacticDefDefExtractor { - def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef = + def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = DefDef(mods, name, mkTparams(tparams), mkVparamss(vparamss), tpt, rhs) def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)] = tree match { @@ -664,6 +680,21 @@ trait BuildUtils { self: SymbolTable => } } + 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") + } + + object SyntacticMatch extends SyntacticMatchExtractor { + def apply(selector: Tree, cases: List[Tree]) = Match(selector, mkCases(cases)) + def unapply(tree: Match): Option[(Tree, List[CaseDef])] = Match.unapply(tree) + } + + object SyntacticTry extends SyntacticTryExtractor { + def apply(block: Tree, catches: List[Tree], finalizer: Tree) = Try(block, mkCases(catches), finalizer) + def unapply(tree: Try): Option[(Tree, List[CaseDef], Tree)] = Try.unapply(tree) + } + object SyntacticIdent extends SyntacticIdentExtractor { def apply(name: Name, isBackquoted: Boolean) = { val id = self.Ident(name) diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index f6c612f4eb..6cc0199458 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -598,10 +598,12 @@ trait StdNames { val SyntacticFunction: NameType = "SyntacticFunction" val SyntacticFunctionType: NameType = "SyntacticFunctionType" val SyntacticIdent: NameType = "SyntacticIdent" + val SyntacticMatch: NameType = "SyntacticMatch" val SyntacticNew: NameType = "SyntacticNew" val SyntacticObjectDef: NameType = "SyntacticObjectDef" val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef" val SyntacticTraitDef: NameType = "SyntacticTraitDef" + val SyntacticTry: NameType = "SyntacticTry" val SyntacticTuple: NameType = "SyntacticTuple" val SyntacticTupleType: NameType = "SyntacticTupleType" val SyntacticTypeApplied: NameType = "SyntacticTypeApplied" diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala index 2ec679e78b..2af656c7c9 100644 --- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala @@ -2,12 +2,25 @@ import org.scalacheck._, Prop._, Gen._, Arbitrary._ import scala.reflect.runtime.universe._, Flag._, build.ScalaDot object DefinitionConstructionProps - extends QuasiquoteProperties("definition construction") - with ClassConstruction - with TraitConstruction - with TypeDefConstruction - with ValDefConstruction - with PackageConstruction + extends QuasiquoteProperties("definition construction") + with ClassConstruction + with TraitConstruction + with TypeDefConstruction + with ValDefConstruction + with PackageConstruction { + 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]") + } +} trait ClassConstruction { self: QuasiquoteProperties => val anyRef = ScalaDot(TypeName("AnyRef")) @@ -283,7 +296,7 @@ trait MethodConstruction { self: QuasiquoteProperties => assertEqAst(q"@$a def foo", "@Foo[A,B] def foo") } - property("splice annotation with multiple argument lists") = test{ + property("splice annotation with multiple argument lists") = test { val a = q"new Foo(a)(b)" assertEqAst(q"@$a def foo", "@Foo(a)(b) def foo") } diff --git a/test/files/scalacheck/quasiquotes/ErrorProps.scala b/test/files/scalacheck/quasiquotes/ErrorProps.scala index cb46a60dbe..adad48fcdf 100644 --- a/test/files/scalacheck/quasiquotes/ErrorProps.scala +++ b/test/files/scalacheck/quasiquotes/ErrorProps.scala @@ -105,13 +105,6 @@ object ErrorProps extends QuasiquoteProperties("errors") { q"f($sb)" """) - property("casedef expected") = fails( - "reflect.runtime.universe.CaseDef expected but reflect.runtime.universe.Tree found", - """ - val t = EmptyTree - q"_ { case $t }" - """) - property("can't splice with ... card here") = fails( "Can't splice with ... here", """ diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index ded8fd9c16..338c379fc3 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -210,6 +210,12 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { assertEqAst(q"{..$xs}", "{1; 2}") } + property("SI-6842") = test { + val cases: List[Tree] = cq"a => b" :: cq"_ => c" :: Nil + assertEqAst(q"1 match { case ..$cases }", "1 match { case a => b case _ => c }") + assertEqAst(q"try 1 catch { case ..$cases }", "try 1 catch { case a => b case _ => c }") + } + property("SI-8009") = test { q"`foo`".asInstanceOf[reflect.internal.SymbolTable#Ident].isBackquoted } |