summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-05-22 15:13:22 +0000
committerMartin Odersky <odersky@gmail.com>2009-05-22 15:13:22 +0000
commit22b60f2f2b6dbacbd528d10cb18da8e5afe750da (patch)
treed4cf7da9ae04026febcaeb779f22a3b10aaf7b4e /src
parent182a5cbf022de71b7fd89d996ab1a922aa6e7602 (diff)
downloadscala-22b60f2f2b6dbacbd528d10cb18da8e5afe750da.tar.gz
scala-22b60f2f2b6dbacbd528d10cb18da8e5afe750da.tar.bz2
scala-22b60f2f2b6dbacbd528d10cb18da8e5afe750da.zip
some documentation; statistics wrt implicits; n...
some documentation; statistics wrt implicits; new presentation compiler
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala4
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala205
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Main.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ScalaDoc.scala2
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Scanners.scala46
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Global.scala41
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala32
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala36
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala33
-rw-r--r--src/compiler/scala/tools/nsc/util/WorkScheduler.scala43
13 files changed, 339 insertions, 119 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index b38ac01c8a..5385a5a54f 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -26,6 +26,7 @@ trait CompilationUnits { self: Global =>
* To get their sourcefiles, you need to dereference with .sourcefile
*/
val depends = new HashSet[Symbol]
+
/** so we can relink
*/
val defined = new HashSet[Symbol]
@@ -40,6 +41,9 @@ trait CompilationUnits { self: Global =>
/** used to track changes in a signature */
var pickleHash : Long = 0
+ /** the current edit point offset */
+ var editPoint: Int = -1
+
def position(pos: Int) = source.position(pos)
/** The icode representation of classes in this compilation unit.
diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala
index 5d14064728..010d183bc8 100644
--- a/src/compiler/scala/tools/nsc/CompileServer.scala
+++ b/src/compiler/scala/tools/nsc/CompileServer.scala
@@ -113,7 +113,7 @@ class StandardCompileServer extends SocketServer {
compiler = newGlobal(command.settings, reporter)
}
val c = compiler
- val run = new c.Run
+ val run = new c.Run()
run compile command.files
} catch {
case ex @ FatalError(msg) =>
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 5b23ce2c45..fff92aac64 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -38,10 +38,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
with PhaseAssembly
{
// alternate constructors ------------------------------------------
+
def this(reporter: Reporter) =
this(new Settings(err => reporter.error(null,err)),
reporter)
-
def this(settings: Settings) =
this(settings, new ConsoleReporter(settings))
@@ -49,6 +49,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
// sub-components --------------------------------------------------
+ /** Print tree in detailed form */
object nodePrinters extends {
val global: Global.this.type = Global.this
} with NodePrinters {
@@ -56,6 +57,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
}
val nodeToString = nodePrinters.nodeToString
+ /** Generate ASTs */
object gen extends {
val global: Global.this.type = Global.this
} with TreeGen {
@@ -63,38 +65,47 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
typer.typed(mkAttributedCastUntyped(tree, pt))
}
+ /** Fold constants */
object constfold extends {
val global: Global.this.type = Global.this
} with ConstantFolder
+ /** Tree checker (used for testing and debugging) */
object checker extends {
val global: Global.this.type = Global.this
} with TreeCheckers
+ /** ICode generator */
object icodes extends {
val global: Global.this.type = Global.this
} with ICodes
+ /** ICode analysis for optimization */
object analysis extends {
val global: Global.this.type = Global.this
} with TypeFlowAnalysis
+ /** Copy propagation for optimization */
object copyPropagation extends {
val global: Global.this.type = Global.this
} with CopyPropagation
+ /** Icode verification */
object checkers extends {
val global: Global.this.type = Global.this
} with Checkers
+ /** Some statistics (normally disabled) */
object statistics extends {
val global: Global.this.type = Global.this
} with Statistics
+ /** Computing pairs of overriding/overridden symbols */
object overridingPairs extends {
val global: Global.this.type = Global.this
} with OverridingPairs
+ /** Representing ASTs as graphs */
object treeBrowsers extends {
val global: Global.this.type = Global.this
} with TreeBrowsers
@@ -104,22 +115,39 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
// val copy = new LazyTreeCopier()
+ /** A map of all doc comments, indexed by symbols.
+ * Only active in onlyPresentation mode
+ */
val comments =
if (onlyPresentation) new HashMap[Symbol,String]
else null
+
+ /** A map of argument names for methods
+ * !!! can be dropped once named method arguments are in !!!
+ */
val methodArgumentNames =
if (onlyPresentation) new HashMap[Symbol,List[List[Symbol]]]
else null
-// reporting -------------------------------------------------------
+ // ------------ Hooks for IDE ----------------------------------
+
+ /** Return a position correponding to tree startaing at `start`, with tip
+ * at `mid`, and ending at `end`. ^ batch mode errors point at tip.
+ */
+ def rangePos(source: SourceFile, start: Int, mid: Int, end: Int) = OffsetPosition(source, mid)
+
+ /** Poll for a high-priority task
+ */
+ def pollForHighPriorityJob() {}
+
+// ------------------ Reporting -------------------------------------
+
import nsc.util.NoPosition
def error(msg: String) = reporter.error(NoPosition, msg)
def warning(msg: String) = reporter.warning(NoPosition, msg)
def inform(msg: String) = Console.err.println(msg)
def inform[T](msg: String, value: T): T = { inform(msg+value); value }
- def rangePos(source: SourceFile, start: Int, mid: Int, end: Int) = OffsetPosition(source, mid)
-
//reporter.info(null, msg, true)
def informProgress(msg: String) =
@@ -155,7 +183,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
def abort(msg: String) = throw new Error(msg)
-// file interface -------------------------------------------------------
+// ------------ File interface -----------------------------------------
private val reader: SourceReader = {
def stdCharset: Charset = {
@@ -204,7 +232,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
set
}
-
if (settings.verbose.value) {
inform("[Classpath = " + classPath + "]")
if (forMSIL) inform("[AssemRefs = " + settings.assemrefs.value + "]")
@@ -235,7 +262,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
if (forMSIL) new loaders.NamespaceLoader(classPath.root)
else new loaders.PackageLoader(classPath.root /* getRoot() */)
-// Phases ------------------------------------------------------------}
+// ------------ Phases -------------------------------------------}
var globalPhase: Phase = NoPhase
@@ -575,61 +602,85 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
messages.mkString("\n")
}
+ // ----------- Runs ---------------------------------------
private var curRun: Run = null
- def currentRun: Run = curRun
private var curRunId = 0
- override def currentRunId = curRunId
- private var runCount = 0
+ /** The currently active run
+ */
+ def currentRun: Run = curRun
- class Run {
- curRunId += 1
- assert(curRunId > 0)
- //Console.println("starting run: " + id)
- var currentUnit: CompilationUnit = _
- curRun = this
- // Can not take the phaseDescriptors.head even though its the syntaxAnalyser, this will implicitly
- // call definitions.init which uses phase and needs it to be != NoPhase
- private val firstPhase = syntaxAnalyzer.newPhase(NoPhase)
- phase = firstPhase
- definitions.init // needs phase to be defined != NoPhase,
- // that's why it is placed here.
-
- /** Deprecation warnings occurred */
- var deprecationWarnings: Boolean = false
- var uncheckedWarnings: Boolean = false
+ /** The id of the currently active run
+ */
+ override def currentRunId = curRunId
- // The first phase in the compiler phase chain
- private var p: Phase = firstPhase
+ /** A Run is a single execution of the compiler on a sets of units
+ */
+ class Run {
- protected def stopPhase(name : String) = settings.stop.contains(name)
+ private val firstPhase = {
+ // ----------- Initialization code -------------------------
+ curRunId += 1
+ assert(curRunId > 0)
+ curRun = this
+ //Console.println("starting run: " + id)
+
+ // Can not take the phaseDescriptors.head even though its the syntaxAnalyser, this will implicitly
+ // call definitions.init which uses phase and needs it to be != NoPhase
+ val phase1 = syntaxAnalyzer.newPhase(NoPhase)
+ phase = phase1
+ definitions.init // needs phase to be defined != NoPhase,
+ // that's why it is placed here.
+
+ // The first phase in the compiler phase chain
+ var p: Phase = phase1
+
+ // Reset the cache in terminal, the chain could have been build before where nobody used it
+ // This happens in the interpreter
+ terminal.reset
+
+ // Each subcomponent is asked to deliver a newPhase that is chained together. If -Ystop:phasename is
+ // given at command-line, this will stop with that phasename
+ for (pd <- phaseDescriptors.tail.takeWhile(pd => !(stopPhase(pd.phaseName))))
+ if (!(settings.skip contains pd.phaseName)) p = pd.newPhase(p)
+
+ // Ensure there is a terminal phase at the end, Normally there will then be two terminal phases at the end
+ // if -Ystop:phasename was given, this makes sure that there is a terminal phase at the end
+ p = terminal.newPhase(p)
+
+ phase1
+ }
- // Reset the cache in terminal, the chain could have been build before where nobody used it
- // This happens in the interpreter
- terminal.reset
+ // --------------- Miscellania -------------------------------
- // Each subcomponent is asked to deliver a newPhase that is chained together. If -Ystop:phasename is
- // given at command-line, this will stop with that phasename
- for (pd <- phaseDescriptors.tail.takeWhile(pd => !(stopPhase(pd.phaseName))))
- if (!(settings.skip contains pd.phaseName)) p = pd.newPhase(p)
+ /** The currently compiled unit; set from GlobalPhase */
+ var currentUnit: CompilationUnit = _
- // Ensure there is a terminal phase at the end, Normally there will then be two terminal phases at the end
- // if -Ystop:phasename was given, this makes sure that there is a terminal phase at the end
- p = terminal.newPhase(p)
+ /** Flags indicating whether deprecation warnings occurred */
+ var deprecationWarnings: Boolean = false
+ var uncheckedWarnings: Boolean = false
def cancel { reporter.cancelled = true }
- // progress tracking
+ // ------------------ Progress tracking -------------------------
+
def progress(current: Int, total: Int) {}
private var phasec: Int = 0
private var unitc: Int = 0
+
+ /** take note that phase is completed
+ * (for progress reporting)
+ */
def advancePhase {
unitc = 0
phasec += 1
refreshProgress
}
+ /** take note that a phase on a unit is completed
+ * (for progress reporting)
+ */
def advanceUnit {
unitc += 1
refreshProgress
@@ -639,6 +690,8 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
progress((phasec * fileset.size) + unitc,
(phaseDescriptors.length-1) * fileset.size) // terminal phase not part of the progress display
+ // ----- finding phases --------------------------------------------
+
def phaseNamed(name: String): Phase = {
var p: Phase = firstPhase
while (p.next != p && p.name != name) p = p.next
@@ -656,14 +709,21 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val mixinPhase = phaseNamed("mixin")
val icodePhase = phaseNamed("icode")
+ /** A test whether compilation should stop at phase with given name */
+ protected def stopPhase(name : String) = settings.stop.contains(name)
+
+ // ----------- Units and top-level classes and objects --------
+
private var unitbuf = new ListBuffer[CompilationUnit]
private var fileset = new HashSet[AbstractFile]
+ /** add unit to be compiled in this run */
private def addUnit(unit: CompilationUnit) {
unitbuf += unit
fileset += unit.source.file
}
+ /* An iterator returning all the units being compiled in this run */
def units: Iterator[CompilationUnit] = unitbuf.elements
/** A map from compiled top-level symbols to their source files */
@@ -680,6 +740,9 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
else if (sym.isModuleClass) compiles(sym.sourceModule)
else false
+ // --------------- Compilation methods ----------------------------
+
+ /** Compile list of source files */
def compileSources(_sources: List[SourceFile]) {
val sources = dependencyAnalysis.filter(_sources.removeDuplicates) // bug #1268, scalac confused by duplicated filenames
if (reporter.hasErrors)
@@ -715,7 +778,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
warning("It is not possible to check the result of the "+globalPhase.name+" phase")
}
}
-
if (settings.statistics.value) statistics.print(phase)
advancePhase
}
@@ -745,29 +807,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
dependencyAnalysis.writeToFile();
}
- def compileLate(file: AbstractFile) {
- if (fileset eq null) {
- val msg = "No class file for " + file +
- " was found\n(This file cannot be loaded as a source file)"
- inform(msg)
- throw new FatalError(msg)
- }
- else if (!(fileset contains file)) {
- val unit = new CompilationUnit(getSourceFile(file))
- addUnit(unit)
- var localPhase = firstPhase.asInstanceOf[GlobalPhase]
- while (localPhase != null && (localPhase.id < globalPhase.id || localPhase.id <= namerPhase.id) && !reporter.hasErrors) {
- val oldSource = reporter.getSource
- reporter.setSource(unit.source)
- atPhase(localPhase)(localPhase.applyPhase(unit))
- val newLocalPhase = localPhase.next.asInstanceOf[GlobalPhase]
- localPhase = if (localPhase == newLocalPhase) null else newLocalPhase
- reporter.setSource(oldSource)
- }
- refreshProgress
- }
- }
-
+ /** Compile list of abstract files */
def compileFiles(files: List[AbstractFile]) {
try {
compileSources(files map getSourceFile)
@@ -776,6 +816,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
}
}
+ /** Compile list of files given by their names */
def compile(filenames: List[String]) {
try {
val scriptMain = settings.script.value
@@ -795,6 +836,41 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
}
}
+ /** Compile abstract file until `globalPhase`, but at least
+ * to phase "namer".
+ */
+ def compileLate(file: AbstractFile) {
+ if (fileset eq null) {
+ val msg = "No class file for " + file +
+ " was found\n(This file cannot be loaded as a source file)"
+ inform(msg)
+ throw new FatalError(msg)
+ }
+ else if (!(fileset contains file)) {
+ compileLate(new CompilationUnit(getSourceFile(file)))
+ }
+ }
+
+ /** Compile abstract file until `globalPhase`, but at least
+ * to phase "namer".
+ */
+ def compileLate(unit: CompilationUnit) {
+ addUnit(unit)
+ var localPhase = firstPhase.asInstanceOf[GlobalPhase]
+ while (localPhase != null && (localPhase.id < globalPhase.id || localPhase.id <= namerPhase.id) && !reporter.hasErrors) {
+ val oldSource = reporter.getSource
+ reporter.setSource(unit.source)
+ atPhase(localPhase)(localPhase.applyPhase(unit))
+ val newLocalPhase = localPhase.next.asInstanceOf[GlobalPhase]
+ localPhase = if (localPhase == newLocalPhase) null else newLocalPhase
+ reporter.setSource(oldSource)
+ }
+ refreshProgress
+ }
+
+ /** Reset package class to state at typer (not sure what this
+ * is needed for?)
+ */
private def resetPackageClass(pclazz: Symbol) {
atPhase(firstPhase) {
pclazz.setInfo(atPhase(typerPhase)(pclazz.info))
@@ -803,7 +879,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
}
} // class Run
-
def printAllUnits() {
print("[[syntax trees at end of " + phase + "]]")
atPhase(phase.next) {
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index bf48b2bbe6..0fbd115f4d 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -410,7 +410,7 @@ class Interpreter(val settings: Settings, out: PrintWriter)
*/
def interpret(line: String): IR.Result = {
// initialize the compiler
- if (prevRequests.isEmpty) new compiler.Run
+ if (prevRequests.isEmpty) new compiler.Run()
// parse
val trees = parse(indentCode(line)) match {
diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala
index bfc6681b5b..36e0b67457 100644
--- a/src/compiler/scala/tools/nsc/Main.scala
+++ b/src/compiler/scala/tools/nsc/Main.scala
@@ -36,7 +36,7 @@ object Main extends AnyRef with EvalLoop {
loop { line =>
val args = List.fromString(line, ' ')
val command = new CompilerCommand(args, new Settings(error), error, true)
- (new compiler.Run) compile command.files
+ new compiler.Run() compile command.files
}
}
@@ -69,7 +69,7 @@ object Main extends AnyRef with EvalLoop {
reporter.info(null, command.usageMsg, true)
reporter.info(null, compiler.pluginOptionsHelp, true)
} else {
- val run = new compiler.Run
+ val run = new compiler.Run()
run compile command.files
reporter.printSummary()
}
diff --git a/src/compiler/scala/tools/nsc/ScalaDoc.scala b/src/compiler/scala/tools/nsc/ScalaDoc.scala
index 092f02a259..564207c478 100644
--- a/src/compiler/scala/tools/nsc/ScalaDoc.scala
+++ b/src/compiler/scala/tools/nsc/ScalaDoc.scala
@@ -71,7 +71,7 @@ object ScalaDoc {
else if (command.settings.showPhases.value)
reporter.info(null, compiler.phaseDescriptions, true)
else {
- val run = new compiler.Run
+ val run = new compiler.Run()
run compile command.files
val generator = new DefaultDocDriver {
lazy val global: compiler.type = compiler
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 82dcd74fef..bd32213837 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -811,31 +811,29 @@ trait Scanners {
// ------------- character classification --------------------------------
- def isIdentifierStart(c: Char): Boolean = (
- ('A' <= c && c <= 'Z') ||
- ('a' <= c && c <= 'a') ||
- (c == '_') || (c == '$') ||
- Character.isUnicodeIdentifierStart(c)
- )
-
- def isIdentifierPart(c: Char) = (
- isIdentifierStart(c) ||
- ('0' <= c && c <= '9') ||
- Character.isUnicodeIdentifierPart(c)
- )
-
- def isSpecial(c: Char) = {
- val chtp = Character.getType(c)
- chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL
- }
+ def isIdentifierStart(c: Char): Boolean =
+ ('A' <= c && c <= 'Z') ||
+ ('a' <= c && c <= 'a') ||
+ (c == '_') || (c == '$') ||
+ Character.isUnicodeIdentifierStart(c)
+
+ def isIdentifierPart(c: Char) =
+ isIdentifierStart(c) ||
+ ('0' <= c && c <= '9') ||
+ Character.isUnicodeIdentifierPart(c)
+
+ def isSpecial(c: Char) = {
+ val chtp = Character.getType(c)
+ chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL
+ }
- def isOperatorPart(c : Char) : Boolean = (c: @switch) match {
- case '~' | '!' | '@' | '#' | '%' |
- '^' | '*' | '+' | '-' | '<' |
- '>' | '?' | ':' | '=' | '&' |
- '|' | '/' | '\\' => true
- case c => isSpecial(c)
- }
+ def isOperatorPart(c : Char) : Boolean = (c: @switch) match {
+ case '~' | '!' | '@' | '#' | '%' |
+ '^' | '*' | '+' | '-' | '<' |
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '/' | '\\' => true
+ case c => isSpecial(c)
+ }
// ------------- keyword configuration -----------------------------------
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index a205d3636b..fae9b76520 100755
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -18,6 +18,7 @@ self =>
/** Called from typechecker */
override def pollForHighPriorityJob() {
+ // don';t do this if polling notnenabled unless cancel
scheduler.nextWorkItem() match {
case Some(action) =>
pollingEnabled = false
@@ -98,10 +99,10 @@ self =>
currentTyperRun = new TyperRun
while (outOfDate) {
outOfDate = false
- remainingPriUnits = priorityUnits
for ((unit, id) <- unitsWithRunId.elements) {
if (id != currentRunId) unitsToCompile += unit
}
+ remainingPriUnits = priorityUnits
while (unitsToCompile.nonEmpty) {
if (change) {
change = false
@@ -123,19 +124,6 @@ self =>
case ex: FreshRunReq => outOfDate = true
}
- /** The compilation unit corresponding to a source file */
- def unitOf(s: SourceFile): CompilationUnit =
- unitsWithRunId.keys find (_.source == s) match {
- case Some(unit) => unit
- case None =>
- val unit = new CompilationUnit(s)
- unitsWithRunId(unit) = NotLoaded
- unit
- }
-
- /** The compilation unit corresponding to a position */
- def unitOf(pos: Position): CompilationUnit = unitOf(pos.source.get)
-
/** Make sure a set of compilation units is loaded and parsed */
def reload(units: Set[CompilationUnit]) = {
for (unit <- units) {
@@ -178,14 +166,27 @@ self =>
}
}
- /** Locate smallest tree that encloses position */
- def locateTree(pos: Position): Tree =
- locate(pos, unitOf(pos).body)
-
// ----------------- interface to IDE ------------------------------------
private val scheduler = new WorkScheduler
+ /** The compilation unit corresponding to a source file */
+ def unitOf(s: SourceFile): CompilationUnit =
+ unitsWithRunId.keys find (_.source == s) match {
+ case Some(unit) => unit
+ case None =>
+ val unit = new CompilationUnit(s)
+ unitsWithRunId(unit) = NotLoaded
+ unit
+ }
+
+ /** The compilation unit corresponding to a position */
+ def unitOf(pos: Position): CompilationUnit = unitOf(pos.source.get)
+
+ /** Locate smallest tree that encloses position */
+ def locateTree(pos: Position): Tree =
+ locate(pos, unitOf(pos).body)
+
/** Make sure a set of compilation units is loaded and parsed */
def askReload(units: Set[CompilationUnit]) =
scheduler.postWorkItem(() => reload(units))
@@ -194,7 +195,7 @@ self =>
def askTypeAt(pos: Position, result: SyncVar[Tree]) =
scheduler.postWorkItem(() => self.typedTreeAt(pos, result))
- /** Ask to do unit first on subsequent type checking passes */
+ /** Ask to do unit first on present and subsequent type checking passes */
def askToDoFirst(unit: CompilationUnit) = {
def moveToFront(unit: CompilationUnit, units: List[CompilationUnit]) = unit :: (units filter (unit !=))
scheduler.postWorkItem { () =>
@@ -203,7 +204,7 @@ self =>
}
}
- /** Cancel current high-priority job */
+ /** Cancel currently pending high-priority jobs */
def askCancel() =
scheduler.raise(new CancelActionReq)
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index f5e33a0ac9..3db4e372aa 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1646,6 +1646,8 @@ A type's typeSymbol should never be inspected directly.
override def kind = "MethodType"
}
+ // Lukas: check whether we can eliminate this in favor of implicit flags on parameters
+
class ImplicitMethodType(pts: List[Type], rt: Type) extends MethodType(pts, rt) {
override protected def paramPrefix = "(implicit "
}
@@ -2017,6 +2019,8 @@ A type's typeSymbol should never be inspected directly.
new RefinementOfClass
}
+
+
/** the canonical creator for a refined type with a given scope */
def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos : Position): Type = {
if (phase.erasedTypes)
@@ -3226,6 +3230,10 @@ A type's typeSymbol should never be inspected directly.
val restp1 = this(restp)
if (restp1 eq restp) tp
else PolyType(tparams, restp1)
+
+ // Lukas: we need to check (together) whether we should also include parameter types
+ // of PolyType and MethodType in adaptToNewRun
+
case ClassInfoType(parents, decls, clazz) =>
if (clazz.isPackageClass) tp
else {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 31bb361d68..a2e567282f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -35,6 +35,8 @@ trait Analyzer extends AnyRef
}
}
+ var typerTime = 0L
+
object typerFactory extends SubComponent {
val global: Analyzer.this.global.type = Analyzer.this.global
val phaseName = "typer"
@@ -42,6 +44,36 @@ trait Analyzer extends AnyRef
val runsRightAfter = Some("namer")
def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) {
resetTyper()
+ override def run {
+ val start = System.nanoTime()
+ currentRun.units foreach applyPhase
+ /*
+ typerTime += System.nanoTime() - start
+ def show(time: Long) = "%2.1f".format(time.toDouble / typerTime * 100)+" / "+time+"ns"
+ println("time spent typechecking: "+show(typerTime))
+ println("time spent in implicits: "+show(implicitTime))
+ println(" successful in scope: "+show(inscopeSucceed))
+ println(" failed in scope: "+show(inscopeFail))
+ println(" successful of type: "+show(oftypeSucceed))
+ println(" failed of type: "+show(oftypeFail))
+ println(" successful manifest: "+show(manifSucceed))
+ println(" failed manifest: "+show(manifFail))
+ println("implicit cache hitratio: "+"%2.1f".format(hits.toDouble / (hits + misses) * 100))
+ println("time spent in failed : "+show(failedSilent))
+ println(" failed op= : "+show(failedOpEqs))
+ println(" failed applu : "+show(failedApplies))
+ */
+ typerTime = 0L
+ implicitTime = 0L
+ inscopeSucceed = 0L
+ inscopeFail = 0L
+ oftypeSucceed = 0L
+ oftypeFail = 0L
+ manifSucceed = 0L
+ manifFail = 0L
+ hits = 0
+ misses = 0
+ }
def apply(unit: CompilationUnit) {
try {
unit.body = newTyper(rootContext(unit)).typed(unit.body)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 6ca93116d6..667827dfa4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -30,6 +30,16 @@ self: Analyzer =>
final val traceImplicits = false
+ var implicitTime = 0L
+ var inscopeSucceed = 0L
+ var inscopeFail = 0L
+ var oftypeSucceed = 0L
+ var oftypeFail = 0L
+ var manifSucceed = 0L
+ var manifFail = 0L
+ var hits = 0
+ var misses = 0
+
/** Search for an implicit value. See the comment on `result` at the end of class `ImplicitSearch`
* for more info how the search is conducted.
* @param tree The tree for which the implicit needs to be inserted.
@@ -52,6 +62,11 @@ self: Analyzer =>
search.result
}
+ final val sizeLimit = 100
+ val implicitsCache = new HashMap[Type, SearchResult]
+
+ def resetImplicits() { implicitsCache.clear() }
+
/** If type `pt` an instance of Manifest or OptManifest, or an abstract type lower-bounded
* by such an instance?
*/
@@ -633,16 +648,35 @@ self: Analyzer =>
* If that fails, and `pt` is an instance of Manifest, try to construct a manifest.
* If all fails return SearchFailure
*/
+ //val start = System.nanoTime()
var result = searchImplicit(context.implicitss, true)
+ //val timer1 = System.nanoTime()
+ //if (result == SearchFailure) inscopeFail += timer1 - start else inscopeSucceed += timer1 - start
if (result == SearchFailure) {
- result = searchImplicit(implicitsOfExpectedType, false)
+ implicitsCache get pt match {
+ case Some(r) =>
+ hits += 1
+ result = r
+ case None =>
+ misses += 1
+ result = searchImplicit(implicitsOfExpectedType, false)
+// println("new fact: search implicit of "+pt+" = "+result)
+// if (implicitsCache.size >= sizeLimit)
+// implicitsCache -= implicitsCache.values.next
+ implicitsCache(pt) = result
+ }
}
+ //val timer2 = System.nanoTime()
+ //if (result == SearchFailure) oftypeFail += timer2 - timer1 else oftypeSucceed += timer2 - timer1
if (result == SearchFailure) {
val resultTree = implicitManifest(pt)
if (resultTree != EmptyTree) result = new SearchResult(resultTree, EmptyTreeTypeSubstituter)
}
+ //val timer3 = System.nanoTime()
+ //if (result == SearchFailure) manifFail += timer3 - timer2 else manifSucceed += timer3 - timer2
if (result == SearchFailure && settings.debug.value)
println("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+parts(pt)+implicitsOfExpectedType)
+ //implicitTime += System.nanoTime() - start
if (util.Statistics.enabled) impltime += (currentTime - startTime)
result
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index a272d7aa28..170e445458 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -36,6 +36,10 @@ trait Typers { self: Analyzer =>
var implcnt = 0
var impltime = 0l
+ var failedApplies = 0L
+ var failedOpEqs = 0L
+ var failedSilent = 0L
+
private val transformed = new HashMap[Tree, Tree]
private val superDefs = new HashMap[Symbol, ListBuffer[Tree]]
@@ -43,6 +47,7 @@ trait Typers { self: Analyzer =>
def resetTyper() {
resetContexts
resetNamer()
+ resetImplicits()
transformed.clear
superDefs.clear
}
@@ -660,7 +665,9 @@ trait Typers { self: Analyzer =>
else qual.tpe.nonLocalMember(name)(from)
}
- def silent(op: Typer => Tree): AnyRef /* in fact, TypeError or Tree */ = try {
+ def silent(op: Typer => Tree): AnyRef /* in fact, TypeError or Tree */ = {
+ val start = System.nanoTime()
+ try {
if (context.reportGeneralErrors) {
val context1 = context.makeSilent(context.reportAmbiguousErrors)
context1.undetparams = context.undetparams
@@ -675,8 +682,10 @@ trait Typers { self: Analyzer =>
}
} catch {
case ex: CyclicReference => throw ex
- case ex: TypeError => ex
- }
+ case ex: TypeError =>
+ failedSilent += System.nanoTime() - start
+ ex
+ }}
/** Perform the following adaptations of expression, pattern or type `tree' wrt to
* given mode `mode' and given prototype `pt':
@@ -1815,6 +1824,16 @@ trait Typers { self: Analyzer =>
fun.tpe match {
case OverloadedType(pre, alts) =>
val undetparams = context.extractUndetparams()
+
+ /* Lukas:
+
+ var m: Map[Tree, Name] = Map()
+ val args1 = List.mapConserve(args) {
+ case Assign(name, rhs) => m += (rhs -> name)
+ case arg => arg
+ }
+ */
+
val args1 = typedArgs(args, argMode(fun, mode))
context.undetparams = undetparams
inferMethodAlternative(fun, undetparams, args1 map (_.tpe.deconst), pt)
@@ -2667,11 +2686,13 @@ trait Typers { self: Analyzer =>
* @param args ...
* @return ...
*/
- def tryTypedApply(fun: Tree, args: List[Tree]): Tree =
+ def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
+ val start = System.nanoTime()
silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
case t: Tree =>
t
case ex: TypeError =>
+ failedApplies += System.nanoTime() - start
def errorInResult(tree: Tree): Boolean = tree.pos == ex.pos || {
tree match {
case Block(_, r) => errorInResult(r)
@@ -2701,6 +2722,7 @@ trait Typers { self: Analyzer =>
reportTypeError(tree.pos, ex)
setError(tree)
}
+ }
def typedApply(fun: Tree, args: List[Tree]) = {
val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable
@@ -2709,6 +2731,7 @@ trait Typers { self: Analyzer =>
typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
} else {
val funpt = if ((mode & PATTERNmode) != 0) pt else WildcardType
+ val start = System.nanoTime()
silent(_.typed(fun, funMode(mode), funpt)) match {
case fun1: Tree =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
@@ -2736,6 +2759,7 @@ trait Typers { self: Analyzer =>
else res
*/
case ex: TypeError =>
+ failedOpEqs += System.nanoTime() - start
fun match {
case Select(qual, name)
if (mode & PATTERNmode) == 0 && nme.isOpAssignmentName(name.decode) =>
@@ -3425,6 +3449,7 @@ trait Typers { self: Analyzer =>
val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt)
if (printTypings) println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams); //DEBUG
// if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe)
+ if (phase.id == currentRun.typerPhase.id) pollForHighPriorityJob()
result
} catch {
case ex: TypeError =>
diff --git a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
new file mode 100644
index 0000000000..7bcd3b7a8e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
@@ -0,0 +1,43 @@
+package scala.tools.nsc.util
+
+import scala.collection.mutable.Queue
+
+class WorkScheduler {
+
+ type Action = () => Unit
+
+ private var todo = new Queue[Action]
+
+ /** Called from server */
+ def waitForMoreWork() = synchronized {
+ do { wait() } while (todo.isEmpty)
+ }
+
+ /** called from Server */
+ def moreWork(): Boolean = synchronized {
+ todo.nonEmpty
+ }
+
+ /** Called from server */
+ def nextWorkItem(): Option[Action] = synchronized {
+ if (!todo.isEmpty) Some(todo.dequeue()) else None
+ }
+
+ /** Called from client */
+ def postWorkItem(action: Action) {
+ todo enqueue action
+ notify()
+ }
+
+ /** Called from client */
+ def cancel() = synchronized {
+ todo.clear()
+ }
+
+ /** Called from client */
+ def raise(exc: Exception) = synchronized {
+ todo.clear()
+ todo enqueue (() => throw exc)
+ }
+}
+