diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/PhaseAssembly.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/PhaseAssembly.scala | 90 |
1 files changed, 35 insertions, 55 deletions
diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index ae71eb7255..c962cc8bb7 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"Phase ${sanity.head.to.phasename} has too many 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 - */ + + /** Called by Global#computePhaseDescriptors to compute phase order. */ def buildCompilerFromPhasesSet(): 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 } - } |