aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Constraint.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-01-07 20:36:11 +0100
committerMartin Odersky <odersky@gmail.com>2014-01-07 20:36:11 +0100
commitf2d8f28b1eebfc52b61594bd6607faa581499f03 (patch)
tree21e4dd85bb63319c07b85593ce78a5afa0e5cd5e /src/dotty/tools/dotc/core/Constraint.scala
parent84cbb43bc3e4dc8399202763b371fda57ac3c072 (diff)
downloaddotty-f2d8f28b1eebfc52b61594bd6607faa581499f03.tar.gz
dotty-f2d8f28b1eebfc52b61594bd6607faa581499f03.tar.bz2
dotty-f2d8f28b1eebfc52b61594bd6607faa581499f03.zip
New subtype constraint maintenance algorithm.
Objective: Avoid cycles by detecting all cases where A <: B and B <: A and removing those cases by unifuing A and B. Cycles need to be avoided because they lead to deep subtype recursions.
Diffstat (limited to 'src/dotty/tools/dotc/core/Constraint.scala')
-rw-r--r--src/dotty/tools/dotc/core/Constraint.scala55
1 files changed, 26 insertions, 29 deletions
diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala
index a9fa8f0c6..8704a35d8 100644
--- a/src/dotty/tools/dotc/core/Constraint.scala
+++ b/src/dotty/tools/dotc/core/Constraint.scala
@@ -79,8 +79,8 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends AnyVal wit
val param = PolyParam(pt, i)
entry match {
case TypeBounds(lo, hi) =>
- assert(lo != param, param)
- assert(hi != param, param)
+ assert(!param.occursIn(lo, fromBelow = false), s"$param occurs above $lo")
+ assert(!param.occursIn(hi, fromBelow = true), s"$param occurs below $hi")
case _ =>
}
}
@@ -126,47 +126,44 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends AnyVal wit
noneLeft
}
+ /** Drop parameter `PolyParam(poly, n)` from `bounds`,
+ * replacing with Nothing in the lower bound and by `Any` in the upper bound.
+ */
+ def dropParamIn(bounds: TypeBounds, poly: PolyType, n: Int)(implicit ctx: Context): TypeBounds = {
+ def drop(tp: Type): Type = tp match {
+ case tp: AndOrType =>
+ val tp1 = drop(tp.tp1)
+ val tp2 = drop(tp.tp2)
+ if (!tp1.exists) tp2
+ else if (!tp2.exists) tp1
+ else tp
+ case PolyParam(`poly`, `n`) => NoType
+ case _ => tp
+ }
+ def approx(tp: Type, limit: Type): Type = {
+ val tp1 = drop(tp)
+ if (tp1.exists || !tp.exists) tp1 else limit
+ }
+ bounds.derivedTypeBounds(
+ approx(bounds.lo, defn.NothingType), approx(bounds.hi, defn.AnyType))
+ }
+
/** A new constraint which is derived from this constraint by removing
* the type parameter `param` from the domain and replacing all occurrences
* of the parameter elsewhere in the constraint by type `tp`.
*/
def replace(param: PolyParam, tp: Type)(implicit ctx: Context): Constraint = {
- /** Drop parameter `PolyParam(poly, n)` from bounds in type `tp` */
- def dropParamIn(tp: Type, poly: PolyType, n: Int, fromBelow: Boolean = false): Type = {
- def drop(tp: Type): Type = tp match {
- case tp: AndOrType =>
- val tp1 = drop(tp.tp1)
- val tp2 = drop(tp.tp2)
- if (!tp1.exists) tp2
- else if (!tp2.exists) tp1
- else tp
- case PolyParam(`poly`, `n`) => NoType
- case _ => tp
- }
- tp match {
- case tp: TypeBounds =>
- tp.derivedTypeBounds(
- dropParamIn(tp.lo, poly, n, !fromBelow),
- dropParamIn(tp.hi, poly, n, fromBelow))
- case _ =>
- val tp1 = drop(tp)
- if (tp1.exists || !tp.exists) tp1
- else if (fromBelow) defn.NothingType
- else defn.AnyType
- }
- }
-
def subst(poly: PolyType, entries: Array[Type]) = {
var result = entries
var i = 0
while (i < paramCount(entries)) {
entries(i) match {
case oldBounds: TypeBounds =>
- val newBounds = oldBounds.substParam(param, tp)
+ val newBounds = oldBounds.substParam(param, tp).asInstanceOf[TypeBounds]
if (oldBounds ne newBounds) {
if (result eq entries) result = entries.clone
- result(i) = dropParamIn(newBounds, poly, i, fromBelow = false)
+ result(i) = dropParamIn(newBounds, poly, i)
}
case _ =>
}