@@ -6,6 +6,7 @@ import Contexts._
6
6
import config.PathResolver
7
7
import dotty.tools.io._
8
8
import Phases._
9
+ import config.Printers.plugins.{ println => debug }
9
10
10
11
import scala.collection.mutable.ListBuffer
11
12
@@ -144,56 +145,107 @@ object Plugins {
144
145
* Note: this algorithm is factored out for unit test.
145
146
*/
146
147
def schedule(plan: List[List[Phase]], pluginPhases: List[PluginPhase]): List[List[Phase]] = {
147
- import scala.collection.mutable.{ Set => MSet, Map => MMap }
148
- type OrderingReq = (MSet [Class[_]], MSet [Class[_]])
148
+ import scala.collection.mutable.{ Map => MMap, Set => MSet }
149
+ type OrderingReq = (Set [Class[_]], Set [Class[_]])
149
150
150
151
val orderRequirements = MMap[Class[_], OrderingReq]()
151
- val existingPhases = {
152
- val set = MSet.empty[Class[_]]
153
- for (ps <- plan; p <- ps) set += p.getClass
154
- set
152
+ val primitivePhases = plan.flatMap(ps => ps.map(_.getClass.asInstanceOf[Class[_]])).toSet
153
+
154
+ def isPrimitive(phase: Class[_]): Boolean = primitivePhases.contains(phase)
155
+
156
+ def constraintConflict(phase: Phase): String = {
157
+ val (runsAfter, runsBefore) = orderRequirements(phase.getClass)
158
+ s"""
159
+ |Ordering conflict for phase ${phase.phaseName}
160
+ |after: ${runsAfter.mkString("[", ", ", "]")}
161
+ |before: ${runsBefore.mkString("[", ", ", "]")}
162
+ """.stripMargin
155
163
}
156
164
157
- def updateOrdering(phase: PluginPhase): Unit = {
158
- val runsBefore: MSet[Class[_]] = MSet(phase.runsBefore.toSeq: _*)
159
- val runsAfter: MSet[Class[_]] = MSet(phase.runsAfter.toSeq: _*)
165
+ // init ordering map, no propagation
166
+ pluginPhases.foreach { phase =>
167
+ val runsAfter : Set[Class[_]] = phase.runsAfter.asInstanceOf[Set[Class[_]]]
168
+ val runsBefore : Set[Class[_]] = phase.runsBefore.asInstanceOf[Set[Class[_]]]
160
169
161
- if (!orderRequirements.contains(phase.getClass)) {
162
- orderRequirements.update(phase.getClass, (runsBefore, runsAfter) )
163
- } else {
164
- val (runsBefore1, runsAfter1) = orderRequirements(phase.getClass)
165
- runsAfter1 ++= runsAfter
166
- runsBefore1 ++= runsBefore
167
- }
170
+ orderRequirements.update(phase.getClass, (runsAfter, runsBefore))
171
+ }
172
+
173
+ // propagate ordering constraint : reflexivity
174
+ pluginPhases.foreach { phase =>
168
175
169
- runsBefore.foreach { phaseClass =>
170
- if (!orderRequirements.contains(phaseClass))
171
- orderRequirements.update(phaseClass, (MSet.empty, MSet.empty))
172
- val (_, runsAfter) = orderRequirements(phaseClass)
173
- runsAfter += phase.getClass
176
+ var (runsAfter, runsBefore) = orderRequirements(phase.getClass)
177
+
178
+ // propagate transitive constraints to related phases
179
+ runsAfter.filter(!isPrimitive(_)).foreach { phaseClass =>
180
+ val (runsAfter1, runsBefore1) = orderRequirements(phaseClass)
181
+ orderRequirements.update(phaseClass, (runsAfter1, runsBefore1 + phase.getClass))
174
182
}
175
183
176
- runsAfter.foreach { phaseClass =>
177
- if (!orderRequirements.contains(phaseClass))
178
- orderRequirements.update(phaseClass, (MSet.empty, MSet.empty))
179
- val (runsBefore, _) = orderRequirements(phaseClass)
180
- runsBefore += phase.getClass
184
+ runsBefore.filter(!isPrimitive(_)).foreach { phaseClass =>
185
+ val (runsAfter1, runsBefore1) = orderRequirements(phaseClass)
186
+ orderRequirements.update(phaseClass, (runsAfter1 + phase.getClass, runsBefore1))
181
187
}
188
+
182
189
}
183
190
184
- pluginPhases.foreach(updateOrdering)
191
+ debug(
192
+ s""" reflexive constraints:
193
+ | ${orderRequirements.mkString("\n")}
194
+ """.stripMargin
195
+ )
196
+
197
+ // propagate transitive constraints from related phases to current phase: transitivity
198
+ def propagate(phase: Phase): OrderingReq = {
199
+ def propagateRunsBefore(beforePhase: Class[_]): Set[Class[_]] =
200
+ if (beforePhase == phase.getClass)
201
+ throw new Exception(constraintConflict(phase))
202
+ else if (primitivePhases.contains(beforePhase))
203
+ Set(beforePhase)
204
+ else {
205
+ val (_, runsBefore) = orderRequirements(beforePhase)
206
+ runsBefore.flatMap(propagateRunsBefore) + beforePhase
207
+ }
208
+
209
+ def propagateRunsAfter(afterPhase: Class[_]): Set[Class[_]] =
210
+ if (afterPhase == phase.getClass)
211
+ throw new Exception(constraintConflict(phase))
212
+ else if (primitivePhases.contains(afterPhase))
213
+ Set(afterPhase)
214
+ else {
215
+ val (runsAfter, _) = orderRequirements(afterPhase)
216
+ runsAfter.flatMap(propagateRunsAfter) + afterPhase
217
+ }
218
+
219
+ var (runsAfter, runsBefore) = orderRequirements(phase.getClass)
220
+
221
+ runsAfter = runsAfter.flatMap(propagateRunsAfter)
222
+ runsBefore = runsBefore.flatMap(propagateRunsBefore)
223
+
224
+ // orderRequirements.update(phase.getClass, (runsBefore, runsAfter) )
225
+
226
+ (runsAfter, runsBefore)
227
+ }
185
228
186
229
var updatedPlan = plan
230
+ var insertedPhase = primitivePhases
187
231
pluginPhases.sortBy(_.phaseName).foreach { phase =>
188
- val (runsBefore1, runsAfter1) = orderRequirements(phase.getClass)
189
- val runsBefore = runsBefore1 & existingPhases
190
- val runsAfter = runsAfter1 & existingPhases
232
+ var (runsAfter1, runsBefore1) = propagate(phase)
233
+
234
+ debug(
235
+ s"""propagated constraints for ${phase}:
236
+ |after: ${runsAfter1.mkString("[", ", ", "]")}
237
+ |before: ${runsBefore1.mkString("[", ", ", "]")}
238
+ """.stripMargin
239
+ )
240
+
241
+ var runsAfter = runsAfter1 & insertedPhase
242
+ val runsBefore = runsBefore1 & insertedPhase
191
243
192
244
// beforeReq met after the split
193
245
val (before, after) = updatedPlan.span { ps =>
194
246
val classes = ps.map(_.getClass)
195
247
val runsAfterSat = runsAfter.isEmpty
196
- runsAfter --= classes
248
+ runsAfter = runsAfter -- classes
197
249
// Prefer the point immediately before the first beforePhases.
198
250
// If beforePhases not specified, insert at the point immediately
199
251
// after the last afterPhases.
@@ -209,7 +261,7 @@ object Plugins {
209
261
throw new Exception(s"Ordering conflict for phase ${phase.phaseName}")
210
262
}
211
263
212
- existingPhases += phase.getClass
264
+ insertedPhase = insertedPhase + phase.getClass
213
265
updatedPlan = before ++ (List(phase) :: after)
214
266
}
215
267
0 commit comments