Skip to content

Commit

Permalink
Merge pull request #3477 from densh/topic/syntactic-empty-type-tree
Browse files Browse the repository at this point in the history
Rename EmptyTypTree into SyntacticEmptyTypeTree
  • Loading branch information
xeno-by committed Feb 7, 2014
2 parents 3306967 + a98eee5 commit 947baf2
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ trait Reifiers { self: Quasiquotes =>
reifyBuildCall(nme.SyntacticFunction, args, body)
case SyntacticIdent(name, isBackquoted) =>
reifyBuildCall(nme.SyntacticIdent, name, isBackquoted)
case SyntacticEmptyTypeTree() =>
reifyBuildCall(nme.SyntacticEmptyTypeTree)
case Q(Placeholder(Hole(tree, DotDot))) =>
mirrorBuildCall(nme.SyntacticBlock, tree)
case Q(other) =>
Expand Down
7 changes: 7 additions & 0 deletions src/reflect/scala/reflect/api/BuildUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ private[reflect] trait BuildUtils { self: Universe =>
def unapply(tree: Tree): Option[(Tree)]
}

val SyntacticEmptyTypeTree: SyntacticEmptyTypeTreeExtractor

trait SyntacticEmptyTypeTreeExtractor {
def apply(): TypeTree
def unapply(tt: TypeTree): Boolean
}

val SyntacticFor: SyntacticForExtractor
val SyntacticForYield: SyntacticForExtractor

Expand Down
24 changes: 13 additions & 11 deletions src/reflect/scala/reflect/internal/BuildUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -537,13 +537,15 @@ trait BuildUtils { self: SymbolTable =>
def unapply(tree: Tree): Option[Tree] = gen.Filter.unapply(tree)
}

// abstract over possible alternative representations of no type in valdef
protected object EmptyTypTree {
def unapply(tree: Tree): Boolean = tree match {
case EmptyTree => true
case tt: TypeTree if (tt.original == null || tt.original.isEmpty) => true
case _ => false
}
// If a tree in type position isn't provided by the user (e.g. `tpt` fields of
// `ValDef` and `DefDef`, function params etc), then it's going to be parsed as
// TypeTree with empty original and empty tpe. This extractor matches such trees
// so that one can write q"val x = 2" to match typecheck(q"val x = 2"). Note that
// TypeTree() is the only possible representation for empty trees in type positions.
// We used to sometimes receive EmptyTree in such cases, but not anymore.
object SyntacticEmptyTypeTree extends SyntacticEmptyTypeTreeExtractor {
def apply(): TypeTree = self.TypeTree()
def unapply(tt: TypeTree): Boolean = tt.original == null || tt.original.isEmpty
}

// match a sequence of desugared `val $pat = $value`
Expand All @@ -561,8 +563,8 @@ trait BuildUtils { self: SymbolTable =>
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: ${EmptyTypTree()} = $value" :: UnPatSeq(rest) =>
case ValDef(_, name, EmptyTypTree(), value) :: UnPatSeq(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) =>
Expand Down Expand Up @@ -604,8 +606,8 @@ trait BuildUtils { self: SymbolTable =>
def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
case Function(ValDef(Modifiers(PARAM, _, _), name, tpt, EmptyTree) :: Nil, body) =>
tpt match {
case EmptyTypTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body))
case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body))
case SyntacticEmptyTypeTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body))
case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body))
}
case UnVisitor(_, CaseDef(pat, EmptyTree, body) :: Nil) =>
Some((pat, body))
Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/internal/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ trait StdNames {
val SyntacticBlock: NameType = "SyntacticBlock"
val SyntacticClassDef: NameType = "SyntacticClassDef"
val SyntacticDefDef: NameType = "SyntacticDefDef"
val SyntacticEmptyTypeTree: NameType = "SyntacticEmptyTypeTree"
val SyntacticFilter: NameType = "SyntacticFilter"
val SyntacticFor: NameType = "SyntacticFor"
val SyntacticForYield: NameType = "SyntacticForYield"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ object TypeConstructionProps extends QuasiquoteProperties("type construction")
}

property("empty tq") = test {
val tt: TypeTree = tq" "
val tt: TypeTree = tq""
assert(tt.tpe == null)
assert(tt.original == null)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,10 @@ object TypeDeconstructionProps extends QuasiquoteProperties("type deconstruction
assert(arglast ≈ tq"C")
assert(restpe ≈ tq"D")
}

property("match empty type tree") = test {
val tq"" = TypeTree()
// matches because type tree isn't syntactic without original
val tq"" = tq"${typeOf[Int]}"
}
}
9 changes: 8 additions & 1 deletion test/files/scalacheck/quasiquotes/TypecheckedProps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,11 @@ object TypecheckedProps extends QuasiquoteProperties("typechecked") {
assert(f.original ≈ pq"Test.this.Cell")
assert(args ≈ List(pq"v"))
}
}

property("extract inferred val type") = test {
val typechecked = typecheck(q"val x = 42")
val q"val x = 42" = typechecked
val q"val x: ${tq""} = 42" = typechecked
val q"val x: ${t: Type} = 42" = typechecked
}
}

0 comments on commit 947baf2

Please sign in to comment.