Skip to content

Commit 5d56fb7

Browse files
committed
refactor ordering algorithm for unit test
1 parent c80f36d commit 5d56fb7

File tree

5 files changed

+45
-24
lines changed

5 files changed

+45
-24
lines changed

compiler/src/dotty/tools/dotc/plugins/Plugin.scala

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,21 @@ trait Plugin {
3030
*/
3131
def research: Boolean = false
3232

33-
/** Handle any plugin-specific options.
34-
* The user writes `-P:plugname:opt1,opt2`,
35-
* but the plugin sees `List(opt1, opt2)`.
36-
*/
37-
def options(implicit ctx: Context): List[String] = {
38-
// Process plugin options of form plugin:option
39-
def namec = name + ":"
40-
ctx.settings.pluginOptions.value filter (_ startsWith namec) map (_ stripPrefix namec)
41-
}
4233

4334
/** Non-research plugins should override this method to return the phases
4435
*
36+
* @param options: commandline options to the plugin, `-P:plugname:opt1,opt2`
4537
* @return a list of phases to be added to the phase plan
4638
*/
47-
def init()(implicit ctx: Context): List[PluginPhase] = ???
39+
def init(options: List[String]): List[PluginPhase] = ???
4840

49-
/** Research plugins should override this method to return the new phase plan
50-
*
51-
* @return the new phase plan
52-
*/
53-
def init(phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = ???
41+
/** Research plugins should override this method to return the new phase plan
42+
*
43+
* @param options: commandline options to the plugin, `-P:plugname:opt1,opt2`
44+
* @param plan: the given phase plan
45+
* @return the new phase plan
46+
*/
47+
def init(options: List[String], plan: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = ???
5448

5549
/** A description of this plugin's options, suitable as a response
5650
* to the -help command-line option. Conventionally, the options

compiler/src/dotty/tools/dotc/plugins/Plugins.scala

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,30 @@ trait Plugins {
117117

118118
/** Add plugin phases to phase plan */
119119
def addPluginPhases(plan: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = {
120+
// plugin-specific options.
121+
// The user writes `-P:plugname:opt1,opt2`, but the plugin sees `List(opt1, opt2)`.
122+
def options(plugin: Plugin): List[String] = {
123+
def namec = plugin.name + ":"
124+
ctx.settings.pluginOptions.value filter (_ startsWith namec) map (_ stripPrefix namec)
125+
}
126+
127+
// schedule plugins according to ordering constraints
128+
val updatedPlan = Plugins.schedule(plan, plugins.filter(!_.research), options)
129+
130+
// add research plugins
131+
plugins.filter(_.research).foldRight(updatedPlan) { (plug, plan) => plug.init(options(plug), plan) }
132+
}
133+
}
134+
135+
object Plugins {
136+
/** Insert plugin phases in the right place of the phase plan
137+
*
138+
* The scheduling makes sure the ordering constraints of plugin phases are satisfied.
139+
* If the ordering constraints are unsatisfiable, an exception is thrown.
140+
*
141+
* Note: this algorithm is factored out for unit test.
142+
*/
143+
def schedule(plan: List[List[Phase]], plugins: List[Plugin], optionFn: Plugin => List[String]): List[List[Phase]] = {
120144
import scala.collection.mutable.{ Set => MSet, Map => MMap }
121145
type OrderingReq = (MSet[Class[_]], MSet[Class[_]])
122146

@@ -145,19 +169,23 @@ trait Plugins {
145169
}
146170
}
147171

148-
// add non-research plugins
149172
var updatedPlan = plan
150-
plugins.filter(!_.research).foreach { plug =>
151-
plug.init().foreach { phase =>
173+
plugins.foreach { plug =>
174+
plug.init(optionFn(plug)).foreach { phase =>
152175
updateOrdering(phase)
153176

154177
val beforePhases: MSet[Class[_]] = MSet(phase.runsBefore.toSeq: _*)
155178
val afterPhases: MSet[Class[_]] = MSet(phase.runsAfter.toSeq: _*)
156179

180+
// beforeReq met after the split
157181
val (before, after) = updatedPlan.span { ps =>
158182
val classes = ps.map(_.getClass)
159183
afterPhases --= classes
160-
!classes.exists(beforePhases.contains) // beforeReq satisfied
184+
// Prefer the point immediately before the first beforePhases.
185+
// If beforePhases not specified, insert at the point immediately
186+
// after the last afterPhases.
187+
!classes.exists(beforePhases.contains) &&
188+
!(beforePhases.isEmpty && afterPhases.isEmpty)
161189
}
162190

163191
// check afterReq
@@ -172,7 +200,6 @@ trait Plugins {
172200
}
173201
}
174202

175-
// add research plugins
176-
ctx.plugins.filter(_.research).foldRight(updatedPlan) { (plug, plan) => plug.init(plan) }
203+
updatedPlan
177204
}
178205
}

tests/plugins/neg/divideZero-research/plugin_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class DivideZero extends MiniPhase with Plugin {
1717

1818
val phaseName = name
1919

20-
override def init(phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = {
20+
override def init(options: List[String], phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = {
2121
val (before, after) = phases.span(ps => !ps.exists(_.phaseName == "pickler"))
2222
before ++ (List(this) :: after)
2323
}

tests/plugins/neg/divideZero/plugin_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class DivideZero extends PluginPhase with Plugin {
1919
override val runsAfter = Set(classOf[Pickler])
2020
override val runsBefore = Set(classOf[LinkAll])
2121

22-
override def init()(implicit ctx: Context): List[PluginPhase] = this :: Nil
22+
override def init(options: List[String]): List[PluginPhase] = this :: Nil
2323

2424
private def isNumericDivide(sym: Symbol)(implicit ctx: Context): Boolean = {
2525
def test(tpe: String): Boolean =

tests/plugins/pos/divideZero/plugin_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class DivideZero extends MiniPhase with Plugin {
1717

1818
override val research = true
1919

20-
override def init(phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = {
20+
override def init(options: List[String], phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = {
2121
val (before, after) = phases.span(ps => !ps.exists(_.phaseName == "pickler"))
2222
before ++ (List(this) :: after)
2323
}

0 commit comments

Comments
 (0)