@@ -6,6 +6,7 @@ import Contexts._
66import config .PathResolver
77import dotty .tools .io ._
88import Phases ._
9+ import config .Printers .plugins .{ println => debug }
910
1011import scala .collection .mutable .ListBuffer
1112
@@ -144,56 +145,107 @@ object Plugins {
144145 * Note: this algorithm is factored out for unit test.
145146 */
146147 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 [_]])
149150
150151 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
155163 }
156164
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 [_]]]
160169
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 =>
168175
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))
174182 }
175183
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))
181187 }
188+
182189 }
183190
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+ }
185228
186229 var updatedPlan = plan
230+ var insertedPhase = primitivePhases
187231 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
191243
192244 // beforeReq met after the split
193245 val (before, after) = updatedPlan.span { ps =>
194246 val classes = ps.map(_.getClass)
195247 val runsAfterSat = runsAfter.isEmpty
196- runsAfter --= classes
248+ runsAfter = runsAfter -- classes
197249 // Prefer the point immediately before the first beforePhases.
198250 // If beforePhases not specified, insert at the point immediately
199251 // after the last afterPhases.
@@ -209,7 +261,7 @@ object Plugins {
209261 throw new Exception (s " Ordering conflict for phase ${phase.phaseName}" )
210262 }
211263
212- existingPhases += phase.getClass
264+ insertedPhase = insertedPhase + phase.getClass
213265 updatedPlan = before ++ (List (phase) :: after)
214266 }
215267
0 commit comments