diff options
author | Paul Phillips <paulp@improving.org> | 2012-02-25 20:43:37 -0800 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-02-25 21:41:19 -0800 |
commit | da12146b8f3a5215e9685cd978d898131f67f1eb (patch) | |
tree | d00f643dcfb3b08fbe2842f46a4ed54b520cf236 /src/compiler/scala/tools/nsc/Global.scala | |
parent | 7970e0d949bd8b3a5e8069e377d007351327ce80 (diff) | |
download | scala-da12146b8f3a5215e9685cd978d898131f67f1eb.tar.gz scala-da12146b8f3a5215e9685cd978d898131f67f1eb.tar.bz2 scala-da12146b8f3a5215e9685cd978d898131f67f1eb.zip |
Toward a higher level abstraction than atPhase.
I guess these are self-explanatory.
@inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op)
@inline final def afterExplicitOuter[T](op: => T): T = afterPhase(currentRun.explicitouterPhase)(op)
...
@inline final def beforeTyper[T](op: => T): T = beforePhase(currentRun.typerPhase)(op)
@inline final def beforeUncurry[T](op: => T): T = beforePhase(currentRun.uncurryPhase)(op)
This commit is basically pure substitution. To get anywhere interesting
with all the phase-related bugs we have to determine why we use atPhase
and capture that reasoning directly. With the exception of erasure, most
phases don't have much meaning outside of the compiler. How can anyone
know why a block of code which says atPhase(explicitouter.prev) { ... }
needs to run there? Too much cargo cult, and it should stop. Every usage
of atPhase should be commented as to intention.
It's easy to find bugs like
atPhase(uncurryPhase.prev)
which was probably intended to run before uncurry, but actually runs
before whatever happens to be before uncurry - which, luckily enough, is
non-deterministic because the continuations plugin inserts phases
between refchecks and uncurry.
% scalac -Xplugin-disable:continuations -Xshow-phases
refchecks 7 reference/override checking, translate nested objects
uncurry 8 uncurry, translate function values to anonymous classes
% scalac -Xshow-phases
selectivecps 9
uncurry 10 uncurry, translate function values to anonymous classes
Expressions like atPhase(somePhase.prev) are never right or are at best
highly suboptimal, because most of the time you have no guarantees about
what phase precedes you. Anyway, I think most or all atPhases expressed
that way only wanted to run before somePhase, and because one can never
be too sure without searching for documentation whether "atPhase" means
before or after, people err on the side of caution and overshoot by a
phase. Unfortunately, this usually works. (I prefer bugs which never work.)
Diffstat (limited to 'src/compiler/scala/tools/nsc/Global.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index ca5604c828..1a6507936c 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -224,7 +224,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb ) def logAfterEveryPhase[T](msg: String)(op: => T) { - log("Running operation '%s' after every phase.\n" + describeAfterEveryPhase(op)) + log("Running operation '%s' after every phase.\n".format(msg) + describeAfterEveryPhase(op)) } // Over 200 closure objects are eliminated by inlining this. @inline final def log(msg: => AnyRef): Unit = @@ -866,9 +866,27 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile + // TODO - trim these to the absolute minimum. + @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op) + @inline final def afterExplicitOuter[T](op: => T): T = afterPhase(currentRun.explicitouterPhase)(op) + @inline final def afterFlatten[T](op: => T): T = afterPhase(currentRun.flattenPhase)(op) + @inline final def afterIcode[T](op: => T): T = afterPhase(currentRun.icodePhase)(op) + @inline final def afterMixin[T](op: => T): T = afterPhase(currentRun.mixinPhase)(op) + @inline final def afterPickler[T](op: => T): T = afterPhase(currentRun.picklerPhase)(op) + @inline final def afterRefchecks[T](op: => T): T = afterPhase(currentRun.refchecksPhase)(op) + @inline final def afterSpecialize[T](op: => T): T = afterPhase(currentRun.specializePhase)(op) @inline final def afterTyper[T](op: => T): T = afterPhase(currentRun.typerPhase)(op) + @inline final def afterUncurry[T](op: => T): T = afterPhase(currentRun.uncurryPhase)(op) @inline final def beforeErasure[T](op: => T): T = beforePhase(currentRun.erasurePhase)(op) - @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op) + @inline final def beforeExplicitOuter[T](op: => T): T = beforePhase(currentRun.explicitouterPhase)(op) + @inline final def beforeFlatten[T](op: => T): T = beforePhase(currentRun.flattenPhase)(op) + @inline final def beforeIcode[T](op: => T): T = beforePhase(currentRun.icodePhase)(op) + @inline final def beforeMixin[T](op: => T): T = beforePhase(currentRun.mixinPhase)(op) + @inline final def beforePickler[T](op: => T): T = beforePhase(currentRun.picklerPhase)(op) + @inline final def beforeRefchecks[T](op: => T): T = beforePhase(currentRun.refchecksPhase)(op) + @inline final def beforeSpecialize[T](op: => T): T = beforePhase(currentRun.specializePhase)(op) + @inline final def beforeTyper[T](op: => T): T = beforePhase(currentRun.typerPhase)(op) + @inline final def beforeUncurry[T](op: => T): T = beforePhase(currentRun.uncurryPhase)(op) /** Don't want to introduce new errors trying to report errors, * so swallow exceptions. |