@@ -26,7 +26,6 @@ object OrderingConstraint {
26
26
/** A new constraint with given maps */
27
27
private def newConstraint (boundsMap : ParamBounds , lowerMap : ParamOrdering , upperMap : ParamOrdering )(implicit ctx : Context ) : OrderingConstraint = {
28
28
val result = new OrderingConstraint (boundsMap, lowerMap, upperMap)
29
- if (Config .checkConstraintsNonCyclic) result.checkNonCyclic()
30
29
ctx.run.recordConstraintSize(result, result.boundsMap.size)
31
30
result
32
31
}
@@ -179,7 +178,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
179
178
180
179
def minUpper (param : TypeParamRef ): List [TypeParamRef ] = {
181
180
val all = upper(param)
182
- all.filterNot(p => all.exists(isLess(_, p)))
181
+ all// .filterNot(p => all.exists(isLess(_, p)))
183
182
}
184
183
185
184
def exclusiveLower (param : TypeParamRef , butNot : TypeParamRef ): List [TypeParamRef ] =
@@ -215,8 +214,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
215
214
def dependentParams (tp : Type , isUpper : Boolean ): List [TypeParamRef ] = tp match {
216
215
case param : TypeParamRef if contains(param) =>
217
216
param :: (if (isUpper) upper(param) else lower(param))
218
- case tp : AndType => dependentParams(tp.tp1, isUpper) | (dependentParams(tp.tp2, isUpper))
219
- case tp : OrType => dependentParams(tp.tp1, isUpper).intersect(dependentParams(tp.tp2, isUpper))
217
+ case tp : AndType if isUpper => dependentParams(tp.tp1, isUpper) | (dependentParams(tp.tp2, isUpper))
218
+ case tp : OrType if ! isUpper => dependentParams(tp.tp1, isUpper).intersect(dependentParams(tp.tp2, isUpper))
220
219
case _ =>
221
220
Nil
222
221
}
@@ -307,8 +306,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
307
306
hiBuf.clear()
308
307
i += 1
309
308
}
310
- if (Config .checkConstraintsNonCyclic) checkNonCyclic()
311
- current
309
+ current.checkNonCyclic()
312
310
}
313
311
314
312
// ---------- Updates ------------------------------------------------------------
@@ -329,9 +327,40 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
329
327
}
330
328
331
329
def addLess (param1 : TypeParamRef , param2 : TypeParamRef )(implicit ctx : Context ): This =
332
- order(this , param1, param2)
330
+ order(this , param1, param2).checkNonCyclic()
331
+
332
+ private def ensureNonCyclic (param : TypeParamRef , inst : Type )(using Context ): Type =
333
+
334
+ def recur (tp : Type , fromBelow : Boolean ): Type = tp match
335
+ case tp : AndOrType =>
336
+ val r1 = recur(tp.tp1, fromBelow)
337
+ val r2 = recur(tp.tp2, fromBelow)
338
+ if (r1 eq tp.tp1) && (r2 eq tp.tp2) then tp
339
+ else if tp.isAnd then r1 & r2
340
+ else r1 | r2
341
+ case tp : TypeParamRef =>
342
+ if tp eq param then
343
+ if fromBelow then defn.NothingType else defn.AnyType
344
+ else entry(tp) match
345
+ case NoType => tp
346
+ case TypeBounds (lo, hi) => if lo eq hi then recur(lo, fromBelow) else tp
347
+ case inst => recur(inst, fromBelow)
348
+ case tp : TypeVar if false => // TODO: needed?
349
+ val underlying1 = recur(tp.underlying, fromBelow)
350
+ if underlying1 ne tp.underlying then underlying1 else tp
351
+ case _ => tp
352
+
353
+ inst match
354
+ case bounds : TypeBounds =>
355
+ bounds.derivedTypeBounds(
356
+ recur(bounds.lo, fromBelow = true ),
357
+ recur(bounds.hi, fromBelow = false ))
358
+ case _ =>
359
+ inst
360
+ end ensureNonCyclic
333
361
334
- def updateEntry (current : This , param : TypeParamRef , tp : Type )(implicit ctx : Context ): This = {
362
+ private def updateEntry (current : This , param : TypeParamRef , tp : Type )(implicit ctx : Context ): This = {
363
+ val tp0 = tp
335
364
var current1 = boundsLens.update(this , current, param, tp)
336
365
tp match {
337
366
case TypeBounds (lo, hi) =>
@@ -345,11 +374,12 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
345
374
}
346
375
347
376
def updateEntry (param : TypeParamRef , tp : Type )(implicit ctx : Context ): This =
348
- updateEntry(this , param, tp)
377
+ updateEntry(this , param, tp).checkNonCyclic()
349
378
350
379
def unify (p1 : TypeParamRef , p2 : TypeParamRef )(implicit ctx : Context ): This = {
351
- val p1Bounds = (nonParamBounds(p1) & nonParamBounds(p2)).substParam(p2, p1)
352
- updateEntry(p1, p1Bounds).replace(p2, p1)
380
+ val p1Bounds = ensureNonCyclic(p1,
381
+ (nonParamBounds(p1) & nonParamBounds(p2)).substParam(p2, p1))
382
+ updateEntry(this , p1, p1Bounds).replace(p2, p1)
353
383
}
354
384
355
385
// ---------- Removals ------------------------------------------------------------
@@ -390,9 +420,24 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
390
420
def removeParam (ps : List [TypeParamRef ]) =
391
421
ps.filterNot(p => p.binder.eq(poly) && p.paramNum == idx)
392
422
423
+ var current =
424
+ if isRemovable(poly) then remove(poly) else updateEntry(this , param, replacement)
425
+ val current0 = current
426
+
427
+ var avoided = List [(Type , Type )]()
428
+
393
429
def replaceParam (tp : Type , atPoly : TypeLambda , atIdx : Int ): Type = tp match {
394
430
case bounds @ TypeBounds (lo, hi) =>
395
431
432
+ /*
433
+ tp.substParam(param, replacement) match
434
+ case bounds: TypeBounds =>
435
+ val finalized = current.avoidCycles(atPoly.paramRefs(atIdx), bounds)
436
+ if finalized ne bounds then avoided = ((bounds, finalized)) :: avoided
437
+ finalized
438
+ case tp => tp
439
+ current.avoidCycles() */
440
+
396
441
def recombineAnd (and : AndType , op : (Type , Boolean ) => Type , isUpper : Boolean ): Type = {
397
442
val tp1 = op(and.tp1, isUpper)
398
443
val tp2 = op(and.tp2, isUpper)
@@ -422,19 +467,26 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
422
467
case _ => tp.substParam(param, replacement)
423
468
}
424
469
425
- bounds.derivedTypeBounds(replaceIn(lo, isUpper = false ), replaceIn(hi, isUpper = true ))
470
+ val replaced = bounds.derivedTypeBounds(replaceIn(lo, isUpper = false ), replaceIn(hi, isUpper = true ))
471
+ val finalized = current.ensureNonCyclic(atPoly.paramRefs(atIdx), replaced)
472
+ // bounds.derivedTypeBounds(replaceIn(lo, isUpper = false), replaceIn(hi, isUpper = true)))
473
+ if finalized ne replaced then avoided = ((replaced, finalized)) :: avoided
474
+ finalized
426
475
case _ =>
427
476
tp.substParam(param, replacement)
428
477
}
429
478
430
- var current =
431
- if (isRemovable(poly)) remove(poly) else updateEntry(param, replacement)
432
- current.foreachParam {(p, i) =>
433
- current = boundsLens.map(this , current, p, i, replaceParam(_, p, i))
434
- current = lowerLens.map(this , current, p, i, removeParam)
435
- current = upperLens.map(this , current, p, i, removeParam)
436
- }
437
- current
479
+ try current.foreachParam { (p, i) =>
480
+ current = boundsLens.map(this , current, p, i, replaceParam(_, p, i))
481
+ current = lowerLens.map(this , current, p, i, removeParam)
482
+ current = upperLens.map(this , current, p, i, removeParam)
483
+ }
484
+ catch case ex : AssertionError =>
485
+ println(i " FAILED wen replacing $param := $tp in $this, initial = $current0" )
486
+ for (f, t) <- avoided do
487
+ println(i " avoided $f --> $t" )
488
+ throw ex
489
+ current.checkNonCyclic()
438
490
}
439
491
}
440
492
@@ -447,6 +499,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
447
499
po.remove(pt).mapValuesNow(removeFromBoundss)
448
500
}
449
501
newConstraint(boundsMap.remove(pt), removeFromOrdering(lowerMap), removeFromOrdering(upperMap))
502
+ .checkNonCyclic()
450
503
}
451
504
452
505
def isRemovable (pt : TypeLambda ): Boolean = {
@@ -566,7 +619,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
566
619
if (binder eq tl) tvar.setOrigin(tl1.paramRefs(n))
567
620
}
568
621
constr.println(i " renamd $this to $current" )
569
- current
622
+ current.checkNonCyclic()
570
623
}
571
624
572
625
def ensureFresh (tl : TypeLambda )(implicit ctx : Context ): TypeLambda =
@@ -614,11 +667,30 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
614
667
615
668
// ---------- Cyclic checking -------------------------------------------
616
669
617
- def checkNonCyclic ()(implicit ctx : Context ): Unit =
618
- domainParams.foreach(checkNonCyclic)
670
+ def checkNonCyclic ()(implicit ctx : Context ): this .type =
671
+ if Config .checkConstraintsNonCyclic then domainParams.foreach(checkNonCyclic)
672
+ this
619
673
620
674
private def checkNonCyclic (param : TypeParamRef )(implicit ctx : Context ): Unit =
621
- assert(! isLess(param, param), i " cyclic constraint involving $param in $this" )
675
+ assert(! isLess(param, param), i " cyclic ordering involving $param in $this, upper = ${upper(param)}" )
676
+
677
+ def recur (tp : Type )(using Context ): Unit = tp match
678
+ case tp : AndOrType =>
679
+ recur(tp.tp1)
680
+ recur(tp.tp2)
681
+ case tp : TypeParamRef =>
682
+ assert(tp ne param, i " cyclic bound for $param: ${entry(param)} in $this" )
683
+ entry(tp) match
684
+ case NoType =>
685
+ case TypeBounds (lo, hi) => if lo eq hi then recur(lo)
686
+ case inst => recur(inst)
687
+ case TypeBounds (lo, hi) =>
688
+ recur(lo)
689
+ recur(hi)
690
+ case _ =>
691
+
692
+ recur(entry(param))
693
+ end checkNonCyclic
622
694
623
695
// ---------- Invalidation -------------------------------------------
624
696
@@ -631,6 +703,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
631
703
// ---------- toText -----------------------------------------------------
632
704
633
705
override def toText (printer : Printer ): Text = {
706
+ // Printer.debugPrintUnique = true
634
707
def entryText (tp : Type ) = tp match {
635
708
case tp : TypeBounds =>
636
709
tp.toText(printer)
@@ -663,6 +736,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
663
736
Text (ups.map(_.toText(printer)), " , " )
664
737
Text (deps, " \n " )
665
738
}
739
+ // Printer.debugPrintUnique = false
666
740
Text .lines(List (header, uninstVarsText, constrainedText, boundsText, orderingText, " )" ))
667
741
}
668
742
0 commit comments