@@ -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