summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDen Shabalin <den.shabalin@gmail.com>2013-09-05 13:27:54 +0200
committerDen Shabalin <den.shabalin@gmail.com>2013-09-05 14:39:12 +0200
commit800f5acd0d7117bf953829da7c6d955e61e63bdc (patch)
treef7a28dbe2888cb6a2ba39a751c6dd24a296979d5
parent1585b52b6cbf2e2985ef3a02009466e56baf6e74 (diff)
downloadscala-800f5acd0d7117bf953829da7c6d955e61e63bdc.tar.gz
scala-800f5acd0d7117bf953829da7c6d955e61e63bdc.tar.bz2
scala-800f5acd0d7117bf953829da7c6d955e61e63bdc.zip
add support for function type splicing and extraction
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala3
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala4
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala7
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala4
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala7
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala22
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala4
-rw-r--r--test/files/scalacheck/quasiquotes/TypeConstructionProps.scala6
-rw-r--r--test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala6
10 files changed, 62 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index ed7c0d1a0a..28e3217449 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -516,8 +516,7 @@ abstract class TreeBuilder {
}
/** Create a tree representing the function type (argtpes) => restpe */
- def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
- AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe))
+ def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = gen.mkFunctionTypeTree(argtpes, restpe)
/** Append implicit parameter section if `contextBounds` nonempty */
def addEvidenceParams(owner: Name, vparamss: List[List[ValDef]], contextBounds: List[Tree]): List[List[ValDef]] = {
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index fe0809c869..868eccebcd 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -64,6 +64,10 @@ trait Parsers { self: Quasiquotes =>
case (head @ Ident(name)) :: Nil if holeMap.contains(name) => Block(Nil, head)
case _ => super.makeBlock(stats)
}
+
+ // tq"$a => $b"
+ override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
+ AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), argtpes :+ restpe)
}
import treeBuilder.{global => _, _}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index 5d7edcd75e..f0886b5735 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -113,6 +113,13 @@ trait Placeholders { self: Quasiquotes =>
}
}
+ object FunctionTypePlaceholder {
+ def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
+ case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res) => Some((args, res))
+ case _ => None
+ }
+ }
+
object SymbolPlaceholder {
def unapply(scrutinee: Any): Option[Tree] = scrutinee match {
case Placeholder(tree, SymbolLocation, _) => Some(tree)
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index a817afe741..9789801fac 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -45,6 +45,7 @@ trait Reifiers { self: Quasiquotes =>
case Placeholder(tree, _, 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(tree, location, _) => reifyCase(tree, location)
case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree)
case _ => EmptyTree
@@ -104,6 +105,9 @@ trait Reifiers { self: Quasiquotes =>
case _ => reifyBuildCall(nme.TupleTypeN, args)
}
+ def reifyFunctionType(argtpes: List[Tree], restpe: Tree) =
+ reifyBuildCall(nme.SyntacticFunctionType, argtpes, restpe)
+
def reifyRefineStat(tree: Tree) = tree
/** Splits list into a list of groups where subsequent elements are considered
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index a0a47fe23c..a74d3c137d 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -132,5 +132,12 @@ private[reflect] trait BuildUtils { self: Universe =>
def apply(stats: List[Tree]): Tree
def unapply(tree: Tree): Option[List[Tree]]
}
+
+ val SyntacticFunctionType: SyntacticFunctionTypeExtractor
+
+ trait SyntacticFunctionTypeExtractor {
+ def apply(argtpes: List[Tree], restpe: Tree): Tree
+ def unapply(tree: Tree): Option[(List[Tree], Tree)]
+ }
}
}
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index abe9e39067..e2894c5b94 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -5,7 +5,7 @@ package internal
import Flags._
trait BuildUtils { self: SymbolTable =>
- import definitions.{TupleClass, MaxTupleArity, ScalaPackage, UnitClass}
+ import definitions.{TupleClass, FunctionClass, MaxTupleArity, MaxFunctionArity, ScalaPackage, UnitClass}
class BuildImpl extends BuildApi {
@@ -200,6 +200,26 @@ trait BuildUtils { self: SymbolTable =>
}
}
+ object SyntacticFunctionType extends SyntacticFunctionTypeExtractor {
+ def apply(argtpes: List[Tree], restpe: Tree): Tree = {
+ require(argtpes.length <= MaxFunctionArity + 1, s"Function types with arity bigger than $MaxFunctionArity aren't supported")
+ gen.mkFunctionTypeTree(argtpes, restpe)
+ }
+
+ def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
+ case AppliedTypeTree(id: Ident, args @ (argtpes :+ restpe))
+ if args.length - 1 <= MaxFunctionArity && id.symbol == FunctionClass(args.length - 1) =>
+ Some((argtpes, restpe))
+ case AppliedTypeTree(Select(pack, fun), args @ (argtpes :+ restpe))
+ if args.length - 1 <= MaxFunctionArity && pack.symbol == ScalaPackage && fun == FunctionClass(args.length - 1).name =>
+ Some((argtpes, restpe))
+ case AppliedTypeTree(Select(Select(Ident(nme.ROOTPKG), nme.scala_), fun), args @ (argtpes :+ restpe))
+ if args.length - 1 <= MaxFunctionArity && fun == FunctionClass(args.length - 1).name =>
+ Some((argtpes, restpe))
+ case _ => None
+ }
+ }
+
object SyntacticBlock extends SyntacticBlockExtractor {
def apply(stats: List[Tree]): Tree = gen.mkBlock(stats)
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 0b1f444772..f4662296e2 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -249,6 +249,7 @@ trait StdNames {
// quasiquote-specific names
final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
+ final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$"
final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
// Annotation simple names, used in Namer
@@ -590,6 +591,7 @@ trait StdNames {
val SyntacticApplied: NameType = "SyntacticApplied"
val SyntacticBlock: NameType = "SyntacticBlock"
val SyntacticClassDef: NameType = "SyntacticClassDef"
+ val SyntacticFunctionType: NameType= "SyntacticFunctionType"
val SyntacticTypeApplied: NameType = "SyntacticTypeApplied"
val This: NameType = "This"
val ThisType: NameType = "ThisType"
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index 9623cc31f6..648c921eb7 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -415,6 +415,10 @@ abstract class TreeGen extends macros.TreeBuilder {
}
}
+ /** Create a tree representing the function type (argtpes) => restpe */
+ def mkFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
+ AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe))
+
/** Create block of statements `stats` */
def mkBlock(stats: List[Tree]): Tree =
if (stats.isEmpty) Literal(Constant(()))
diff --git a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala
index 459d733733..cac83ff8ac 100644
--- a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala
@@ -27,4 +27,10 @@ object TypeConstructionProps extends QuasiquoteProperties("type construction")
val stats = q"def foo" :: q"val x: Int" :: q"type Y = String" :: Nil
assert(tq"T { ..$stats }" ≈ tq"T { def foo; val x: Int; type Y = String }")
}
+
+ property("function type") = test {
+ val argtpes = tq"A" :: tq"B" :: Nil
+ val restpe = tq"C"
+ assert(tq"..$argtpes => $restpe" ≈ tq"(A, B) => C")
+ }
} \ No newline at end of file
diff --git a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala
index 5c919e55cb..02787c551b 100644
--- a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala
@@ -31,4 +31,10 @@ object TypeDeconstructionProps extends QuasiquoteProperties("type deconstruction
val tq"T { ..$stats }" = tq"T { def foo; val x: Int; type Y = String }"
assert(stats ≈ (q"def foo" :: q"val x: Int" :: q"type Y = String" :: Nil))
}
+
+ property("function type") = test {
+ val tq"..$argtpes => $restpe" = tq"(A, B) => C"
+ assert(argtpes ≈ (tq"A" :: tq"B" :: Nil))
+ assert(restpe ≈ tq"C")
+ }
} \ No newline at end of file