summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/reflect
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-02-16 16:17:03 +0100
committerJason Zaugg <jzaugg@gmail.com>2014-02-16 16:17:03 +0100
commitd7332c0c6594fe2f7c2042410c1c8792c2a7658a (patch)
tree9a14d95704476f582e8fceb0230bb913f445beee /src/compiler/scala/tools/reflect
parentb0ac4da8a300f3a2c73423ec6f783d1bfb708843 (diff)
parent609047ba372ceaf06916d3361954bc949a6906ee (diff)
downloadscala-d7332c0c6594fe2f7c2042410c1c8792c2a7658a.tar.gz
scala-d7332c0c6594fe2f7c2042410c1c8792c2a7658a.tar.bz2
scala-d7332c0c6594fe2f7c2042410c1c8792c2a7658a.zip
Merge pull request #3513 from xeno-by/topic/typecheck-member-defs
typecheck(q"class C") no longer crashes
Diffstat (limited to 'src/compiler/scala/tools/reflect')
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala104
1 files changed, 48 insertions, 56 deletions
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 7bae3203c2..d459b4f981 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -64,7 +64,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lastSeenContext = null
}
- def verify(expr: Tree): Unit = {
+ def verify(expr: Tree): Tree = {
// Previously toolboxes used to typecheck their inputs before compiling.
// Actually, the initial demo by Martin first typechecked the reified tree,
// then ran it, which typechecked it again, and only then launched the
@@ -86,14 +86,8 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
|if you have troubles tracking free type variables, consider using -Xlog-free-types
""".stripMargin.trim)
}
- }
-
- def wrapIntoTerm(tree: Tree): Tree =
- if (!tree.isTerm) Block(List(tree), Literal(Constant(()))) else tree
- def unwrapFromTerm(tree: Tree): Tree = tree match {
- case Block(List(tree), Literal(Constant(()))) => tree
- case tree => tree
+ expr
}
def extractFreeTerms(expr0: Tree, wrapFreeTermRefs: Boolean): (Tree, scala.collection.mutable.LinkedHashMap[FreeTermSymbol, TermName]) = {
@@ -122,53 +116,51 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
(expr, freeTermNames)
}
- def transformDuringTyper(expr0: Tree, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean)(transform: (analyzer.Typer, Tree) => Tree): Tree = {
- verify(expr0)
-
- // need to wrap the expr, because otherwise you won't be able to typecheck macros against something that contains free vars
- val exprAndFreeTerms = extractFreeTerms(expr0, wrapFreeTermRefs = false)
- var expr = exprAndFreeTerms._1
- val freeTerms = exprAndFreeTerms._2
- val dummies = freeTerms.map{ case (freeTerm, name) => ValDef(NoMods, name, TypeTree(freeTerm.info), Select(Ident(PredefModule), newTermName("$qmark$qmark$qmark"))) }.toList
- expr = Block(dummies, wrapIntoTerm(expr))
-
- // [Eugene] how can we implement that?
- // !!! Why is this is in the empty package? If it's only to make
- // it inaccessible then please put it somewhere designed for that
- // rather than polluting the empty package with synthetics.
- val ownerClass = rootMirror.EmptyPackageClass.newClassSymbol(newTypeName("<expression-owner>"))
- build.setTypeSignature(ownerClass, ClassInfoType(List(ObjectTpe), newScope, ownerClass))
- val owner = ownerClass.newLocalDummy(expr.pos)
- val currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr, owner))
- val wrapper1 = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _)
- val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _)
- def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
-
- val run = new Run
- run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works
- phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
- currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
- reporter.reset()
-
- val expr1 = wrapper(transform(currentTyper, expr))
- var (dummies1, unwrapped) = expr1 match {
- case Block(dummies, unwrapped) => ((dummies, unwrapped))
- case unwrapped => ((Nil, unwrapped))
- }
- val invertedIndex = freeTerms map (_.swap)
- // todo. also fixup singleton types
- unwrapped = new Transformer {
- override def transform(tree: Tree): Tree =
- tree match {
- case Ident(name: TermName) if invertedIndex contains name =>
- Ident(invertedIndex(name)) setType tree.tpe
- case _ =>
- super.transform(tree)
- }
- }.transform(unwrapped)
- new TreeTypeSubstituter(dummies1 map (_.symbol), dummies1 map (dummy => SingleType(NoPrefix, invertedIndex(dummy.symbol.name.toTermName)))).traverse(unwrapped)
- unwrapped = if (expr0.isTerm) unwrapped else unwrapFromTerm(unwrapped)
- unwrapped
+ def transformDuringTyper(expr: Tree, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean)(transform: (analyzer.Typer, Tree) => Tree): Tree = {
+ wrappingIntoTerm(verify(expr))(expr1 => {
+ // need to extract free terms, because otherwise you won't be able to typecheck macros against something that contains them
+ val exprAndFreeTerms = extractFreeTerms(expr1, wrapFreeTermRefs = false)
+ var expr2 = exprAndFreeTerms._1
+ val freeTerms = exprAndFreeTerms._2
+ val dummies = freeTerms.map{ case (freeTerm, name) => ValDef(NoMods, name, TypeTree(freeTerm.info), Select(Ident(PredefModule), newTermName("$qmark$qmark$qmark"))) }.toList
+ expr2 = Block(dummies, expr2)
+
+ // !!! Why is this is in the empty package? If it's only to make
+ // it inaccessible then please put it somewhere designed for that
+ // rather than polluting the empty package with synthetics.
+ // [Eugene] how can we implement that?
+ val ownerClass = rootMirror.EmptyPackageClass.newClassSymbol(newTypeName("<expression-owner>"))
+ build.setTypeSignature(ownerClass, ClassInfoType(List(ObjectTpe), newScope, ownerClass))
+ val owner = ownerClass.newLocalDummy(expr2.pos)
+ val currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr2, owner))
+ val withImplicitFlag = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _)
+ val withMacroFlag = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _)
+ def withContext (tree: => Tree) = withImplicitFlag(withMacroFlag(tree))
+
+ val run = new Run
+ run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works
+ phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
+ currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
+ reporter.reset()
+
+ val expr3 = withContext(transform(currentTyper, expr2))
+ var (dummies1, result) = expr3 match {
+ case Block(dummies, result) => ((dummies, result))
+ case result => ((Nil, result))
+ }
+ val invertedIndex = freeTerms map (_.swap)
+ result = new Transformer {
+ override def transform(tree: Tree): Tree =
+ tree match {
+ case Ident(name: TermName) if invertedIndex contains name =>
+ Ident(invertedIndex(name)) setType tree.tpe
+ case _ =>
+ super.transform(tree)
+ }
+ }.transform(result)
+ new TreeTypeSubstituter(dummies1 map (_.symbol), dummies1 map (dummy => SingleType(NoPrefix, invertedIndex(dummy.symbol.name.toTermName)))).traverse(result)
+ result
+ })
}
def typecheck(expr: Tree, pt: Type, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree =
@@ -207,7 +199,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
def compile(expr0: Tree): () => Any = {
- val expr = wrapIntoTerm(expr0)
+ val expr = build.SyntacticBlock(expr0 :: Nil)
val freeTerms = expr.freeTerms // need to calculate them here, because later on they will be erased
val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order