summaryrefslogtreecommitdiff
path: root/src/compiler/scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala')
-rw-r--r--src/compiler/scala/reflect/macros/runtime/Typers.scala16
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala10
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala33
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala203
9 files changed, 168 insertions, 118 deletions
diff --git a/src/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala
index a51bee0fe8..f62c5e90ff 100644
--- a/src/compiler/scala/reflect/macros/runtime/Typers.scala
+++ b/src/compiler/scala/reflect/macros/runtime/Typers.scala
@@ -14,15 +14,11 @@ trait Typers {
def typeCheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
macroLogVerbose("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled))
val context = callsiteTyper.context
- val wrapper1 = if (!withImplicitViewsDisabled) (context.withImplicitsEnabled[Tree] _) else (context.withImplicitsDisabled[Tree] _)
- val wrapper2 = if (!withMacrosDisabled) (context.withMacrosEnabled[Tree] _) else (context.withMacrosDisabled[Tree] _)
- def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
- // if you get a "silent mode is not available past typer" here
- // don't rush to change the typecheck not to use the silent method when the silent parameter is false
- // typechecking uses silent anyways (e.g. in typedSelect), so you'll only waste your time
- // I'd advise fixing the root cause: finding why the context is not set to report errors
- // (also see reflect.runtime.ToolBoxes.typeCheckExpr for a workaround that might work for you)
- wrapper(callsiteTyper.silent(_.typed(tree, universe.analyzer.EXPRmode, pt), reportAmbiguousErrors = false) match {
+ val withImplicitFlag = if (!withImplicitViewsDisabled) (context.withImplicitsEnabled[Tree] _) else (context.withImplicitsDisabled[Tree] _)
+ val withMacroFlag = if (!withMacrosDisabled) (context.withMacrosEnabled[Tree] _) else (context.withMacrosDisabled[Tree] _)
+ def withContext(tree: => Tree) = withImplicitFlag(withMacroFlag(tree))
+ def typecheckInternal(tree: Tree) = callsiteTyper.silent(_.typed(tree, universe.analyzer.EXPRmode, pt), reportAmbiguousErrors = false)
+ universe.wrappingIntoTerm(tree)(wrappedTree => withContext(typecheckInternal(wrappedTree) match {
case universe.analyzer.SilentResultValue(result) =>
macroLogVerbose(result)
result
@@ -30,7 +26,7 @@ trait Typers {
macroLogVerbose(error.err.errMsg)
if (!silent) throw new TypecheckException(error.err.errPos, error.err.errMsg)
universe.EmptyTree
- })
+ }))
}
def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = {
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index cbbb4c8ba8..1005cd1ccf 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -21,6 +21,11 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo {
import definitions.ThrowableClass
+ // TODO these overrides, and the slow trickle of bugs that they solve (e.g. SI-8479),
+ // suggest that we should pursue an alternative design in which the DocDef nodes
+ // are eliminated from the tree before typer, and instead are modelled as tree
+ // attachments.
+
/** Is tree legal as a member definition of an interface?
*/
override def isInterfaceMember(tree: Tree): Boolean = tree match {
@@ -28,6 +33,11 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo {
case _ => super.isInterfaceMember(tree)
}
+ override def isConstructorWithDefault(t: Tree) = t match {
+ case DocDef(_, definition) => isConstructorWithDefault(definition)
+ case _ => super.isConstructorWithDefault(t)
+ }
+
/** Is tree a pure (i.e. non-side-effecting) definition?
*/
override def isPureDef(tree: Tree): Boolean = tree match {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index dbfaa2c531..56fc4d7594 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -179,6 +179,7 @@ trait ScalaSettings extends AbsScalaSettings
val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes")
val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
+ val YfundepMaterialization = BooleanSetting("-Yfundep-materialization", "Turn on the 2.11 behavior of macro expansion being able to influence type inference in implicit searches")
def stop = stopAfter
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 2955986a7e..6991cfa37b 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -436,9 +436,13 @@ abstract class ClassfileParser {
// SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
// therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
// that are not in their correct place (see bug for details)
- if (!settings.isScaladoc)
- warning(s"Class $name not found - continuing with a stub.")
- return NoSymbol.newClass(name.toTypeName)
+
+ // TODO More consistency with use of stub symbols in `Unpickler`
+ // - better owner than `NoSymbol`
+ // - remove eager warning
+ val msg = s"Class $name not found - continuing with a stub."
+ if (!settings.isScaladoc) warning(msg)
+ return NoSymbol.newStubSymbol(name.toTypeName, msg)
}
val completer = new global.loaders.ClassfileLoader(file)
var owner: Symbol = rootMirror.RootClass
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index d6ec5f2cb0..c0844ec8fc 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -713,6 +713,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
var expectedTpe = expandee.tpe
if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType
+ if (settings.YfundepMaterialization.value) {
+ // approximation is necessary for whitebox macros to guide type inference
+ // read more in the comments for onDelayed below
+ val undetparams = expectedTpe collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol }
+ expectedTpe = deriveTypeWithWildcards(undetparams)(expectedTpe)
+ }
+
// also see http://groups.google.com/group/scala-internals/browse_thread/thread/492560d941b315cc
val expanded0 = duplicateAndKeepPositions(expanded)
val expanded1 = typecheck("macro def return type", expanded0, expectedTpe)
@@ -766,9 +773,24 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
// (in a sense that a datatype's uniform representation is unambiguously determined by the datatype,
// e.g. for Foo it will be Int :: String :: Boolean :: HNil), there's no way to convey this information
// to the typechecker. Therefore the typechecker will infer Nothing for L, which is hardly what we want.
+ //
+ // =========== THE SOLUTION ===========
+ //
+ // To give materializers a chance to say their word before vanilla inference kicks in,
+ // we infer as much as possible (e.g. in the example above even though L is hopeless, C still can be inferred to Foo)
+ // and then trigger macro expansion with the undetermined type parameters still there.
+ // Thanks to that the materializer can take a look at what's going on and react accordingly.
+ //
+ // NOTE: This functionality is only available under the -Xfundep-materialization flag in Scala 2.10,
+ // but is enabled by default in Scala 2.11.
val shouldInstantiate = typer.context.undetparams.nonEmpty && !inPolyMode(mode)
- if (shouldInstantiate) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt)
- else delayed
+ if (shouldInstantiate) {
+ if (settings.YfundepMaterialization.value) {
+ forced += delayed
+ typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false)
+ macroExpand(typer, delayed, mode, pt)
+ } else typer.instantiatePossiblyExpectingUnit(delayed, mode, pt)
+ } else delayed
case Fallback(fallback) =>
typer.context.withImplicitsEnabled(typer.typed(fallback, EXPRmode, pt))
case Other(result) =>
@@ -886,10 +908,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
* 2) undetparams (sym.isTypeParameter && !sym.isSkolem)
*/
var hasPendingMacroExpansions = false
+ private val forced = perRunCaches.newWeakSet[Tree]
private val delayed = perRunCaches.newWeakMap[Tree, scala.collection.mutable.Set[Int]]
private def isDelayed(expandee: Tree) = delayed contains expandee
private def calculateUndetparams(expandee: Tree): scala.collection.mutable.Set[Int] =
- delayed.get(expandee).getOrElse {
+ // !settings.YfundepMaterialization.value implies forced.isEmpty
+ if (forced(expandee)) scala.collection.mutable.Set[Int]()
+ else delayed.getOrElse(expandee, {
val calculated = scala.collection.mutable.Set[Symbol]()
expandee foreach (sub => {
def traverse(sym: Symbol) = if (sym != null && (undetparams contains sym.id)) calculated += sym
@@ -898,7 +923,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
})
macroLogVerbose("calculateUndetparams: %s".format(calculated))
calculated map (_.id)
- }
+ })
private val undetparams = perRunCaches.newSet[Int]
def notifyUndetparamsAdded(newUndets: List[Symbol]): Unit = {
undetparams ++= newUndets map (_.id)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index bb938074cb..45da6d80d6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -663,10 +663,7 @@ trait Namers extends MethodSynthesis {
val m = ensureCompanionObject(tree, caseModuleDef)
m.moduleClass.updateAttachment(new ClassForCaseCompanionAttachment(tree))
}
- val hasDefault = impl.body exists {
- case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => mexists(vparamss)(_.mods.hasDefault)
- case _ => false
- }
+ val hasDefault = impl.body exists treeInfo.isConstructorWithDefault
if (hasDefault) {
val m = ensureCompanionObject(tree)
m.updateAttachment(new ConstructorDefaultsAttachment(tree, null))
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 70f2f41ec7..307e17d97a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -175,9 +175,9 @@ trait NamesDefaults { self: Analyzer =>
// setSymbol below is important because the 'selected' function might be overloaded. by
// assigning the correct method symbol, typedSelect will just assign the type. the reason
// to still call 'typed' is to correctly infer singleton types, SI-5259.
- val selectPos =
- if(qual.pos.isRange && baseFun.pos.isRange) qual.pos.union(baseFun.pos).withStart(Math.min(qual.pos.end, baseFun.pos.end))
- else baseFun.pos
+ val selectPos =
+ if(qual.pos.isRange && baseFun1.pos.isRange) qual.pos.union(baseFun1.pos).withStart(Math.min(qual.pos.end, baseFun1.pos.end))
+ else baseFun1.pos
val f = blockTyper.typedOperator(Select(newQual, selected).setSymbol(baseFun1.symbol).setPos(selectPos))
if (funTargs.isEmpty) f
else TypeApply(f, funTargs).setType(baseFun.tpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index e09a509839..8153766784 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4934,7 +4934,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (tree.isInstanceOf[PostfixSelect])
checkFeature(tree.pos, PostfixOpsFeature, name.decode)
- if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember)
+ if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember && !tree1.symbol.isMacro)
checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString)
if (qual1.hasSymbolWhich(_.isRootPackage)) treeCopy.Ident(tree1, name)
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 8803980dac..650598f9db 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -5,9 +5,10 @@ import scala.tools.nsc.reporters._
import scala.tools.nsc.CompilerCommand
import scala.tools.nsc.Global
import scala.tools.nsc.typechecker.Modes
-import scala.tools.nsc.io.VirtualDirectory
+import scala.tools.nsc.io.{AbstractFile, VirtualDirectory}
import scala.tools.nsc.interpreter.AbstractFileClassLoader
import scala.tools.nsc.util.FreshNameCreator
+import scala.tools.nsc.util.CommandLineParser
import scala.tools.nsc.ast.parser.Tokens.EOF
import scala.reflect.internal.Flags._
import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, NoFile}
@@ -17,6 +18,7 @@ import scala.reflect.NameTransformer
import scala.reflect.api.JavaUniverse
import scala.reflect.io.NoAbstractFile
import scala.tools.nsc.interactive.RangePositions
+import scala.reflect.internal.FatalError
abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
@@ -32,6 +34,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, factorySelf.mirror.classLoader)
lazy val mirror: u.Mirror = u.runtimeMirror(classLoader)
+ lazy val arguments = CommandLineParser.tokenize(options)
+ lazy val virtualDirectory =
+ arguments.iterator.sliding(2).collectFirst{ case Seq("-d", dir) => dir } match {
+ case Some(outDir) => AbstractFile.getDirectory(outDir)
+ case None => new VirtualDirectory("(memory)", None)
+ }
+
class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter: Reporter)
extends ReflectGlobal(settings, reporter, toolBoxSelf.classLoader) {
import definitions._
@@ -50,7 +59,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
// should be called after every use of ToolBoxGlobal in order to prevent leaks
- // there's the `withCleanupCaches` method defined below, which provides a convenient interface for that
def cleanupCaches(): Unit = {
perRunCaches.clearAll()
undoLog.clear()
@@ -59,11 +67,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lastSeenContext = null
}
- def withCleanupCaches[T](body: => T): T =
- try body
- finally cleanupCaches()
-
- 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
@@ -84,14 +88,8 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
msg += "if you have troubles tracking free type variables, consider using -Xlog-free-types"
throw ToolBoxError(msg)
}
- }
-
- 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]) = {
@@ -121,50 +119,51 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
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
- var (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = false)
- 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(ObjectClass.tpe), newScope, ownerClass))
- val owner = ownerClass.newLocalDummy(expr.pos)
- var 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)
- }
- var invertedIndex = freeTerms map (_.swap)
- // todo. also fixup singleton types
- unwrapped = new Transformer {
- override def transform(tree: Tree): Tree =
- tree match {
- case Ident(name) 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)))).traverse(unwrapped)
- unwrapped = if (expr0.isTerm) unwrapped else unwrapFromTerm(unwrapped)
- unwrapped
+ wrappingIntoTerm(verify(expr0))(expr1 => {
+ // need to wrap the expr, because otherwise you won't be able to typecheck macros against something that contains free vars
+ 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)
+
+ // [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(ObjectClass.tpe), newScope, ownerClass))
+ val owner = ownerClass.newLocalDummy(expr2.pos)
+ var currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr2, 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 expr3 = wrapper(transform(currentTyper, expr2))
+ var (dummies1, result) = expr3 match {
+ case Block(dummies, result) => (dummies, result)
+ case result => (Nil, result)
+ }
+ var invertedIndex = freeTerms map (_.swap)
+ // todo. also fixup singleton types
+ result = new Transformer {
+ override def transform(tree: Tree): Tree =
+ tree match {
+ case Ident(name) 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)))).traverse(result)
+ result
+ })
}
def typeCheck(expr: Tree, pt: Type, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree =
@@ -317,42 +316,51 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
}
- // todo. is not going to work with quoted arguments with embedded whitespaces
- lazy val arguments = options.split(" ")
+ trait CompilerApi {
+ val compiler: ToolBoxGlobal
+ val importer: compiler.Importer { val from: u.type }
+ val exporter: u.Importer { val from: compiler.type }
+ }
- lazy val virtualDirectory =
- (arguments zip arguments.tail).collect{ case ("-d", dir) => dir }.lastOption match {
- case Some(outDir) => scala.tools.nsc.io.AbstractFile.getDirectory(outDir)
- case None => new VirtualDirectory("(memory)", None)
+ object withCompilerApi {
+ private object api extends CompilerApi {
+ lazy val compiler: ToolBoxGlobal = {
+ try {
+ val errorFn: String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition, msg, frontEnd.ERROR)
+ val command = new CompilerCommand(arguments.toList, errorFn)
+ val settings = command.settings
+ settings.outputDirs setSingleOutput virtualDirectory
+ val reporter = frontEndToReporter(frontEnd, command.settings)
+ val instance =
+ if (settings.Yrangepos.value) new ToolBoxGlobal(settings, reporter) with RangePositions
+ else new ToolBoxGlobal(settings, reporter)
+ if (frontEnd.hasErrors) {
+ var msg = "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL
+ msg += frontEnd.infos map (_.msg) mkString EOL
+ throw ToolBoxError(msg)
+ }
+ instance
+ } catch {
+ case ex: Throwable =>
+ var msg = "reflective compilation has failed: cannot initialize the compiler due to %s".format(ex.toString)
+ throw ToolBoxError(msg, ex)
+ }
+ }
+
+ lazy val importer = compiler.mkImporter(u)
+ lazy val exporter = importer.reverse
}
- lazy val compiler: ToolBoxGlobal = {
- try {
- val errorFn: String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition, msg, frontEnd.ERROR)
- val command = new CompilerCommand(arguments.toList, errorFn)
- val settings = command.settings
- settings.outputDirs setSingleOutput virtualDirectory
- val reporter = frontEndToReporter(frontEnd, command.settings)
- val instance =
- if (settings.Yrangepos.value) new ToolBoxGlobal(settings, reporter) with RangePositions
- else new ToolBoxGlobal(settings, reporter)
- if (frontEnd.hasErrors) {
- var msg = "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL
- msg += frontEnd.infos map (_.msg) mkString EOL
- throw ToolBoxError(msg)
- }
- instance
- } catch {
- case ex: Throwable =>
- var msg = "reflective compilation has failed: cannot initialize the compiler due to %s".format(ex.toString)
- throw ToolBoxError(msg, ex)
+ def apply[T](f: CompilerApi => T): T = {
+ object FatalError { def unapply(ex: Throwable) = ex match { case _: FatalError | _: AssertionError => Some(ex); case _ => None } }
+ try f(api) catch { case FatalError(ex) => throw ToolBoxError(s"fatal compiler error", ex) }
+ finally api.compiler.cleanupCaches()
}
}
- lazy val importer = compiler.mkImporter(u)
- lazy val exporter = importer.reverse
+ def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
- def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = compiler.withCleanupCaches {
if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType)
var ctree: compiler.Tree = importer.importTree(tree)
var cexpectedType: compiler.Type = importer.importType(expectedType)
@@ -372,7 +380,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
inferImplicit(tree, viewTpe, isView = true, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
}
- private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = compiler.withCleanupCaches {
+ private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
+
if (compiler.settings.verbose.value) println("importing "+pt, ", tree = "+tree+", pos = "+pos)
var ctree: compiler.Tree = importer.importTree(tree)
var cpt: compiler.Type = importer.importType(pt)
@@ -384,31 +394,38 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
uitree
}
- def resetAllAttrs(tree: u.Tree): u.Tree = {
+ def resetAllAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
val ctree: compiler.Tree = importer.importTree(tree)
val ttree: compiler.Tree = compiler.resetAllAttrs(ctree)
val uttree = exporter.importTree(ttree)
uttree
}
- def resetLocalAttrs(tree: u.Tree): u.Tree = {
+ def resetLocalAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
val ctree: compiler.Tree = importer.importTree(tree)
val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree)
val uttree = exporter.importTree(ttree)
uttree
}
- def showAttributed(tree: u.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String =
+ def showAttributed(tree: u.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = withCompilerApi { compilerApi =>
+ import compilerApi._
compiler.showAttributed(importer.importTree(tree), printTypes, printIds, printKinds)
+ }
- def parse(code: String): u.Tree = {
+ def parse(code: String): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
if (compiler.settings.verbose.value) println("parsing "+code)
val ctree: compiler.Tree = compiler.parse(code)
val utree = exporter.importTree(ctree)
utree
}
- def compile(tree: u.Tree): () => Any = {
+ def compile(tree: u.Tree): () => Any = withCompilerApi { compilerApi =>
+ import compilerApi._
+
if (compiler.settings.verbose.value) println("importing "+tree)
val ctree: compiler.Tree = importer.importTree(tree)