Skip to content
This repository has been archived by the owner on Apr 19, 2020. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
SI-6842 give up on strict static types in trees
  • Loading branch information
densh committed Nov 29, 2013
1 parent 78845ce commit 59ee22c
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 61 deletions.
1 change: 0 additions & 1 deletion src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
Expand Up @@ -210,5 +210,4 @@ trait Holes { self: Quasiquotes =>
if (card != NoDot) Some((card, innerTpe)) else None
}
}
object WithCard { def unapply(hole: Hole): Some[Cardinality] = Some(hole.cardinality) }
}
19 changes: 9 additions & 10 deletions src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
Expand Up @@ -117,12 +117,12 @@ trait Reifiers { self: Quasiquotes =>

def reifyTreePlaceholder(tree: Tree): Tree = tree match {
case Placeholder(hole: ApplyHole) if hole.tpe <:< treeType => hole.tree
case Placeholder(hole @ WithCard(NoDot)) if isReifyingPatterns => hole.tree
case Placeholder(WithCard(card @ Dot())) => c.abort(tree.pos, s"Can't $action with $card here")
case Placeholder(Hole(tree, NoDot)) if isReifyingPatterns => tree
case Placeholder(Hole(_, card @ Dot())) => c.abort(tree.pos, s"Can't $action with $card here")
case TuplePlaceholder(args) => reifyTuple(args)
case TupleTypePlaceholder(args) => reifyTupleType(args)
case FunctionTypePlaceholder(argtpes, restpe) => reifyFunctionType(argtpes, restpe)
case CasePlaceholder(hole) => reifyCase(hole)
case CasePlaceholder(hole) => hole.tree
case RefineStatPlaceholder(hole) => reifyRefineStat(hole)
case EarlyDefPlaceholder(hole) => reifyEarlyDef(hole)
case PackageStatPlaceholder(hole) => reifyPackageStat(hole)
Expand Down Expand Up @@ -178,6 +178,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
Expand All @@ -203,14 +207,9 @@ trait Reifiers { self: Quasiquotes =>
super.reifyName(name)
}

def reifyCase(hole: Hole) = hole match {
case hole: ApplyHole if !(hole.tpe <:< caseDefType) => c.abort(hole.pos, s"$caseDefType expected but ${hole.tpe} found")
case _ => hole.tree
}

def reifyTuple(args: List[Tree]) = args match {
case Nil => reify(Literal(Constant(())))
case List(hole @ Placeholder(WithCard(NoDot))) => reify(hole)
case List(hole @ Placeholder(Hole(_, NoDot))) => reify(hole)
case List(Placeholder(_)) => reifyBuildCall(nme.SyntacticTuple, args)
// in a case we only have one element tuple without
// any cardinality annotations this means that this is
Expand All @@ -221,7 +220,7 @@ trait Reifiers { self: Quasiquotes =>

def reifyTupleType(args: List[Tree]) = args match {
case Nil => reify(Select(Ident(nme.scala_), tpnme.Unit))
case List(hole @ Placeholder(WithCard(NoDot))) => reify(hole)
case List(hole @ Placeholder(Hole(_, NoDot))) => reify(hole)
case List(Placeholder(_)) => reifyBuildCall(nme.SyntacticTupleType, args)
case List(other) => reify(other)
case _ => reifyBuildCall(nme.SyntacticTupleType, args)
Expand Down
32 changes: 22 additions & 10 deletions src/reflect/scala/reflect/api/BuildUtils.scala
Expand Up @@ -125,18 +125,18 @@ 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])]
}

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])]
}
Expand All @@ -145,15 +145,15 @@ 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])]
}

val SyntacticPackageObjectDef: SyntacticPackageObjectDefExtractor

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])]
}

Expand All @@ -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])]
}

Expand All @@ -189,15 +189,15 @@ 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)]
}

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)]
}
Expand Down Expand Up @@ -255,5 +255,17 @@ private[reflect] trait BuildUtils { self: Universe =>
trait UnliftHelper2[T] {
def unapply(lst: List[List[Tree]]): Option[List[List[T]]]
}

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)]
}
}
}
79 changes: 55 additions & 24 deletions src/reflect/scala/reflect/internal/BuildUtils.scala
Expand Up @@ -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] =
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}

Expand All @@ -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)
}

Expand All @@ -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)) =>
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}

Expand All @@ -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) =>
Expand All @@ -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 {
Expand Down Expand Up @@ -677,6 +693,21 @@ trait BuildUtils { self: SymbolTable =>
case annottee => Some(annottee)
}
}

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)
}
}

val build: BuildImpl = new BuildImpl
Expand Down
6 changes: 4 additions & 2 deletions src/reflect/scala/reflect/internal/StdNames.scala
Expand Up @@ -606,10 +606,12 @@ trait StdNames {
val SyntacticForYield: NameType = "SyntacticForYield"
val SyntacticFunction: NameType = "SyntacticFunction"
val SyntacticFunctionType: NameType = "SyntacticFunctionType"
val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef"
val SyntacticObjectDef: NameType = "SyntacticObjectDef"
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"
Expand Down
Expand Up @@ -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"))
Expand Down Expand Up @@ -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")
}
Expand Down
Expand Up @@ -88,6 +88,22 @@ trait ClassDeconstruction { self: QuasiquoteProperties =>
matches("class Foo { self => bar(self) }")
matches("case class Foo(x: Int)")
}

// property("SI-7979") = test {
// val PARAMACCESSOR = (1 << 29).toLong.asInstanceOf[FlagSet]
// assertThrows[MatchError] {
// val build.SyntacticClassDef(_, _, _, _, _, _, _, _, _) =
// ClassDef(
// Modifiers(), TypeName("Foo"), List(),
// Template(
// List(Select(Ident(TermName("scala")), TypeName("AnyRef"))),
// noSelfType,
// List(
// //ValDef(Modifiers(PRIVATE | LOCAL | PARAMACCESSOR), TermName("x"), Ident(TypeName("Int")), EmptyTree),
// DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List(ValDef(Modifiers(PARAM | PARAMACCESSOR), TermName("x"),
// Ident(TypeName("Int")), EmptyTree))), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))))))
// }
// }
}

trait ModsDeconstruction { self: QuasiquoteProperties =>
Expand Down
7 changes: 0 additions & 7 deletions test/files/scalacheck/quasiquotes/ErrorProps.scala
Expand Up @@ -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",
"""
Expand Down

0 comments on commit 59ee22c

Please sign in to comment.