summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala28
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala246
-rw-r--r--src/compiler/scala/tools/nsc/PhaseAssembly.scala92
-rw-r--r--src/compiler/scala/tools/nsc/SubComponent.scala21
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala117
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala52
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala2
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugin.scala29
-rw-r--r--src/compiler/scala/tools/nsc/plugins/PluginComponent.scala6
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugins.scala25
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala29
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala13
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala18
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala81
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala7
34 files changed, 415 insertions, 480 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index f1f5130fb8..bab0768ca9 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -27,7 +27,7 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
|-- Notes on option parsing --
|Boolean settings are always false unless set.
|Where multiple values are accepted, they should be comma-separated.
- | example: -Xplugin:plugin1,plugin2
+ | example: -Xplugin:option1,option2
|<phases> means one or a comma-separated list of:
| (partial) phase names, phase ids, phase id ranges, or the string "all".
| example: -Xprint:all prints all phases.
@@ -80,23 +80,23 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
def xusageMsg = createUsageMsg("Possible advanced", shouldExplain = true, _.isAdvanced)
def yusageMsg = createUsageMsg("Possible private", shouldExplain = true, _.isPrivate)
- // If any of these settings is set, the compiler shouldn't start;
- // an informative message of some sort should be printed instead.
- def shouldStopWithInfo = {
- import settings.{ Setting => _, _ }
- Set[BooleanSetting](help, Xhelp, Yhelp, showPlugins, showPhases) exists (_.value)
- }
+ /** For info settings, compiler should just print a message and quit. */
+ def shouldStopWithInfo = settings.isInfo
def getInfoMessage(global: Global): String = {
import settings._
- if (help.value) usageMsg + global.pluginOptionsHelp
- else if (Xhelp.value) xusageMsg
- else if (Yhelp.value) yusageMsg
- else if (showPlugins.value) global.pluginDescriptions
- else if (showPhases.value) global.phaseDescriptions + (
- if (debug.value) "\n" + global.phaseFlagDescriptions else ""
+ if (help) usageMsg + global.pluginOptionsHelp
+ else if (Xhelp) xusageMsg
+ else if (Yhelp) yusageMsg
+ else if (showPlugins) global.pluginDescriptions
+ else if (showPhases) global.phaseDescriptions + (
+ if (debug) "\n" + global.phaseFlagDescriptions else ""
)
- else ""
+ else if (genPhaseGraph.isSetByUser) {
+ val components = global.phaseNames // global.phaseDescriptors // one initializes
+ s"Phase graph of ${components.size} components output to ${genPhaseGraph.value}*.dot."
+ }
+ else ""
}
/**
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 8b9ef2178b..f3a2d49697 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -47,7 +47,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// the mirror --------------------------------------------------
override def isCompilerUniverse = true
- override val useOffsetPositions = !currentSettings.Yrangepos.value
+ override val useOffsetPositions = !currentSettings.Yrangepos
class GlobalMirror extends Roots(NoSymbol) {
val universe: self.type = self
@@ -431,9 +431,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// phaseName = "parser"
lazy val syntaxAnalyzer = new {
val global: Global.this.type = Global.this
+ } with SyntaxAnalyzer {
val runsAfter = List[String]()
val runsRightAfter = None
- } with SyntaxAnalyzer
+ override val initial = true
+ }
import syntaxAnalyzer.{ UnitScanner, UnitParser }
@@ -453,9 +455,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
object patmat extends {
val global: Global.this.type = Global.this
val runsAfter = List("typer")
- // patmat doesn't need to be right after typer, as long as we run before supperaccesors
- // (sbt does need to run right after typer, so don't conflict)
val runsRightAfter = None
+ // patmat doesn't need to be right after typer, as long as we run before superaccessors
+ // (sbt does need to run right after typer, so don't conflict)
} with PatternMatching
// phaseName = "superaccessors"
@@ -629,18 +631,17 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// phaseName = "terminal"
object terminal extends {
val global: Global.this.type = Global.this
+ } with SubComponent {
val phaseName = "terminal"
val runsAfter = List("jvm")
val runsRightAfter = None
- } with SubComponent {
- private var cache: Option[GlobalPhase] = None
- def reset(): Unit = cache = None
+ override val terminal = true
- def newPhase(prev: Phase): GlobalPhase =
- cache getOrElse returning(new TerminalPhase(prev))(x => cache = Some(x))
-
- class TerminalPhase(prev: Phase) extends GlobalPhase(prev) {
- def name = "terminal"
+ def newPhase(prev: Phase): GlobalPhase = {
+ new TerminalPhase(prev)
+ }
+ private class TerminalPhase(prev: Phase) extends GlobalPhase(prev) {
+ def name = phaseName
def apply(unit: CompilationUnit) {}
}
}
@@ -668,7 +669,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Add the internal compiler phases to the phases set.
* This implementation creates a description map at the same time.
*/
- protected def computeInternalPhases() {
+ protected def computeInternalPhases(): Unit = {
// Note: this fits -Xshow-phases into 80 column width, which it is
// desirable to preserve.
val phs = List(
@@ -698,7 +699,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
closureElimination -> "optimization: eliminate uncalled closures",
constantOptimization -> "optimization: optimize null and other constants",
deadCode -> "optimization: eliminate dead code",
- terminal -> "The last phase in the compiler chain"
+ terminal -> "the last phase during a compilation run"
)
phs foreach (addToPhasesSet _).tupled
@@ -716,13 +717,21 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// sequences the phase assembly
protected def computePhaseDescriptors: List[SubComponent] = {
- computeInternalPhases() // Global.scala
- computePlatformPhases() // backend/Platform.scala
- computePluginPhases() // plugins/Plugins.scala
- buildCompilerFromPhasesSet() // PhaseAssembly.scala
+ /** Allow phases to opt out of the phase assembly. */
+ def cullPhases(phases: List[SubComponent]) = {
+ val enabled = if (settings.debug && settings.isInfo) phases else phases filter (_.enabled)
+ def isEnabled(q: String) = enabled exists (_.phaseName == q)
+ val (satisfied, unhappy) = enabled partition (_.requires forall isEnabled)
+ unhappy foreach (u => globalError(s"Phase '${u.phaseName}' requires: ${u.requires filterNot isEnabled}"))
+ satisfied // they're happy now, but they may need an unhappy phase that was booted
+ }
+ computeInternalPhases() // Global.scala
+ computePlatformPhases() // backend/Platform.scala
+ computePluginPhases() // plugins/Plugins.scala
+ cullPhases(computePhaseAssembly()) // PhaseAssembly.scala
}
- /* The phase descriptor list */
+ /* The phase descriptor list. Components that are phase factories. */
lazy val phaseDescriptors: List[SubComponent] = computePhaseDescriptors
/* The set of phase objects that is the basis for the compiler phase chain */
@@ -740,22 +749,50 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
phaseDescriptors map (_.phaseName)
}
- /** A description of the phases that will run */
- def phaseDescriptions: String = {
+ /** A description of the phases that will run in this configuration, or all if -Ydebug. */
+ def phaseDescriptions: String = phaseHelp("description", elliptically = true, phasesDescMap)
+
+ /** Summary of the per-phase values of nextFlags and newFlags, shown under -Xshow-phases -Ydebug. */
+ def phaseFlagDescriptions: String = {
+ def fmt(ph: SubComponent) = {
+ def fstr1 = if (ph.phaseNewFlags == 0L) "" else "[START] " + Flags.flagsToString(ph.phaseNewFlags)
+ def fstr2 = if (ph.phaseNextFlags == 0L) "" else "[END] " + Flags.flagsToString(ph.phaseNextFlags)
+ if (ph.initial) Flags.flagsToString(Flags.InitialFlags)
+ else if (ph.phaseNewFlags != 0L && ph.phaseNextFlags != 0L) fstr1 + " " + fstr2
+ else fstr1 + fstr2
+ }
+ phaseHelp("new flags", elliptically = false, fmt)
+ }
+
+ /** Emit a verbose phase table.
+ * The table includes the phase id in the current assembly,
+ * or "oo" to indicate a skipped phase, or "xx" to indicate
+ * a disabled phase.
+ *
+ * @param title descriptive header
+ * @param elliptically whether to truncate the description with an ellipsis (...)
+ * @param describe how to describe a component
+ */
+ def phaseHelp(title: String, elliptically: Boolean, describe: SubComponent => String) = {
val Limit = 16 // phase names should not be absurdly long
val MaxCol = 80 // because some of us edit on green screens
- val maxName = (0 /: phaseNames)(_ max _.length)
+ val maxName = phaseNames map (_.length) max
val width = maxName min Limit
val maxDesc = MaxCol - (width + 6) // descriptions not novels
- val fmt = if (settings.verbose) s"%${maxName}s %2s %s%n"
+ val fmt = if (settings.verbose || !elliptically) s"%${maxName}s %2s %s%n"
else s"%${width}.${width}s %2s %.${maxDesc}s%n"
- val line1 = fmt.format("phase name", "id", "description")
- val line2 = fmt.format("----------", "--", "-----------")
+ val line1 = fmt.format("phase name", "id", title)
+ val line2 = fmt.format("----------", "--", "-" * title.length)
// built-in string precision merely truncates
import java.util.{ Formattable, FormattableFlags, Formatter }
- def fmtable(s: String) = new Formattable {
+ def dotfmt(s: String) = new Formattable {
+ def elliptically(s: String, max: Int) = (
+ if (max < 0 || s.length <= max) s
+ else if (max < 4) s.take(max)
+ else s.take(max - 3) + "..."
+ )
override def formatTo(formatter: Formatter, flags: Int, width: Int, precision: Int) {
val p = elliptically(s, precision)
val w = if (width > 0 && p.length < width) {
@@ -771,36 +808,19 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
formatter.out.append(w)
}
}
- def elliptically(s: String, max: Int) =
- if (max < 0 || s.length <= max) s
- else if (max < 4) s.take(max)
- else s.take(max - 3) + "..."
- val descs = phaseDescriptors.zipWithIndex map {
- case (ph, idx) => fmt.format(fmtable(ph.phaseName), idx + 1, fmtable(phasesDescMap(ph)))
- }
- line1 :: line2 :: descs mkString
- }
- /** Summary of the per-phase values of nextFlags and newFlags, shown
- * with -Xshow-phases if -Ydebug also given.
- */
- def phaseFlagDescriptions: String = {
- val width = phaseNames map (_.length) max
- val fmt = "%" + width + "s %2s %s\n"
-
- val line1 = fmt.format("phase name", "id", "new flags")
- val line2 = fmt.format("----------", "--", "---------")
- val descs = phaseDescriptors.zipWithIndex map {
- case (ph, idx) =>
- def fstr1 = if (ph.phaseNewFlags == 0L) "" else "[START] " + Flags.flagsToString(ph.phaseNewFlags)
- def fstr2 = if (ph.phaseNextFlags == 0L) "" else "[END] " + Flags.flagsToString(ph.phaseNextFlags)
- val fstr = (
- if (ph.ownPhase.id == 1) Flags.flagsToString(Flags.InitialFlags)
- else if (ph.phaseNewFlags != 0L && ph.phaseNextFlags != 0L) fstr1 + " " + fstr2
- else fstr1 + fstr2
- )
- fmt.format(ph.phaseName, idx + 1, fstr)
+
+ // phase id in run, or suitable icon
+ def idOf(p: SubComponent) = (
+ if (settings.skip contains p.phaseName) "oo" // (currentRun skipPhase p.phaseName)
+ else if (!p.enabled) "xx"
+ else p.ownPhase.id.toString
+ )
+ def mkText(p: SubComponent) = {
+ val (name, text) = if (elliptically) (dotfmt(p.phaseName), dotfmt(describe(p)))
+ else (p.phaseName, describe(p))
+ fmt.format(name, idOf(p), text)
}
- line1 :: line2 :: descs mkString
+ line1 :: line2 :: (phaseDescriptors map mkText) mkString
}
/** Returns List of (phase, value) pairs, including only those
@@ -1157,7 +1177,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def newUnitParser(code: String, filename: String = "<console>"): UnitParser =
newUnitParser(newCompilationUnit(code, filename))
- /** A Run is a single execution of the compiler on a sets of units
+ /** A Run is a single execution of the compiler on a set of units.
*/
class Run extends RunContextApi {
/** Have been running into too many init order issues with Run
@@ -1196,64 +1216,100 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** A map from compiled top-level symbols to their picklers */
val symData = new mutable.HashMap[Symbol, PickleBuffer]
- private var phasec: Int = 0 // phases completed
- private var unitc: Int = 0 // units completed this phase
+ private var phasec: Int = 0 // phases completed
+ private var unitc: Int = 0 // units completed this phase
private var _unitbufSize = 0
def size = _unitbufSize
override def toString = "scalac Run for:\n " + compiledFiles.toList.sorted.mkString("\n ")
// Calculate where to stop based on settings -Ystop-before or -Ystop-after.
- // Slightly complicated logic due to wanting -Ystop-before:parser to fail rather
- // than mysteriously running to completion.
+ // The result is the phase to stop at BEFORE running it.
private lazy val stopPhaseSetting = {
- val result = phaseDescriptors sliding 2 collectFirst {
- case xs if xs exists (settings.stopBefore contains _.phaseName) => if (settings.stopBefore contains xs.head.phaseName) xs.head else xs.last
- case xs if settings.stopAfter contains xs.head.phaseName => xs.last
+ def isBefore(pd: SubComponent) = settings.stopBefore contains pd.phaseName
+ phaseDescriptors sliding 2 collectFirst {
+ case xs if xs exists isBefore
+ => (xs find isBefore).get
+ case xs if settings.stopAfter contains xs.head.phaseName
+ => xs.last
}
- if (result exists (_.phaseName == "parser"))
- globalError("Cannot stop before parser phase.")
-
- result
}
- // The phase to stop BEFORE running.
+ /** Should we stop right before entering the given phase? */
protected def stopPhase(name: String) = stopPhaseSetting exists (_.phaseName == name)
+ /** Should we skip the given phase? */
protected def skipPhase(name: String) = settings.skip contains name
- /** As definitions.init requires phase != NoPhase, and calling phaseDescriptors.head
- * will force init, there is some jockeying herein regarding init order: instead of
- * taking the head descriptor we create a parser phase directly.
- */
private val firstPhase = {
- /** Initialization. */
+ // Initialization. definitions.init requires phase != NoPhase
+ import scala.reflect.internal.SomePhase
curRunId += 1
curRun = this
-
- /* Set phase to a newly created syntaxAnalyzer and call definitions.init. */
- val parserPhase: Phase = syntaxAnalyzer.newPhase(NoPhase)
- phase = parserPhase
+ phase = SomePhase
+ phaseWithId(phase.id) = phase
definitions.init()
- // Flush the cache in the terminal phase: the chain could have been built
- // before without being used. (This happens in the interpreter.)
- terminal.reset()
-
- // Each subcomponent supplies a phase, which are chained together.
- // If -Ystop:phase is given, neither that phase nor any beyond it is added.
- // If -Yskip:phase is given, that phase will be skipped.
- val phaseLinks = {
- val phs = (
- phaseDescriptors.tail
- takeWhile (pd => !stopPhase(pd.phaseName))
- filterNot (pd => skipPhase(pd.phaseName))
- )
+ // the components to use, omitting those named by -Yskip and stopping at the -Ystop phase
+ val components = {
+ // stop on a dime, but this test fails if pd is after the stop phase
+ def unstoppable(pd: SubComponent) = {
+ val stoppable = stopPhase(pd.phaseName)
+ if (stoppable && pd.initial) {
+ globalError(s"Cannot stop before initial phase '${pd.phaseName}'.")
+ true
+ } else
+ !stoppable
+ }
+ // skip a component for -Yskip or if not enabled
+ def skippable(pd: SubComponent) = {
+ val skippable = skipPhase(pd.phaseName)
+ if (skippable && (pd.initial || pd.terminal)) {
+ globalError(s"Cannot skip an initial or terminal phase '${pd.phaseName}'.")
+ false
+ } else
+ skippable || !pd.enabled
+ }
+ val phs = phaseDescriptors takeWhile unstoppable filterNot skippable
// Ensure there is a terminal phase at the end, since -Ystop may have limited the phases.
- if (phs.isEmpty || (phs.last ne terminal)) phs :+ terminal
- else phs
+ if (phs.isEmpty || !phs.last.terminal) {
+ val t = if (phaseDescriptors.last.terminal) phaseDescriptors.last else terminal
+ phs :+ t
+ } else phs
}
- // Link them together.
- phaseLinks.foldLeft(parserPhase)((chain, ph) => ph newPhase chain)
- parserPhase
+ // Create phases and link them together. We supply the previous, and the ctor sets prev.next.
+ val last = components.foldLeft(NoPhase: Phase)((prev, c) => c newPhase prev)
+ // rewind (Iterator.iterate(last)(_.prev) dropWhile (_.prev ne NoPhase)).next
+ val first = { var p = last ; while (p.prev ne NoPhase) p = p.prev ; p }
+ val ss = settings
+
+ // As a final courtesy, see if the settings make any sense at all.
+ // If a setting selects no phase, it's a mistake. If a name prefix
+ // doesn't select a unique phase, that might be surprising too.
+ def checkPhaseSettings(including: Boolean, specs: Seq[String]*) = {
+ def isRange(s: String) = s.forall(c => c.isDigit || c == '-')
+ def isSpecial(s: String) = (s == "all" || isRange(s))
+ val setting = new ss.PhasesSetting("fake","fake")
+ for (p <- specs.flatten.to[Set]) {
+ setting.value = List(p)
+ val count = (
+ if (including) first.iterator count (setting containsPhase _)
+ else phaseDescriptors count (setting contains _.phaseName)
+ )
+ if (count == 0) warning(s"'$p' specifies no phase")
+ if (count > 1 && !isSpecial(p)) warning(s"'$p' selects $count phases")
+ if (!including && isSpecial(p)) globalError(s"-Yskip and -Ystop values must name phases: '$p'")
+ setting.clear()
+ }
+ }
+ // phases that are excluded; for historical reasons, these settings only select by phase name
+ val exclusions = List(ss.stopBefore, ss.stopAfter, ss.skip)
+ val inclusions = ss.visibleSettings collect {
+ case s: ss.PhasesSetting if !(exclusions contains s) => s.value
+ }
+ checkPhaseSettings(including = true, inclusions.toSeq: _*)
+ checkPhaseSettings(including = false, exclusions map (_.value): _*)
+
+ phase = first //parserPhase
+ first
}
/** Reset all classes contained in current project, as determined by
diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala
index ae71eb7255..996f6efe55 100644
--- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala
+++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala
@@ -6,15 +6,12 @@
package scala.tools.nsc
-import java.io.{ BufferedWriter, FileWriter }
import scala.collection.mutable
import scala.language.postfixOps
-/**
- * PhaseAssembly
- * Trait made to separate the constraint solving of the phase order from
- * the rest of the compiler. See SIP 00002
- *
+/** Converts an unordered morass of components into an order that
+ * satisfies their mutual constraints.
+ * @see SIP 00002. You have read SIP 00002?
*/
trait PhaseAssembly {
self: Global =>
@@ -23,18 +20,16 @@ trait PhaseAssembly {
* Aux datastructure for solving the constraint system
* The depency graph container with helper methods for node and edge creation
*/
- class DependencyGraph {
+ private class DependencyGraph {
- /**
- * Simple edge with to and from refs
- */
- class Edge(var frm: Node, var to: Node, var hard: Boolean)
+ /** Simple edge with to and from refs */
+ case class Edge(var frm: Node, var to: Node, var hard: Boolean)
/**
* Simple node with name and object ref for the phase object,
* also sets of in and out going dependencies
*/
- class Node(name: String) {
+ case class Node(name: String) {
val phasename = name
var phaseobj: Option[List[SubComponent]] = None
val after = new mutable.HashSet[Edge]()
@@ -51,8 +46,8 @@ trait PhaseAssembly {
val nodes = new mutable.HashMap[String,Node]()
val edges = new mutable.HashSet[Edge]()
- /* Given a phase object, get the node for this phase object. If the
- * node object does not exist, then create it.
+ /** Given a phase object, get the node for this phase object. If the
+ * node object does not exist, then create it.
*/
def getNodeByPhase(phs: SubComponent): Node = {
val node: Node = getNodeByPhase(phs.phaseName)
@@ -105,9 +100,8 @@ trait PhaseAssembly {
*/
def collapseHardLinksAndLevels(node: Node, lvl: Int) {
if (node.visited) {
- throw new FatalError(
- "Cycle in compiler phase dependencies detected, phase " +
- node.phasename + " reacted twice!")
+ dump("phase-cycle")
+ throw new FatalError(s"Cycle in phase dependencies detected at ${node.phasename}, created phase-cycle.dot")
}
if (node.level < lvl) node.level = lvl
@@ -140,7 +134,8 @@ trait PhaseAssembly {
var hardlinks = edges.filter(_.hard)
for (hl <- hardlinks) {
if (hl.frm.after.size > 1) {
- throw new FatalError("phase " + hl.frm.phasename + " want to run right after " + hl.to.phasename + ", but some phase has declared to run before " + hl.frm.phasename + ". Re-run with -Xgenerate-phase-graph <filename> to better see the problem.")
+ dump("phase-order")
+ throw new FatalError(s"Phase ${hl.frm.phasename} can't follow ${hl.to.phasename}, created phase-order.dot")
}
}
@@ -153,15 +148,9 @@ trait PhaseAssembly {
if (sanity.length == 0) {
throw new FatalError("There is no runs right after dependency, where there should be one! This is not supposed to happen!")
} else if (sanity.length > 1) {
- var msg = "Multiple phases want to run right after the phase " + sanity.head.to.phasename + "\n"
- msg += "Phases: "
- sanity = sanity sortBy (_.frm.phasename)
- for (edge <- sanity) {
- msg += edge.frm.phasename + ", "
- }
- msg += "\nRe-run with -Xgenerate-phase-graph <filename> to better see the problem."
- throw new FatalError(msg)
-
+ dump("phase-order")
+ val following = (sanity map (_.frm.phasename)).sorted mkString ","
+ throw new FatalError(s"Multiple phases want to run right after ${sanity.head.to.phasename}; followers: $following; created phase-order.dot")
} else {
val promote = hl.to.before.filter(e => (!e.hard))
@@ -199,39 +188,38 @@ trait PhaseAssembly {
}
}
}
+
+ def dump(title: String = "phase-assembly") = graphToDotFile(this, s"$title.dot")
}
- /* Method called from computePhaseDescriptors in class Global
- */
- def buildCompilerFromPhasesSet(): List[SubComponent] = {
+
+ /** Called by Global#computePhaseDescriptors to compute phase order. */
+ def computePhaseAssembly(): List[SubComponent] = {
// Add all phases in the set to the graph
val graph = phasesSetToDepGraph(phasesSet)
+ val dot = if (settings.genPhaseGraph.isSetByUser) Some(settings.genPhaseGraph.value) else None
+
// Output the phase dependency graph at this stage
- if (settings.genPhaseGraph.value != "")
- graphToDotFile(graph, settings.genPhaseGraph.value + "1.dot")
+ def dump(stage: Int) = dot foreach (n => graphToDotFile(graph, s"$n-$stage.dot"))
+
+ dump(1)
// Remove nodes without phaseobj
graph.removeDanglingNodes()
- // Output the phase dependency graph at this stage
- if (settings.genPhaseGraph.value != "")
- graphToDotFile(graph, settings.genPhaseGraph.value + "2.dot")
+ dump(2)
// Validate and Enforce hardlinks / runsRightAfter and promote nodes down the tree
graph.validateAndEnforceHardlinks()
- // Output the phase dependency graph at this stage
- if (settings.genPhaseGraph.value != "")
- graphToDotFile(graph, settings.genPhaseGraph.value + "3.dot")
+ dump(3)
// test for cycles, assign levels and collapse hard links into nodes
graph.collapseHardLinksAndLevels(graph.getNodeByPhase("parser"), 1)
- // Output the phase dependency graph at this stage
- if (settings.genPhaseGraph.value != "")
- graphToDotFile(graph, settings.genPhaseGraph.value + "4.dot")
+ dump(4)
// assemble the compiler
graph.compilerPhaseList()
@@ -288,16 +276,11 @@ trait PhaseAssembly {
sbuf.append("digraph G {\n")
for (edge <- graph.edges) {
sbuf.append("\"" + edge.frm.allPhaseNames + "(" + edge.frm.level + ")" + "\"->\"" + edge.to.allPhaseNames + "(" + edge.to.level + ")" + "\"")
- if (! edge.frm.phaseobj.get.head.internal) {
- extnodes += edge.frm
- }
- edge.frm.phaseobj match { case None => null case Some(ln) => if(ln.size > 1) fatnodes += edge.frm }
- edge.to.phaseobj match { case None => null case Some(ln) => if(ln.size > 1) fatnodes += edge.to }
- if (edge.hard) {
- sbuf.append(" [color=\"#0000ff\"]\n")
- } else {
- sbuf.append(" [color=\"#000000\"]\n")
- }
+ if (!edge.frm.phaseobj.get.head.internal) extnodes += edge.frm
+ edge.frm.phaseobj foreach (phobjs => if (phobjs.tail.nonEmpty) fatnodes += edge.frm )
+ edge.to.phaseobj foreach (phobjs => if (phobjs.tail.nonEmpty) fatnodes += edge.to )
+ val color = if (edge.hard) "#0000ff" else "#000000"
+ sbuf.append(s""" [color="$color"]\n""")
}
for (node <- extnodes) {
sbuf.append("\"" + node.allPhaseNames + "(" + node.level + ")" + "\" [color=\"#00ff00\"]\n")
@@ -306,10 +289,7 @@ trait PhaseAssembly {
sbuf.append("\"" + node.allPhaseNames + "(" + node.level + ")" + "\" [color=\"#0000ff\"]\n")
}
sbuf.append("}\n")
- val out = new BufferedWriter(new FileWriter(filename))
- out.write(sbuf.toString)
- out.flush()
- out.close()
+ import reflect.io._
+ for (d <- settings.outputDirs.getSingleOutput if !d.isVirtual) Path(d.file) / File(filename) writeAll sbuf.toString
}
-
}
diff --git a/src/compiler/scala/tools/nsc/SubComponent.scala b/src/compiler/scala/tools/nsc/SubComponent.scala
index 9b8582ae02..b21d156145 100644
--- a/src/compiler/scala/tools/nsc/SubComponent.scala
+++ b/src/compiler/scala/tools/nsc/SubComponent.scala
@@ -19,19 +19,30 @@ abstract class SubComponent {
/** The name of the phase */
val phaseName: String
- /** List of phase names, this phase should run after */
+ /** Names of phases that must run before this phase. */
val runsAfter: List[String]
- /** List of phase names, this phase should run before */
+ /** Names of phases that must run after this phase. Default is `Nil`. */
val runsBefore: List[String] = Nil
- /** Phase name this phase will attach itself to, not allowing any phase to come between it
- * and the phase name declared */
+ /** Name of the phase that this phase must follow immediately. */
val runsRightAfter: Option[String]
- /** Internal flag to tell external from internal phases */
+ /** Names of phases required by this component. Default is `Nil`. */
+ val requires: List[String] = Nil
+
+ /** Is this component enabled? Default is true. */
+ def enabled: Boolean = true
+
+ /** True if this phase is not provided by a plug-in. */
val internal: Boolean = true
+ /** True if this phase runs before all other phases. Usually, `parser`. */
+ val initial: Boolean = false
+
+ /** True if this phase runs after all other phases. Usually, `terminal`. */
+ val terminal: Boolean = false
+
/** SubComponent are added to a HashSet and two phases are the same if they have the same name */
override def hashCode() = phaseName.hashCode()
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index d7a32c3be0..5922b4bbbf 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -133,90 +133,6 @@ trait TreeDSL {
def ==>(body: Tree): CaseDef = CaseDef(pat, guard, body)
}
- /** VODD, if it's not obvious, means ValOrDefDef. This is the
- * common code between a tree based on a pre-existing symbol and
- * one being built from scratch.
- */
- trait VODDStart {
- def name: Name
- def defaultMods: Modifiers
- def defaultTpt: Tree
- def defaultPos: Position
-
- type ResultTreeType <: ValOrDefDef
- def mkTree(rhs: Tree): ResultTreeType
- def ===(rhs: Tree): ResultTreeType
-
- private var _tpt: Tree = null
- private var _pos: Position = null
-
- def withType(tp: Type): this.type = {
- _tpt = TypeTree(tp)
- this
- }
- def withPos(pos: Position): this.type = {
- _pos = pos
- this
- }
-
- final def mods = defaultMods
- final def tpt = if (_tpt == null) defaultTpt else _tpt
- final def pos = if (_pos == null) defaultPos else _pos
- }
- trait SymVODDStart extends VODDStart {
- def sym: Symbol
- def symType: Type
-
- def name = sym.name
- def defaultMods = Modifiers(sym.flags)
- def defaultTpt = TypeTree(symType) setPos sym.pos.focus
- def defaultPos = sym.pos
-
- final def ===(rhs: Tree): ResultTreeType =
- atPos(pos)(mkTree(rhs) setSymbol sym)
- }
- trait ValCreator {
- self: VODDStart =>
-
- type ResultTreeType = ValDef
- def mkTree(rhs: Tree): ValDef = ValDef(mods, name.toTermName, tpt, rhs)
- }
- trait DefCreator {
- self: VODDStart =>
-
- def tparams: List[TypeDef]
- def vparamss: List[List[ValDef]]
-
- type ResultTreeType = DefDef
- def mkTree(rhs: Tree): DefDef = DefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs)
- }
-
- class DefSymStart(val sym: Symbol) extends SymVODDStart with DefCreator {
- def symType = sym.tpe.finalResultType
- def tparams = sym.typeParams map TypeDef
- def vparamss = mapParamss(sym)(ValDef)
- }
- class ValSymStart(val sym: Symbol) extends SymVODDStart with ValCreator {
- def symType = sym.tpe
- }
-
- trait TreeVODDStart extends VODDStart {
- def defaultMods = NoMods
- def defaultTpt = TypeTree()
- def defaultPos = NoPosition
-
- final def ===(rhs: Tree): ResultTreeType =
- if (pos == NoPosition) mkTree(rhs)
- else atPos(pos)(mkTree(rhs))
- }
-
- class ValTreeStart(val name: Name) extends TreeVODDStart with ValCreator {
- }
- class DefTreeStart(val name: Name) extends TreeVODDStart with DefCreator {
- def tparams: List[TypeDef] = Nil
- def vparamss: List[List[ValDef]] = ListOfNil
- }
-
class IfStart(cond: Tree, thenp: Tree) {
def THEN(x: Tree) = new IfStart(cond, x)
def ELSE(elsep: Tree) = If(cond, thenp, elsep)
@@ -230,46 +146,23 @@ trait TreeDSL {
def CASE(pat: Tree): CaseStart = new CaseStart(pat, EmptyTree)
def DEFAULT: CaseStart = new CaseStart(WILD.empty, EmptyTree)
- class SymbolMethods(target: Symbol) {
- def IS_NULL() = REF(target) OBJ_EQ NULL
- def GET() = fn(REF(target), nme.get)
- def ARGS = target.paramss.head
- }
-
- /** Top level accessible. */
- def MATCHERROR(arg: Tree) = Throw(MatchErrorClass.tpe, arg)
- def THROW(sym: Symbol, msg: Tree): Throw = Throw(sym.tpe, msg.TOSTRING())
-
def NEW(tpt: Tree, args: Tree*): Tree = New(tpt, List(args.toList))
- def DEF(sym: Symbol): DefSymStart = new DefSymStart(sym)
- def VAL(sym: Symbol): ValSymStart = new ValSymStart(sym)
- def AND(guards: Tree*) =
- if (guards.isEmpty) EmptyTree
- else guards reduceLeft gen.mkAnd
+ def NOT(tree: Tree) = Select(tree, Boolean_not)
+ def AND(guards: Tree*) = if (guards.isEmpty) EmptyTree else guards reduceLeft gen.mkAnd
def IF(tree: Tree) = new IfStart(tree, EmptyTree)
def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree)
def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last)
- def NOT(tree: Tree) = Select(tree, Boolean_not)
- def SOME(xs: Tree*) = Apply(SomeClass.companionSymbol, makeTupleTerm(xs.toList, flattenUnary = true))
+ def SOME(xs: Tree*) = Apply(SomeClass.companionSymbol, treeBuilder.makeTupleTerm(xs.toList, flattenUnary = true))
/** Typed trees from symbols. */
- def THIS(sym: Symbol) = gen.mkAttributedThis(sym)
- def ID(sym: Symbol) = gen.mkAttributedIdent(sym)
- def REF(sym: Symbol) = gen.mkAttributedRef(sym)
- def REF(pre: Type, sym: Symbol) = gen.mkAttributedRef(pre, sym)
-
- def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree = trees match {
- case Nil => UNIT
- case List(tree) if flattenUnary => tree
- case _ => Apply(TupleClass(trees.length).companionModule, trees: _*)
- }
+ def REF(sym: Symbol) = gen.mkAttributedRef(sym)
+ def REF(pre: Type, sym: Symbol) = gen.mkAttributedRef(pre, sym)
/** Implicits - some of these should probably disappear **/
implicit def mkTreeMethods(target: Tree): TreeMethods = new TreeMethods(target)
implicit def mkTreeMethodsFromSymbol(target: Symbol): TreeMethods = new TreeMethods(Ident(target))
- implicit def mkSymbolMethodsFromSymbol(target: Symbol): SymbolMethods = new SymbolMethods(target)
/** (foo DOT bar) might be simply a Select, but more likely it is to be immediately
* followed by an Apply. We don't want to add an actual apply method to arbitrary
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index f3b842b170..07e24900e9 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -703,14 +703,10 @@ self =>
/* ---------- TREE CONSTRUCTION ------------------------------------------- */
- def atPos[T <: Tree](offset: Int)(t: T): T =
- global.atPos(r2p(offset, offset, in.lastOffset max offset))(t)
- def atPos[T <: Tree](start: Int, point: Int)(t: T): T =
- global.atPos(r2p(start, point, in.lastOffset max start))(t)
- def atPos[T <: Tree](start: Int, point: Int, end: Int)(t: T): T =
- global.atPos(r2p(start, point, end))(t)
- def atPos[T <: Tree](pos: Position)(t: T): T =
- global.atPos(pos)(t)
+ def atPos[T <: Tree](offset: Int)(t: T): T = atPos(r2p(offset, offset, in.lastOffset max offset))(t)
+ def atPos[T <: Tree](start: Int, point: Int)(t: T): T = atPos(r2p(start, point, in.lastOffset max start))(t)
+ def atPos[T <: Tree](start: Int, point: Int, end: Int)(t: T): T = atPos(r2p(start, point, end))(t)
+ def atPos[T <: Tree](pos: Position)(t: T): T = global.atPos(pos)(t)
def atInPos[T <: Tree](t: T): T = atPos(o2p(in.offset))(t)
def setInPos[T <: Tree](t: T): T = t setPos o2p(in.offset)
@@ -946,21 +942,23 @@ self =>
ts += annotType()
}
newLineOptWhenFollowedBy(LBRACE)
- atPos(t.pos.startOrPoint) {
- if (in.token == LBRACE) {
- // Warn if they are attempting to refine Unit; we can't be certain it's
- // scala.Unit they're refining because at this point all we have is an
- // identifier, but at a later stage we lose the ability to tell an empty
- // refinement from no refinement at all. See bug #284.
- for (Ident(name) <- ts) name.toString match {
- case "Unit" | "scala.Unit" =>
- warning("Detected apparent refinement of Unit; are you missing an '=' sign?")
- case _ =>
- }
- CompoundTypeTree(Template(ts.toList, emptyValDef, refinement()))
- }
- else
- makeIntersectionTypeTree(ts.toList)
+ val types = ts.toList
+ val braceOffset = in.offset
+ val hasRefinement = in.token == LBRACE
+ val refinements = if (hasRefinement) refinement() else Nil
+ // Warn if they are attempting to refine Unit; we can't be certain it's
+ // scala.Unit they're refining because at this point all we have is an
+ // identifier, but at a later stage we lose the ability to tell an empty
+ // refinement from no refinement at all. See bug #284.
+ if (hasRefinement) types match {
+ case Ident(name) :: Nil if name endsWith "Unit" => warning(braceOffset, "Detected apparent refinement of Unit; are you missing an '=' sign?")
+ case _ =>
+ }
+ // The second case includes an empty refinement - refinements is empty, but
+ // it still gets a CompoundTypeTree.
+ ts.toList match {
+ case tp :: Nil if !hasRefinement => tp // single type, no refinement, already positioned
+ case tps => atPos(t.pos.startOrPoint)(CompoundTypeTree(Template(tps, emptyValDef, refinements)))
}
}
@@ -2776,8 +2774,10 @@ self =>
def readAppliedParent() = {
val start = in.offset
val parent = startAnnotType()
- val argss = if (in.token == LPAREN) multipleArgumentExprs() else Nil
- parents += atPos(start)((parent /: argss)(Apply.apply))
+ parents += (in.token match {
+ case LPAREN => atPos(start)((parent /: multipleArgumentExprs())(Apply.apply))
+ case _ => parent
+ })
}
readAppliedParent()
while (in.token == WITH) { in.nextToken(); readAppliedParent() }
@@ -2818,6 +2818,8 @@ self =>
case tdef @ TypeDef(mods, name, tparams, rhs) =>
deprecationWarning(tdef.pos.point, "early type members are deprecated. Move them to the regular body: the semantics are the same.")
treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs)
+ case docdef @ DocDef(comm, rhs) =>
+ treeCopy.DocDef(docdef, comm, rhs)
case stat if !stat.isEmpty =>
syntaxError(stat.pos, "only concrete field definitions allowed in early object initialization section", skipIt = false)
EmptyTree
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index d622031e9d..91ff530e05 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -205,11 +205,6 @@ abstract class TreeBuilder {
atPos(r2p(start, end, end + op.length)) { new PostfixSelect(od, op.encode) }
}
- /** A type tree corresponding to (possibly unary) intersection type */
- def makeIntersectionTypeTree(tps: List[Tree]): Tree =
- if (tps.tail.isEmpty) tps.head
- else CompoundTypeTree(Template(tps, emptyValDef, Nil))
-
/** Create tree representing a while loop */
def makeWhile(startPos: Int, cond: Tree, body: Tree): Tree = {
val lname = freshTermName(nme.WHILE_PREFIX)
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index bde17b28fc..c49f23852f 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -18,6 +18,8 @@ abstract class ClosureElimination extends SubComponent {
val phaseName = "closelim"
+ override val enabled: Boolean = settings.Xcloselim
+
/** Create a new phase */
override def newPhase(p: Phase) = new ClosureEliminationPhase(p)
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala
index 43c8527f41..64a0727440 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala
@@ -34,6 +34,8 @@ abstract class ConstantOptimization extends SubComponent {
/** Create a new phase */
override def newPhase(p: Phase) = new ConstantOptimizationPhase(p)
+ override val enabled: Boolean = settings.YconstOptimization
+
/**
* The constant optimization phase.
*/
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index 7511da8b00..193aae37b6 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -22,6 +22,8 @@ abstract class DeadCodeElimination extends SubComponent {
val phaseName = "dce"
+ override val enabled: Boolean = settings.Xdce
+
/** Create a new phase */
override def newPhase(p: Phase) = new DeadCodeEliminationPhase(p)
diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala
index cecabda171..f4e97a91d8 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala
@@ -57,6 +57,8 @@ abstract class InlineExceptionHandlers extends SubComponent {
/** Create a new phase */
override def newPhase(p: Phase) = new InlineExceptionHandlersPhase(p)
+ override def enabled = settings.inlineHandlers
+
/**
* Inlining Exception Handlers
*/
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 09095879bf..181f4bde4e 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -49,6 +49,8 @@ abstract class Inliners extends SubComponent {
val phaseName = "inliner"
+ override val enabled: Boolean = settings.inline
+
/** Debug - for timing the inliner. */
/****
private def timed[T](s: String, body: => T): T = {
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
index 4fd6ba7d9d..1578caff26 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
@@ -41,12 +41,31 @@ abstract class Plugin {
*/
val global: Global
- /** Handle any plugin-specific options. The `-P:plugname:` part
- * will not be present.
+ def options: List[String] = {
+ // Process plugin options of form plugin:option
+ def namec = name + ":"
+ global.settings.pluginOptions.value filter (_ startsWith namec) map (_ stripPrefix namec)
+ }
+
+ /** Handle any plugin-specific options.
+ * The user writes `-P:plugname:opt1,opt2`,
+ * but the plugin sees `List(opt1, opt2)`.
+ * The plugin can opt out of further processing
+ * by returning false. For example, if the plugin
+ * has an "enable" flag, now would be a good time
+ * to sit on the bench.
+ * @param options plugin arguments
+ * @param error error function
+ * @return true to continue, or false to opt out
*/
- def processOptions(options: List[String], error: String => Unit) {
- if (!options.isEmpty)
- error("Error: " + name + " has no options")
+ def init(options: List[String], error: String => Unit): Boolean = {
+ processOptions(options, error)
+ true
+ }
+
+ @deprecated("use Plugin#init instead", since="2.11")
+ def processOptions(options: List[String], error: String => Unit): Unit = {
+ if (!options.isEmpty) error(s"Error: $name takes no options")
}
/** A description of this plugin's options, suitable as a response
diff --git a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala
index c6e1af7ea4..a6df08c331 100644
--- a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala
+++ b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala
@@ -15,12 +15,10 @@ package plugins
*/
abstract class PluginComponent extends SubComponent {
- /** Internal flag to tell external from internal phases */
+ /** By definition, plugin phases are externally provided. */
final override val internal = false
- /** Phases supplied by plugins should not have to supply the
- * runsRightAfter constraint, but can override it.
- */
+ /** Only plugins are granted a reprieve from specifying whether they follow. */
val runsRightAfter: Option[String] = None
/** Useful for -Xshow-phases. */
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
index 8f7794fa90..4769705404 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
@@ -78,27 +78,18 @@ trait Plugins {
val plugs = pick(roughPluginsList, Set(), (phasesSet map (_.phaseName)).toSet)
- /* Verify requirements are present. */
+ // Verify required plugins are present.
for (req <- settings.require.value ; if !(plugs exists (_.name == req)))
globalError("Missing required plugin: " + req)
- /* Process plugin options. */
- def namec(plug: Plugin) = plug.name + ":"
- def optList(xs: List[String], p: Plugin) = xs filter (_ startsWith namec(p))
- def doOpts(p: Plugin): List[String] =
- optList(settings.pluginOptions.value, p) map (_ stripPrefix namec(p))
+ // Verify no non-existent plugin given with -P
+ for {
+ opt <- settings.pluginOptions.value
+ if !(plugs exists (opt startsWith _.name + ":"))
+ } globalError("bad option: -P:" + opt)
- for (p <- plugs) {
- val opts = doOpts(p)
- if (!opts.isEmpty)
- p.processOptions(opts, globalError)
- }
-
- /* Verify no non-existent plugin given with -P */
- for (opt <- settings.pluginOptions.value ; if plugs forall (p => optList(List(opt), p).isEmpty))
- globalError("bad option: -P:" + opt)
-
- plugs
+ // Plugins may opt out, unless we just want to show info
+ plugs filter (p => p.init(p.options, globalError) || (settings.debug && settings.isInfo))
}
lazy val plugins: List[Plugin] = loadPlugins()
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 32f0571e83..96c93a838b 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -41,6 +41,12 @@ trait ScalaSettings extends AbsScalaSettings
/** Enabled under -optimise. */
def optimiseSettings = List[BooleanSetting](inline, inlineHandlers, Xcloselim, Xdce, YconstOptimization)
+ /** If any of these settings is enabled, the compiler should print a message and exit. */
+ def infoSettings = List[Setting](help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
+
+ /** Is an info setting set? */
+ def isInfo = infoSettings exists (_.isSetByUser)
+
/** Internal use - syntax enhancements. */
private class EnableSettings[T <: BooleanSetting](val s: T) {
def enabling(toEnable: List[BooleanSetting]): s.type = s withPostSetHook (_ => toEnable foreach (_.value = s.value))
@@ -182,7 +188,6 @@ trait ScalaSettings extends AbsScalaSettings
*/
val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
- val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
val Yissuedebug = BooleanSetting("-Yissue-debug", "Print stack traces when a context issues an error.")
val YmacrodebugLite = BooleanSetting("-Ymacro-debug-lite", "Trace essential macro-related activities.")
val YmacrodebugVerbose = BooleanSetting("-Ymacro-debug-verbose", "Trace all macro-related activities: compilation, generation of synthetics, classloading, expansion, exceptions.")
@@ -193,6 +198,9 @@ trait ScalaSettings extends AbsScalaSettings
val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.")
val Yquasiquotedebug = BooleanSetting("-Yquasiquote-debug", "Trace quasiquote-related activities.")
+ // TODO 2.12 Remove
+ val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.") withDeprecationMessage("Use -Ytyper-debug") enabling(List(Ytyperdebug))
+
/** Groups of Settings.
*/
val future = BooleanSetting("-Xfuture", "Turn on future language features.") enabling futureSettings
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index b16ba91916..0135190256 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -94,7 +94,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
if (!isFinal)
varSym.addAnnotation(VolatileAttr)
- val varDef = typedPos( VAL(varSym) === forInit )
+ val varDef = typedPos(ValDef(varSym, forInit))
newStaticMembers append transform(varDef)
val varInit = typedPos( REF(varSym) === forInit )
@@ -155,13 +155,13 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val methodSym = reflMethodSym.newVariable(mkTerm("method"), ad.pos) setInfo MethodClass.tpe
BLOCK(
- VAL(methodCache) === getPolyCache,
+ ValDef(methodCache, getPolyCache),
IF (REF(methodCache) OBJ_EQ NULL) THEN BLOCK(
REF(methodCache) === NEW(TypeTree(EmptyMethodCacheClass.tpe)),
REF(reflPolyCacheSym) === gen.mkSoftRef(REF(methodCache))
) ENDIF,
- VAL(methodSym) === (REF(methodCache) DOT methodCache_find)(REF(forReceiverSym)),
+ ValDef(methodSym, (REF(methodCache) DOT methodCache_find)(REF(forReceiverSym))),
IF (REF(methodSym) OBJ_NE NULL) .
THEN (Return(REF(methodSym)))
ELSE {
@@ -372,7 +372,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
qual = REF(sym)
BLOCK(
- VAL(sym) === qual0,
+ ValDef(sym, qual0),
callAsReflective(mparams map (_.tpe), resType)
)
}
@@ -543,7 +543,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
)
// create field definition and initialization
- val stfieldDef = theTyper.typedPos(pos)(VAL(stfieldSym) === rhs)
+ val stfieldDef = theTyper.typedPos(pos)(ValDef(stfieldSym, rhs))
val stfieldInit = theTyper.typedPos(pos)(REF(stfieldSym) === rhs)
// add field definition to new defs
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index c74fc620ca..31855bc1ad 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -268,7 +268,7 @@ abstract class Erasure extends AddInterfaces
else abbrvTag(sym).toString
}
else if (sym.isDerivedValueClass) {
- val unboxed = sym.derivedValueClassUnbox.info.finalResultType
+ val unboxed = sym.derivedValueClassUnbox.tpe_*.finalResultType
val unboxedSeen = (tp memberType sym.derivedValueClassUnbox).finalResultType
def unboxedMsg = if (unboxed == unboxedSeen) "" else s", seen within ${sym.simpleName} as $unboxedSeen"
logResult(s"Erasure of value class $sym (underlying type $unboxed$unboxedMsg) is") {
@@ -513,7 +513,7 @@ abstract class Erasure extends AddInterfaces
maybeWrap(bridgingCall)
}
- atPos(bridge.pos)(DefDef(bridge, rhs))
+ DefDef(bridge, rhs)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index d6a6e027cb..a2bf5bf9e5 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -90,7 +90,7 @@ abstract class ExplicitOuter extends InfoTransform
sym expandName clazz
sym.referenced = clazz
- sym setInfo MethodType(Nil, restpe)
+ sym setInfo MethodType(Nil, restpe.widen)
}
def newOuterField(clazz: Symbol) = {
val accFlags = SYNTHETIC | ARTIFACT | PARAMACCESSOR | ( if (clazz.isEffectivelyFinal) PrivateLocal else PROTECTED )
@@ -216,7 +216,7 @@ abstract class ExplicitOuter extends InfoTransform
* values for outer parameters of constructors.
* The class provides methods for referencing via outer.
*/
- abstract class OuterPathTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
+ abstract class OuterPathTransformer(unit: CompilationUnit) extends TypingTransformer(unit) with UnderConstructionTransformer {
/** The directly enclosing outer parameter, if we are in a constructor */
protected var outerParam: Symbol = NoSymbol
@@ -225,9 +225,10 @@ abstract class ExplicitOuter extends InfoTransform
*
* Will return `EmptyTree` if there is no outer accessor because of a premature self reference.
*/
- protected def outerValue: Tree =
- if (outerParam != NoSymbol) ID(outerParam)
- else outerSelect(THIS(currentClass))
+ protected def outerValue: Tree = outerParam match {
+ case NoSymbol => outerSelect(gen.mkAttributedThis(currentClass))
+ case outerParam => gen.mkAttributedIdent(outerParam)
+ }
/** Select and apply outer accessor from 'base'
* The result is typed but not positioned.
@@ -276,16 +277,6 @@ abstract class ExplicitOuter extends InfoTransform
}
- /** The stack of class symbols in which a call to this() or to the super
- * constructor, or early definition is active
- */
- protected def isUnderConstruction(clazz: Symbol) = selfOrSuperCalls contains clazz
- protected val selfOrSuperCalls = mutable.Stack[Symbol]()
- @inline protected def inSelfOrSuperCall[A](sym: Symbol)(a: => A) = {
- selfOrSuperCalls push sym
- try a finally selfOrSuperCalls.pop()
- }
-
override def transform(tree: Tree): Tree = {
val savedOuterParam = outerParam
try {
@@ -299,10 +290,7 @@ abstract class ExplicitOuter extends InfoTransform
}
case _ =>
}
- if ((treeInfo isSelfOrSuperConstrCall tree) || (treeInfo isEarlyDef tree))
- inSelfOrSuperCall(currentOwner.owner)(super.transform(tree))
- else
- super.transform(tree)
+ super.transform(tree)
}
finally outerParam = savedOuterParam
}
@@ -368,8 +356,7 @@ abstract class ExplicitOuter extends InfoTransform
/** The definition tree of the outer accessor of current class
*/
- def outerFieldDef: Tree =
- VAL(outerField(currentClass)) === EmptyTree
+ def outerFieldDef: Tree = ValDef(outerField(currentClass))
/** The definition tree of the outer accessor of current class
*/
diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
index 56ec49e962..6a405295cf 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -205,7 +205,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
def makeExtensionMethodSymbol = {
val extensionName = extensionNames(origMeth).head.toTermName
val extensionMeth = (
- companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE & ~PROTECTED | FINAL)
+ companion.moduleClass.newMethod(extensionName, tree.pos.focus, origMeth.flags & ~OVERRIDE & ~PROTECTED | FINAL)
setAnnotations origMeth.annotations
)
origMeth.removeAnnotation(TailrecClass) // it's on the extension method, now.
@@ -230,9 +230,14 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
.changeOwner(origMeth -> extensionMeth)
new SubstututeRecursion(origMeth, extensionMeth, unit).transform(tree)
}
+ val castBody =
+ if (extensionBody.tpe <:< extensionMono.finalResultType)
+ extensionBody
+ else
+ gen.mkCastPreservingAnnotations(extensionBody, extensionMono.finalResultType) // SI-7818 e.g. mismatched existential skolems
// Record the extension method. Later, in `Extender#transformStats`, these will be added to the companion object.
- extensionDefs(companion) += atPos(tree.pos)(DefDef(extensionMeth, extensionBody))
+ extensionDefs(companion) += DefDef(extensionMeth, castBody)
// These three lines are assembling Foo.bar$extension[T1, T2, ...]($this)
// which leaves the actual argument application for extensionCall.
@@ -289,7 +294,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
val origThis = extensionMeth.owner.companionClass
val baseType = qual.tpe.baseType(origThis)
val allTargs = targs.map(_.tpe) ::: baseType.typeArgs
- val fun = gen.mkAttributedTypeApply(THIS(extensionMeth.owner), extensionMeth, allTargs)
+ val fun = gen.mkAttributedTypeApply(gen.mkAttributedThis(extensionMeth.owner), extensionMeth, allTargs)
allArgss.foldLeft(fun)(Apply(_, _))
}
case _ => super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 515fa66cfa..acef2a50d8 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -436,8 +436,15 @@ abstract class LambdaLift extends InfoTransform {
private def liftDef(tree: Tree): Tree = {
val sym = tree.symbol
val oldOwner = sym.owner
- if (sym.owner.isAuxiliaryConstructor && sym.isMethod) // # bug 1909
- sym setFlag STATIC
+ if (sym.isMethod && isUnderConstruction(sym.owner.owner)) { // # bug 1909
+ if (sym.isModule) { // Yes, it can be a module and a method, see comments on `isModuleNotMethod`!
+ // TODO promote to an implementation restriction if we can reason that this *always* leads to VerifyError.
+ // See neg/t1909-object.scala
+ def msg = s"SI-1909 Unable to STATICally lift $sym, which is defined in the self- or super-constructor call of ${sym.owner.owner}. A VerifyError is likely."
+ devWarning(tree.pos, msg)
+ } else sym setFlag STATIC
+ }
+
sym.owner = sym.owner.enclClass
if (sym.isClass) sym.owner = sym.owner.toInterface
if (sym.isMethod) sym setFlag LIFTED
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index 15ca916ac1..b71d14a04f 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -199,14 +199,15 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
if (bitmaps.contains(lzyVal))
bitmaps(lzyVal).map(_.owner = defSym)
val rhs: Tree = (gen.mkSynchronizedCheck(clazz, cond, syncBody, stats)).changeOwner(currentOwner -> defSym)
- DEF(defSym).mkTree(addBitmapDefs(lzyVal, BLOCK(rhs, retVal))) setSymbol defSym
+
+ DefDef(defSym, addBitmapDefs(lzyVal, BLOCK(rhs, retVal)))
}
def mkFastPathBody(clazz: Symbol, lzyVal: Symbol, cond: Tree, syncBody: List[Tree],
stats: List[Tree], retVal: Tree): (Tree, Tree) = {
val slowPathDef: Tree = mkSlowPathDef(clazz, lzyVal, cond, syncBody, stats, retVal)
- (If(cond, Apply(ID(slowPathDef.symbol), List()), retVal), slowPathDef)
+ (If(cond, Apply(Ident(slowPathDef.symbol), Nil), retVal), slowPathDef)
}
/** return a 'lazified' version of rhs. Rhs should conform to the
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 3ec4d16bf5..7b545be07e 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -472,7 +472,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** The typer */
private var localTyper: erasure.Typer = _
private def typedPos(pos: Position)(tree: Tree): Tree = localTyper.typedPos(pos)(tree)
- private def localTyped(pos: Position, tree: Tree, pt: Type) = localTyper.typed(atPos(pos)(tree), pt)
/** Map lazy values to the fields they should null after initialization. */
private var lazyValNullables: Map[Symbol, Set[Symbol]] = _
@@ -695,10 +694,10 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
def completeSuperAccessor(stat: Tree) = stat match {
case DefDef(_, _, _, vparams :: Nil, _, EmptyTree) if stat.symbol.isSuperAccessor =>
- val rhs0 = (Super(clazz, tpnme.EMPTY) DOT stat.symbol.alias)(vparams map (v => Ident(v.symbol)): _*)
- val rhs1 = localTyped(stat.pos, rhs0, stat.symbol.tpe.resultType)
+ val body = atPos(stat.pos)(Apply(Select(Super(clazz, tpnme.EMPTY), stat.symbol.alias), vparams map (v => Ident(v.symbol))))
+ val pt = stat.symbol.tpe.resultType
- deriveDefDef(stat)(_ => enteringMixin(transform(rhs1)))
+ copyDefDef(stat)(rhs = enteringMixin(transform(localTyper.typed(body, pt))))
case _ =>
stat
}
@@ -724,8 +723,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
case _ =>
}
val init = bitmapKind match {
- case BooleanClass => VAL(sym) === FALSE
- case _ => VAL(sym) === ZERO
+ case BooleanClass => ValDef(sym, FALSE)
+ case _ => ValDef(sym, ZERO)
}
sym setFlag PrivateLocal
@@ -775,7 +774,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
defSym setInfoAndEnter MethodType(params, lzyVal.tpe.resultType)
val rhs: Tree = (gen.mkSynchronizedCheck(attrThis, cond, syncBody, stats)).changeOwner(currentOwner -> defSym)
val strictSubst = new TreeSymSubstituterWithCopying(args.map(_.symbol), params)
- addDef(position(defSym), DEF(defSym).mkTree(strictSubst(BLOCK(rhs, retVal))) setSymbol defSym)
+ addDef(position(defSym), DefDef(defSym, strictSubst(BLOCK(rhs, retVal))))
defSym
}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 4bc4e06fa7..5a440039d6 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -1836,12 +1836,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
// ctor
- mbrs += atPos(m.pos)(DefDef(m, Modifiers(m.flags), mmap(List(vparams))(ValDef), EmptyTree))
+ mbrs += DefDef(m, Modifiers(m.flags), mmap(List(vparams))(ValDef), EmptyTree)
} else {
- mbrs += atPos(m.pos)(DefDef(m, { paramss => EmptyTree }))
+ mbrs += DefDef(m, { paramss => EmptyTree })
}
} else if (m.isValue) {
- mbrs += ValDef(m, EmptyTree).setType(NoType).setPos(m.pos)
+ mbrs += ValDef(m).setType(NoType)
} else if (m.isClass) {
// mbrs +=
// ClassDef(m, Template(m.info.parents map TypeTree, emptyValDef, List())
@@ -1853,9 +1853,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val isSpecializedInstance = sClass :: sClass.parentSymbols exists (_ hasFlag SPECIALIZED)
val sym = sClass.newMethod(nme.SPECIALIZED_INSTANCE, sClass.pos) setInfoAndEnter MethodType(Nil, BooleanTpe)
- mbrs += atPos(sym.pos) {
- DefDef(sym, Literal(Constant(isSpecializedInstance)).setType(BooleanTpe)).setType(NoType)
- }
+ mbrs += DefDef(sym, Literal(Constant(isSpecializedInstance)).setType(BooleanTpe)).setType(NoType)
}
mbrs.toList
}
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index 6f422fcc90..b471d16ddd 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -156,7 +156,7 @@ abstract class TailCalls extends Transform {
private def mkLabel() = {
val label = method.newLabel(newTermName("_" + method.name), method.pos)
val thisParam = method.newSyntheticValueParam(currentClass.typeOfThis)
- label setInfo MethodType(thisParam :: method.tpe.params, method.tpe.finalResultType)
+ label setInfo MethodType(thisParam :: method.tpe.params, method.tpe_*.finalResultType)
if (isEligible)
label substInfo (method.tpe.typeParams, tparams)
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 16c803e2e8..e68f55a09e 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -158,11 +158,12 @@ abstract class UnCurry extends InfoTransform
*/
private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = {
localTyper typed {
- val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType)
+ val restpe = meth.tpe_*.finalResultType
+ val extpe = nonLocalReturnExceptionType(restpe)
val ex = meth.newValue(nme.ex, body.pos) setInfo extpe
- val argType = meth.tpe.finalResultType withAnnotation (AnnotationInfo marker UncheckedClass.tpe)
+ val argType = restpe withAnnotation (AnnotationInfo marker UncheckedClass.tpe)
val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(argType))
- val rhs = (
+ val rhs = (
IF ((ex DOT nme.key)() OBJ_EQ Ident(key))
THEN ((ex DOT nme.value)())
ELSE (Throw(Ident(ex)))
@@ -739,7 +740,7 @@ abstract class UnCurry extends InfoTransform
case p if rpsymbols(p.symbol) => toArrayType(p.symbol.tpe)
case p => p.symbol.tpe
}
- val forwresult = dd.symbol.tpe.finalResultType
+ val forwresult = dd.symbol.tpe_*.finalResultType
val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) =>
currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp)
)
@@ -751,10 +752,11 @@ abstract class UnCurry extends InfoTransform
// create the symbol
val forwsym = currentClass.newMethod(dd.name.toTermName, dd.pos, VARARGS | SYNTHETIC | flatdd.symbol.flags) setInfo forwtype
+ def forwParams = forwsym.info.paramss.flatten
// create the tree
val forwtree = theTyper.typedPos(dd.pos) {
- val locals = map2(forwsym ARGS, flatparams) {
+ val locals = map2(forwParams, flatparams) {
case (_, fp) if !rpsymbols(fp.symbol) => null
case (argsym, fp) =>
Block(Nil,
@@ -764,15 +766,13 @@ abstract class UnCurry extends InfoTransform
)
)
}
- val seqargs = map2(locals, forwsym ARGS) {
+ val seqargs = map2(locals, forwParams) {
case (null, argsym) => Ident(argsym)
case (l, _) => l
}
val end = if (forwsym.isConstructor) List(UNIT) else Nil
- DEF(forwsym) === BLOCK(
- Apply(gen.mkAttributedRef(flatdd.symbol), seqargs) :: end : _*
- )
+ DefDef(forwsym, BLOCK(Apply(gen.mkAttributedRef(flatdd.symbol), seqargs) :: end : _*))
}
// check if the method with that name and those arguments already exists in the template
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala
index cf74f0fb11..c8dbbb02bb 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala
@@ -170,7 +170,7 @@ trait MatchCodeGen extends Interface {
} toList // at most 1 element
// scrutSym == NoSymbol when generating an alternatives matcher
- val scrutDef = scrutSym.fold(List[Tree]())(sym => (VAL(sym) === scrut) :: Nil) // for alternatives
+ val scrutDef = scrutSym.fold(List[Tree]())(ValDef(_, scrut) :: Nil) // for alternatives
// the generated block is taken apart in TailCalls under the following assumptions
// the assumption is once we encounter a case, the remainder of the block will consist of cases
@@ -199,7 +199,7 @@ trait MatchCodeGen extends Interface {
def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = {
val prevSym = freshSym(prev.pos, prev.tpe, "o")
BLOCK(
- VAL(prevSym) === prev,
+ ValDef(prevSym, prev),
// must be isEmpty and get as we don't control the target of the call (prev is an extractor call)
ifThenElseZero(
NOT(prevSym DOT vpmName.isEmpty),
@@ -214,14 +214,12 @@ trait MatchCodeGen extends Interface {
// next == MatchMonad[U]
// returns MatchMonad[U]
def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree = {
- val rest =
+ val rest = (
// only emit a local val for `nextBinder` if it's actually referenced in `next`
if (next.exists(_.symbol eq nextBinder))
- BLOCK(
- VAL(nextBinder) === res,
- next
- )
+ BLOCK(ValDef(nextBinder, res), next)
else next
+ )
ifThenElseZero(cond, rest)
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
index ec45789687..ba78438b66 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
@@ -146,7 +146,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
lazy val storedCond = freshSym(pos, BooleanTpe, "rc") setFlag MUTABLE
lazy val treesToHoist: List[Tree] = {
nextBinder setFlag MUTABLE
- List(storedCond, nextBinder) map { b => VAL(b) === codegen.mkZero(b.info) }
+ List(storedCond, nextBinder) map (b => ValDef(b, codegen.mkZero(b.info)))
}
// TODO: finer-grained duplication
@@ -528,7 +528,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
}
def defaultSym: Symbol = scrutSym
- def defaultBody: Tree = { import CODE._; matchFailGenOverride map (gen => gen(REF(scrutSym))) getOrElse MATCHERROR(REF(scrutSym)) }
+ def defaultBody: Tree = { import CODE._; matchFailGenOverride map (gen => gen(REF(scrutSym))) getOrElse Throw(MatchErrorClass.tpe, REF(scrutSym)) }
def defaultCase(scrutSym: Symbol = defaultSym, guard: Tree = EmptyTree, body: Tree = defaultBody): CaseDef = { import CODE._; atPos(body.pos) {
(DEFAULT IF guard) ==> body
}}
@@ -546,7 +546,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
if (scrutSym.tpe =:= IntTpe) REF(scrutSym)
else (REF(scrutSym) DOT (nme.toInt))
Some(BLOCK(
- VAL(scrutSym) === scrut,
+ ValDef(scrutSym, scrut),
Match(scrutToInt, caseDefsWithDefault) // a switch
))
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
index 942aa80c34..cf26ec3398 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
@@ -174,7 +174,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
else {
// only store binders actually used
val (subPatBindersStored, subPatRefsStored) = stored.filter{case (b, _) => usedBinders(b)}.unzip
- Block(map2(subPatBindersStored.toList, subPatRefsStored.toList)(VAL(_) === _), in)
+ Block(map2(subPatBindersStored.toList, subPatRefsStored.toList)(ValDef(_, _)), in)
}
}
}
@@ -328,9 +328,9 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
def outerTest(testedBinder: Symbol, expectedTp: Type): Tree = {
val expectedOuter = expectedTp.prefix match {
- case ThisType(clazz) => THIS(clazz)
- case pre if pre != NoType => REF(pre.prefix, pre.termSymbol)
- case _ => mkTRUE // fallback for SI-6183
+ case ThisType(clazz) => This(clazz)
+ case NoType => mkTRUE // fallback for SI-6183
+ case pre => REF(pre.prefix, pre.termSymbol)
}
// ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix`
@@ -527,8 +527,9 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
// pt is the fully defined type of the cases (either pt or the lub of the types of the cases)
def combineCasesNoSubstOnly(scrut: Tree, scrutSym: Symbol, casesNoSubstOnly: List[List[TreeMaker]], pt: Type, owner: Symbol, matchFailGenOverride: Option[Tree => Tree]): Tree =
- fixerUpper(owner, scrut.pos){
- def matchFailGen = (matchFailGenOverride orElse Some(CODE.MATCHERROR(_: Tree)))
+ fixerUpper(owner, scrut.pos) {
+ def matchFailGen = matchFailGenOverride orElse Some(Throw(MatchErrorClass.tpe, _: Tree))
+
debug.patmat("combining cases: "+ (casesNoSubstOnly.map(_.mkString(" >> ")).mkString("{", "\n", "}")))
val (suppression, requireSwitch): (Suppression, Boolean) =
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index 263b5ad784..ec2b7d49f5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -21,32 +21,17 @@ trait MethodSynthesis {
import definitions._
import CODE._
- object synthesisUtil {
- type TT[T] = ru.TypeTag[T]
- type CT[T] = ClassTag[T]
-
- def newValOrDefDef(sym: Symbol, body: Tree) =
- if (sym.isLazy) ValDef(sym, body)
- else DefDef(sym, body)
-
- /** The annotations amongst those found on the original symbol which
- * should be propagated to this kind of accessor.
- */
- def deriveAnnotations(initial: List[AnnotationInfo], category: Symbol, keepClean: Boolean): List[AnnotationInfo] = {
- initial filter { ann =>
- // There are no meta-annotation arguments attached to `ann`
- if (ann.metaAnnotations.isEmpty) {
- // A meta-annotation matching `annotKind` exists on `ann`'s definition.
- (ann.defaultTargets contains category) ||
- // `ann`'s definition has no meta-annotations, and `keepClean` is true.
- (ann.defaultTargets.isEmpty && keepClean)
- }
- // There are meta-annotation arguments, and one of them matches `annotKind`
- else ann.metaAnnotations exists (_ matches category)
- }
+ /** The annotations amongst those found on the original symbol which
+ * should be propagated to this kind of accessor.
+ */
+ def deriveAnnotations(initial: List[AnnotationInfo], category: Symbol, keepClean: Boolean): List[AnnotationInfo] = {
+ def annotationFilter(ann: AnnotationInfo) = ann.metaAnnotations match {
+ case Nil if ann.defaultTargets.isEmpty => keepClean // no meta-annotations or default targets
+ case Nil => ann.defaultTargets contains category // default targets exist for ann
+ case metas => metas exists (_ matches category) // meta-annotations attached to ann
}
+ initial filter annotationFilter
}
- import synthesisUtil._
class ClassMethodSynthesis(val clazz: Symbol, localTyper: Typer) {
def mkThis = This(clazz) setPos clazz.pos.focus
@@ -67,7 +52,10 @@ trait MethodSynthesis {
}
private def finishMethod(method: Symbol, f: Symbol => Tree): Tree =
- localTyper typed newValOrDefDef(method, f(method))
+ localTyper typed (
+ if (method.isLazy) ValDef(method, f(method))
+ else DefDef(method, f(method))
+ )
private def createInternal(name: Name, f: Symbol => Tree, info: Type): Tree = {
val name1 = name.toTermName
@@ -105,7 +93,7 @@ trait MethodSynthesis {
def createSwitchMethod(name: Name, range: Seq[Int], returnType: Type)(f: Int => Tree) = {
createMethod(name, List(IntTpe), returnType) { m =>
val arg0 = Ident(m.firstParam)
- val default = DEFAULT ==> THROW(IndexOutOfBoundsExceptionClass, arg0)
+ val default = DEFAULT ==> Throw(IndexOutOfBoundsExceptionClass.tpe_*, fn(arg0, nme.toString_))
val cases = range.map(num => CASE(LIT(num)) ==> f(num)).toList :+ default
Match(arg0, cases)
@@ -393,18 +381,9 @@ trait MethodSynthesis {
}
}
case class Getter(tree: ValDef) extends BaseGetter(tree) {
- override def derivedSym = (
- if (mods.isDeferred) basisSym
- else basisSym.getter(enclClass)
- )
- // Range position errors ensue if we don't duplicate this in some
- // circumstances (at least: concrete vals with existential types.)
- private def tptOriginal = (
- if (mods.isDeferred) tree.tpt // keep type tree of original abstract field
- else tree.tpt.duplicate setPos tree.tpt.pos.focus // focused position of original tpt
- )
-
- override def derivedTree: DefDef = {
+ override def derivedSym = if (mods.isDeferred) basisSym else basisSym.getter(enclClass)
+ private def derivedRhs = if (mods.isDeferred) EmptyTree else fieldSelection
+ private def derivedTpt = {
// For existentials, don't specify a type for the getter, even one derived
// from the symbol! This leads to incompatible existentials for the field and
// the getter. Let the typer do all the work. You might think "why only for
@@ -413,24 +392,16 @@ trait MethodSynthesis {
// starts compiling (instead of failing like it's supposed to) because the typer
// expects to be able to identify escaping locals in typedDefDef, and fails to
// spot that brand of them. In other words it's an artifact of the implementation.
- val tpt = atPos(derivedSym.pos.focus)(derivedSym.tpe.finalResultType match {
- case ExistentialType(_, _) => TypeTree()
- case _ if mods.isDeferred => TypeTree()
+ val tpt = derivedSym.tpe_*.finalResultType.widen match {
+ // Range position errors ensue if we don't duplicate this in some
+ // circumstances (at least: concrete vals with existential types.)
+ case ExistentialType(_, _) => TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus)
+ case _ if mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field
case tp => TypeTree(tp)
- })
- // TODO - reconcile this with the DefDef creator in Trees (which
- // at this writing presented no way to pass a tree in for tpt.)
- atPos(derivedSym.pos) {
- DefDef(
- Modifiers(derivedSym.flags),
- derivedSym.name.toTermName,
- Nil,
- Nil,
- tpt setOriginal tptOriginal,
- if (mods.isDeferred) EmptyTree else fieldSelection
- ) setSymbol derivedSym
}
+ tpt setPos tree.tpt.pos.focus
}
+ override def derivedTree: DefDef = newDefDef(derivedSym, derivedRhs)(tpt = derivedTpt)
}
/** Implements lazy value accessors:
* - for lazy values of type Unit and all lazy fields inside traits,
@@ -461,8 +432,8 @@ trait MethodSynthesis {
if (tree.symbol.owner.isTrait || hasUnitType(basisSym)) rhs1
else gen.mkAssignAndReturn(basisSym, rhs1)
)
- derivedSym.setPos(tree.pos) // cannot set it at createAndEnterSymbol because basisSym can possible stil have NoPosition
- val ddefRes = atPos(tree.pos)(DefDef(derivedSym, new ChangeOwnerAndModuleClassTraverser(basisSym, derivedSym)(body)))
+ derivedSym setPos tree.pos // cannot set it at createAndEnterSymbol because basisSym can possible stil have NoPosition
+ val ddefRes = DefDef(derivedSym, new ChangeOwnerAndModuleClassTraverser(basisSym, derivedSym)(body))
// ValDef will have its position focused whereas DefDef will have original correct rangepos
// ideally positions would be correct at the creation time but lazy vals are really a special case
// here so for the sake of keeping api clean we fix positions manually in LazyValGetter
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 454f913412..9ac0b0835a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -135,7 +135,8 @@ trait Namers extends MethodSynthesis {
setPrivateWithin(tree, sym, tree.mods)
def inConstructorFlag: Long = {
- val termOwnedContexts: List[Context] = context.enclosingContextChain.takeWhile(_.owner.isTerm)
+ val termOwnedContexts: List[Context] =
+ context.enclosingContextChain.takeWhile(c => c.owner.isTerm && !c.owner.isAnonymousFunction)
val constructorNonSuffix = termOwnedContexts exists (c => c.owner.isConstructor && !c.inConstructorSuffix)
val earlyInit = termOwnedContexts exists (_.owner.isEarlyInitialized)
if (constructorNonSuffix || earlyInit) INCONSTRUCTOR else 0L
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 12d6bb2e6a..b706e1af6b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -296,8 +296,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
transformSelect
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) if tree.symbol.isMethodWithExtension =>
- treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, withInvalidOwner(transform(rhs)))
+ case DefDef(_, _, _, _, _, _) if tree.symbol.isMethodWithExtension =>
+ deriveDefDef(tree)(rhs => withInvalidOwner(transform(rhs)))
case TypeApply(sel @ Select(qual, name), args) =>
mayNeedProtectedAccessor(sel, args, goToSuper = true)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 629513ada3..3ac0b398ee 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -363,7 +363,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
check(owner, scope, pt, tree setType tp1.typeSymbol.classBound)
else if (owner == NoSymbol)
tree setType packSymbols(hiddenSymbols.reverse, tp1)
- else if (!phase.erasedTypes) { // privates
+ else if (!isPastTyper) { // privates
val badSymbol = hiddenSymbols.head
SymbolEscapesScopeError(tree, badSymbol)
} else tree
@@ -2103,7 +2103,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case PolyType(_, restpe) => paramssTypes(restpe)
case _ => Nil
}
- def resultType = meth.tpe.finalResultType
+ def resultType = meth.tpe_*.finalResultType
def nthParamPos(n1: Int, n2: Int) =
try ddef.vparamss(n1)(n2).pos catch { case _: IndexOutOfBoundsException => meth.pos }
@@ -2598,8 +2598,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
default -> gen.scalaFunctionConstr(List(A1Tpt), B1Tpt)
)
}
- val rhs = methodBodyTyper.virtualizedMatch(match_, mode, B1.tpe)
- val defdef = DefDef(methodSym, Modifiers(methodSym.flags), originals, rhs)
+ def newParam(param: Symbol): ValDef = {
+ val vd = ValDef(param, EmptyTree)
+ val tt @ TypeTree() = vd.tpt
+ tt setOriginal (originals(param) setPos param.pos.focus)
+ vd
+ }
+
+ val rhs = methodBodyTyper.virtualizedMatch(match_, mode, B1.tpe)
+ val defdef = newDefDef(methodSym, rhs)(vparamss = mapParamss(methodSym)(newParam))
(defdef, matchResTp)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 5049fec65b..af19e3cf80 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -46,11 +46,8 @@ trait Unapplies extends ast.TreeDSL {
def copyUntyped[T <: Tree](tree: T): T =
returning[T](tree.duplicate)(UnTyper traverse _)
- def copyUntypedInvariant(td: TypeDef): TypeDef = {
- val copy = treeCopy.TypeDef(td, td.mods &~ (COVARIANT | CONTRAVARIANT), td.name, td.tparams, td.rhs)
-
- returning[TypeDef](copy.duplicate)(UnTyper traverse _)
- }
+ def copyUntypedInvariant(td: TypeDef): TypeDef =
+ copyTypeDef(copyUntyped(td))(mods = td.mods &~ (COVARIANT | CONTRAVARIANT))
private def toIdent(x: DefTree) = Ident(x.name) setPos x.pos.focus