aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/Constraint.scala10
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala8
-rw-r--r--src/dotty/tools/dotc/core/NaiveConstraint.scala41
-rw-r--r--src/dotty/tools/dotc/core/TrackingConstraint.scala517
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala4
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala2
6 files changed, 550 insertions, 32 deletions
diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala
index a5c55ccce..f7e7a2e13 100644
--- a/src/dotty/tools/dotc/core/Constraint.scala
+++ b/src/dotty/tools/dotc/core/Constraint.scala
@@ -34,7 +34,7 @@ abstract class Constraint extends Showable {
/** The constraint for given type parameter `param`, or NoType if `param` is not part of
* the constraint domain.
*/
- def at(param: PolyParam): Type
+ def at(param: PolyParam)(implicit ctx: Context): Type
/** The type variable corresponding to parameter `param`, or
* NoType, if `param` is not in constrained or is not paired with a type variable.
@@ -44,7 +44,7 @@ abstract class Constraint extends Showable {
/** The constraint bounds for given type parameter `param`.
* @pre `param` is not part of the constraint domain.
*/
- def bounds(param: PolyParam): TypeBounds
+ def bounds(param: PolyParam)(implicit ctx: Context): TypeBounds
/** The non-parameter bounds of this constraint.
* Poly params that are `related` are not contained in the return bounds.
@@ -76,10 +76,10 @@ abstract class Constraint extends Showable {
*/
def updated(param: PolyParam, tp: Type)(implicit ctx: Context): This
- /** A constraint that includes a the relationship `bound <: param` if `fromBelow` is true
- * or else `param <: bound` if `fromBelow` is false.
+ /** A constraint that includes a the relationship `param <: bound` if `inOrder` is true
+ * or else `bound <: param` if `inOrdxer` is false.
*/
- def order(param: PolyParam, bound: PolyParam, fromBelow: Boolean)(implicit ctx: Context): This
+ def order(param: PolyParam, bound: PolyParam, inOrder: Boolean)(implicit ctx: Context): This
/** A new constraint which is derived from this constraint by removing
* the type parameter `param` from the domain and replacing all occurrences
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 264cff012..2aa2a4acd 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -146,7 +146,13 @@ trait ConstraintHandling {
/** Install bounds for param */
def install(param: PolyParam, newBounds: TypeBounds, oldBounds: TypeBounds): Unit = {
val curBounds = constraint.bounds(param)
- constraint = constraint.updated(param, newBounds)
+ try {
+ constraint = constraint.updated(param, newBounds)
+ } catch {
+ case ex: AssertionError =>
+ println(i"error while updating $param $newBounds\n$constraint")
+ throw ex
+ }
if (curBounds ne oldBounds) {
// In this case the bounds were updated previously by a recursive isSubType in
// the satisfiability check of prepare. Reapply the previously added bounds, but
diff --git a/src/dotty/tools/dotc/core/NaiveConstraint.scala b/src/dotty/tools/dotc/core/NaiveConstraint.scala
index f79a7d05f..ae5d5b0f1 100644
--- a/src/dotty/tools/dotc/core/NaiveConstraint.scala
+++ b/src/dotty/tools/dotc/core/NaiveConstraint.scala
@@ -99,12 +99,17 @@ class NaiveConstraint(private val myMap: ParamInfo) extends Constraint {
private def isBounds(tp: Type) = tp.isInstanceOf[TypeBounds]
- def at(param: PolyParam): Type = {
+ def at(param: PolyParam)(implicit ctx: Context): Type = {
+ val entries = myMap(param.binder)
+ if (entries == null) NoType else entries(param.paramNum)
+ }
+
+ def entry(param: PolyParam) = {
val entries = myMap(param.binder)
if (entries == null) NoType else entries(param.paramNum)
}
- def bounds(param: PolyParam): TypeBounds = at(param).asInstanceOf[TypeBounds]
+ def bounds(param: PolyParam)(implicit ctx: Context): TypeBounds = at(param).asInstanceOf[TypeBounds]
def nonParamBounds(param: PolyParam)(implicit ctx: Context): TypeBounds = {
val bs @ TypeBounds(lo, hi) = bounds(param)
@@ -113,11 +118,11 @@ class NaiveConstraint(private val myMap: ParamInfo) extends Constraint {
bs.derivedTypeBounds(lo1.orElse(defn.NothingType), hi1.orElse(defn.AnyType))
}
- def related(param1: PolyParam, param2: PolyParam, firstIsLower: Boolean)(implicit ctx: Context): Boolean = {
+ def related(param1: PolyParam, param2: PolyParam, inOrder: Boolean)(implicit ctx: Context): Boolean = {
var isRelated = false
def registerParam(p: PolyParam) = if (p == param2) isRelated = true
val TypeBounds(lo, hi) = bounds(param1)
- if (firstIsLower) splitParams(hi, seenFromBelow = true, registerParam)
+ if (inOrder) splitParams(hi, seenFromBelow = true, registerParam)
else splitParams(lo, seenFromBelow = false, registerParam)
isRelated
}
@@ -202,13 +207,13 @@ class NaiveConstraint(private val myMap: ParamInfo) extends Constraint {
updateEntries(param.binder, newEntries)
}
- def order(param: PolyParam, bound: PolyParam, fromBelow: Boolean)(implicit ctx: Context): This =
- if (related(param, bound, firstIsLower = !fromBelow)) this
+ def order(param: PolyParam, bound: PolyParam, inOrder: Boolean)(implicit ctx: Context): This =
+ if (related(param, bound, inOrder)) this
else {
val oldBounds = bounds(param)
val newBounds =
- if (fromBelow) TypeBounds(OrType(oldBounds.lo, bound), oldBounds.hi)
- else TypeBounds(oldBounds.lo, AndType(oldBounds.hi, bound))
+ if (inOrder) TypeBounds(oldBounds.lo, AndType(oldBounds.hi, bound))
+ else TypeBounds(OrType(oldBounds.lo, bound), oldBounds.hi)
updated(param, newBounds)
}
@@ -285,20 +290,10 @@ class NaiveConstraint(private val myMap: ParamInfo) extends Constraint {
result
}
- def replace(param: PolyParam, tp: Type)(implicit ctx: Context): This =
- tp.dealias.stripTypeVar match {
- case tp: PolyParam if this contains tp =>
- val bs = bounds(tp)
- if (tp == param)
- this
- else if (param.occursIn(bs.lo, fromBelow = true) ||
- param.occursIn(bs.hi, fromBelow = false))
- unify(tp, param).uncheckedReplace(param, tp)
- else
- uncheckedReplace(param, tp)
- case _ =>
- uncheckedReplace(param, tp)
- }
+ def replace(param: PolyParam, tp: Type)(implicit ctx: Context): This = {
+ val tp1 = tp.dealias.stripTypeVar
+ if (param == tp1) this else uncheckedReplace(param, tp1)
+ }
def unify(p1: PolyParam, p2: PolyParam)(implicit ctx: Context): This = {
val p1Bounds =
@@ -366,7 +361,7 @@ class NaiveConstraint(private val myMap: ParamInfo) extends Constraint {
def constraintText(indent: Int, printer: Printer): Text = {
val assocs =
for (param <- domainParams)
- yield (" " * indent) ~ param.toText(printer) ~ at(param).toText(printer)
+ yield (" " * indent) ~ param.toText(printer) ~ entry(param).toText(printer)
Text(assocs, "\n")
}
diff --git a/src/dotty/tools/dotc/core/TrackingConstraint.scala b/src/dotty/tools/dotc/core/TrackingConstraint.scala
new file mode 100644
index 000000000..6e9ef5a2b
--- /dev/null
+++ b/src/dotty/tools/dotc/core/TrackingConstraint.scala
@@ -0,0 +1,517 @@
+package dotty.tools
+package dotc
+package core
+
+import Types._, Contexts._, Symbols._, Decorators._
+import util.SimpleMap
+import collection.mutable
+import printing.{Printer, Showable}
+import printing.Texts._
+import config.Config
+import config.Printers._
+import collection.immutable.BitSet
+import reflect.ClassTag
+
+object TrackingConstraint {
+
+ /** The type of `Constraint#myMap` */
+ type ParamInfo = SimpleMap[PolyType, Array[Type]]
+
+}
+
+import TrackingConstraint._
+
+/** Constraint over undetermined type parameters
+ * @param myMap a map from PolyType to arrays.
+ * Each array contains twice the number of entries as there a type parameters
+ * in the PolyType. The first half of the array contains the type bounds that constrain the
+ * polytype's type parameters. The second half might contain type variables that
+ * track the corresponding parameters, or is left empty (filled with nulls).
+ * An instantiated type parameter is represented by having its instance type in
+ * the corresponding array entry.
+ */
+class TrackingConstraint(private val myMap: ParamInfo,
+ private val less: Array[BitSet],
+ private val params: Array[PolyParam]) extends Constraint {
+
+ type This = TrackingConstraint
+
+ assert(less.length == params.length)
+
+ /** A new constraint which is derived from this constraint by adding or replacing
+ * the entries corresponding to `pt` with `entries`.
+ */
+ private def newConstraint(myMap: ParamInfo, less: Array[BitSet], params: Array[PolyParam])(implicit ctx: Context) : TrackingConstraint = {
+ val result = new TrackingConstraint(myMap, less, params)
+ if (Config.checkConstraintsNonCyclic) result.checkNonCyclic()
+ ctx.runInfo.recordConstraintSize(result, result.myMap.size)
+ result
+ }
+
+// ----------- Basic indices --------------------------------------------------
+
+ /** The immutable array of constrained polytypes */
+ private val polyTypes = new Array[PolyType](myMap.size)
+
+ /** The start positions of parameters of constrained polytypes in `params` and `less` */
+ private val polyStart = new Array[Int](myMap.size)
+
+ {
+ var idx = 0
+ var count = 0
+ myMap.foreachBinding { (pt, _) =>
+ polyTypes(idx) = pt
+ polyStart(idx) = count
+ count += pt.paramNames.length
+ idx += 1
+ }
+ assert(count == params.length)
+ }
+
+ /** The index of given polytype `pt` in this constraint,
+ * or `polyTypes.length` if constraint does not contain `pt`.
+ */
+ private def polyIndex(pt: PolyType): Int = {
+ var i = 0
+ while (i < polyTypes.length && (polyTypes(i) ne pt)) i += 1
+ i
+ }
+
+ /** The index of the first parameter of given polytype `pt` in this constraint */
+ private def polyStart(pt: PolyType): Int = this.polyStart.apply(polyIndex(pt))
+
+ /** The index of `param` in `params` and `less` */
+ private def paramIndex(param: PolyParam): Int = {
+ assert(contains(param.binder))
+ polyStart(param.binder) + param.paramNum
+ }
+
+ /** The number of type parameters in the given entry array */
+ private def paramCount(entries: Array[Type]) = entries.length >> 1
+
+ /** The type variable corresponding to parameter numbered `n`, null if none was created */
+ private def typeVar(entries: Array[Type], n: Int): Type =
+ entries(paramCount(entries) + n)
+
+ private def entry(param: PolyParam): Type = {
+ val entries = myMap(param.binder)
+ if (entries == null) NoType
+ else entries(param.paramNum)
+ }
+
+// ----------- Contains tests --------------------------------------------------
+
+ def contains(pt: PolyType): Boolean = polyIndex(pt) < polyTypes.length
+
+ def contains(param: PolyParam): Boolean = {
+ val entries = myMap(param.binder)
+ entries != null && entries(param.paramNum).isInstanceOf[TypeBounds]
+ }
+
+ def contains(tvar: TypeVar): Boolean = {
+ val origin = tvar.origin
+ val entries = myMap(origin.binder)
+ val pnum = origin.paramNum
+ entries != null && isBounds(entries(pnum)) && (typeVar(entries, pnum) eq tvar)
+ }
+
+ private def isBounds(tp: Type) = tp.isInstanceOf[TypeBounds]
+
+// ---------- Dependency handling ----------------------------------------------
+
+ private def upperBits(i: Int): BitSet = less(i)
+
+ private def lowerBits(i: Int): BitSet =
+ (BitSet() /: less.indices) ((bits, j) => if (less(i)(j)) bits + j else bits)
+
+ private def minUpperBits(i: Int): BitSet = {
+ val all = upperBits(i)
+ all.filterNot(j => all.exists(k => less(k)(j)))
+ }
+
+ private def minLowerBits(i: Int): BitSet = {
+ val all = lowerBits(i)
+ all.filterNot(j => all.exists(k => less(j)(k)))
+ }
+
+ private def overParams(op: Int => BitSet): PolyParam => List[PolyParam] = param =>
+ op(paramIndex(param)).toList.map(params).filter(contains)
+
+ val upper = overParams(upperBits)
+ val lower = overParams(lowerBits)
+ val minUpper = overParams(minUpperBits)
+ val minLower = overParams(minLowerBits)
+
+
+// ---------- Info related to PolyParams -------------------------------------------
+
+ def related(param1: PolyParam, param2: PolyParam, firstIsLower: Boolean)(implicit ctx: Context): Boolean = {
+ val i1 = paramIndex(param1)
+ val i2 = paramIndex(param2)
+ if (firstIsLower) less(i1)(i2) else less(i2)(i1)
+ }
+
+ def nonParamBounds(param: PolyParam)(implicit ctx: Context): TypeBounds =
+ entry(param).asInstanceOf[TypeBounds]
+
+ def bounds(param: PolyParam)(implicit ctx: Context): TypeBounds = {
+ val bounds @ TypeBounds(lo, hi) = nonParamBounds(param)
+ bounds.derivedTypeBounds(
+ (lo /: minLower(param))(OrType.apply),
+ (hi /: minUpper(param))(AndType.apply))
+ }
+
+ def at(param: PolyParam)(implicit ctx: Context): Type = {
+ entry(param) match {
+ case _: TypeBounds => bounds(param)
+ case e => e
+ }
+ }
+
+ def typeVarOfParam(param: PolyParam): Type = {
+ val entries = myMap(param.binder)
+ if (entries == null) NoType
+ else {
+ val tvar = typeVar(entries, param.paramNum)
+ if (tvar != null) tvar else NoType
+ }
+ }
+
+// ---------- Type splitting --------------------------------------------------
+
+ /** The set of "dependent" constrained parameters that unconditionally strengthen bound `tp`.
+ * @param seenFromBelow If true, `bound` is an upper bound, else a lower bound.
+ */
+ private def depParams(tp: Type, seenFromBelow: Boolean): Set[PolyParam] = tp match {
+ case tp: PolyParam if contains(tp) =>
+ Set(tp)
+ case tp: AndOrType if seenFromBelow == tp.isAnd =>
+ depParams(tp.tp1, seenFromBelow) | depParams(tp.tp2, seenFromBelow)
+ case _ =>
+ Set.empty
+ }
+
+ /** The bound type `tp` without dependent parameters.
+ * NoType if type consists only of dependent parameters.
+ * @param seenFromBelow If true, `bound` is an upper bound, else a lower bound.
+ */
+ private def stripParams(tp: Type, seenFromBelow: Boolean)(implicit ctx: Context): Type = tp match {
+ case tp: PolyParam if contains(tp) =>
+ NoType
+ case tp: AndOrType if seenFromBelow == tp.isAnd =>
+ val tp1 = nonParamType(tp.tp1, seenFromBelow)
+ val tp2 = nonParamType(tp.tp2, seenFromBelow)
+ if (tp1.exists)
+ if (tp2.exists) tp.derivedAndOrType(tp1, tp2)
+ else tp1
+ else tp2
+ case _ =>
+ tp
+ }
+
+ /** The bound type `tp` without dependent parameters.
+ * A top or bottom type if type consists only of dependent parameters.
+ * @param seenFromBelow If true, `bound` is an upper bound, else a lower bound.
+ */
+ private def nonParamType(tp: Type, seenFromBelow: Boolean)(implicit ctx: Context): Type =
+ stripParams(tp, seenFromBelow).orElse(if (seenFromBelow) defn.AnyType else defn.NothingType)
+
+ /** The `tp1 is a TypeBounds type, the bounds without dependent parameters,
+ * otherwise `tp`.
+ */
+ private def nonParamType(tp: Type)(implicit ctx: Context): Type = tp match {
+ case tp @ TypeBounds(lo, hi) =>
+ tp.derivedTypeBounds(
+ nonParamType(lo, seenFromBelow = false),
+ nonParamType(hi, seenFromBelow = true))
+ case _ =>
+ tp
+ }
+
+ /** An updated partial order matrix that incorporates `less` and also reflects the new `bounds`
+ * for parameter `param`.
+ */
+ private def updatedLess(less: Array[BitSet], param: PolyParam, bounds: Type): Array[BitSet] = bounds match {
+ case TypeBounds(lo, hi) =>
+ updatedLess(
+ updatedLess(less, param, lo, seenFromBelow = false),
+ param, hi, seenFromBelow = true)
+ case _ =>
+ less
+ }
+
+ /** An updated partial order matrix that incorporates `less` and also reflects that `param` has a new
+ * `bound`, where `seenFromBelow` is true iff `bound` is an upper bound for `param`.
+ */
+ def updatedLess(less: Array[BitSet], param: PolyParam, bound: Type, seenFromBelow: Boolean): Array[BitSet] =
+ updatedLess(less, param, depParams(bound, seenFromBelow).iterator, inOrder = seenFromBelow)
+
+ /** An updated partial order matrix that incorporates `less` and also reflects that `param` relates
+ * to all parameters in `ps2` wrt <:< if `inOrder` is true, `>:>` otherwise.
+ */
+ def updatedLess(less: Array[BitSet], p1: PolyParam, ps2: Iterator[PolyParam], inOrder: Boolean): Array[BitSet] =
+ if (ps2.hasNext) updatedLess(updatedLess(less, p1, ps2.next, inOrder), p1, ps2, inOrder)
+ else less
+
+ /** An updated partial order matrix that incorporates `less` and also reflects that `param` relates
+ * to `p2` wrt <:< if `inOrder` is true, `>:>` otherwise.
+ */
+ def updatedLess(less: Array[BitSet], p1: PolyParam, p2: PolyParam, inOrder: Boolean): Array[BitSet] =
+ if (!inOrder) updatedLess(less, p2, p1, true)
+ else {
+ val i1 = paramIndex(p1)
+ val i2 = paramIndex(p2)
+ if (i1 == i2 || less(i1)(i2)) less
+ else {
+ val result = less.clone
+ result(i1) = result(i1) + i2 | upperBits(i2)
+ assert(!result(i1)(i1))
+ for (j <- lowerBits(i1)) {
+ result(j) = result(j) + i2 | upperBits(i2)
+ assert(!result(j)(j))
+ }
+ result
+ }
+ }
+
+// ---------- Updates ------------------------------------------------------------
+
+ def order(param: PolyParam, bound: PolyParam, inOrder: Boolean)(implicit ctx: Context): This = {
+ val less1 = updatedLess(less, param, bound, inOrder)
+ if (less1 eq less) this else newConstraint(myMap, less1, params)
+ }
+
+ def nonParamUpdated(param: PolyParam, tpe: Type)(implicit ctx: Context): This = {
+ val entries1 = myMap(param.binder).clone
+ entries1(param.paramNum) = tpe
+ newConstraint(myMap.updated(param.binder, entries1), less, params)
+ }
+
+ def updated(param: PolyParam, tpe: Type)(implicit ctx: Context): This = {
+ val less1 = updatedLess(less, param, tpe)
+ val entries = myMap(param.binder)
+ val entry1 = nonParamType(tpe)
+ val idx = param.paramNum
+ val entries1 =
+ if (entry1 eq entries(idx)) entries
+ else {
+ val entries1 = entries.clone
+ entries1(idx) = entry1
+ entries1
+ }
+ newConstraint(myMap.updated(param.binder, entries1), less1, params)
+ }
+
+ /** Drop parameter `PolyParam(poly, n)` from `bounds`,
+ * replacing with Nothing in the lower bound and by `Any` in the upper bound.
+ */
+ private 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): TrackingConstraint = {
+ val replacement = tp.dealias.stripTypeVar
+
+ 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, replacement).asInstanceOf[TypeBounds]
+ if (oldBounds ne newBounds) {
+ if (result eq entries) result = entries.clone
+ result(i) = dropParamIn(newBounds, poly, i)
+ }
+ case _ =>
+ }
+ i += 1
+ }
+ result
+ }
+
+ if (param == replacement) this
+ else {
+ val pt = param.binder
+ val constr1 = if (isRemovable(pt, param.paramNum)) remove(pt) else updated(param, replacement)
+ val result = new TrackingConstraint(constr1.myMap mapValues subst, constr1.less, constr1.params)
+ if (Config.checkConstraintsNonCyclic) result.checkNonCyclic()
+ result
+ }
+ }
+
+ def unify(p1: PolyParam, p2: PolyParam)(implicit ctx: Context): This = {
+ val p1Bounds =
+ dropParamIn(nonParamBounds(p1), p2.binder, p2.paramNum) &
+ dropParamIn(nonParamBounds(p2), p1.binder, p1.paramNum)
+ this.nonParamUpdated(p1, p1Bounds).nonParamUpdated(p2, p1)
+ }
+
+ def add(poly: PolyType, tvars: List[TypeVar])(implicit ctx: Context): This = {
+ assert(!contains(poly))
+ val nparams = poly.paramNames.length
+ val entries1 = new Array[Type](nparams * 2)
+ poly.paramBounds.copyToArray(entries1, 0)
+ tvars.copyToArray(entries1, nparams)
+ val is = poly.paramBounds.indices
+ val newParams = is.map(PolyParam(poly, _))
+ val params1 = params ++ newParams
+ var less1 = less ++ is.map(Function.const(BitSet.empty))
+ for (i <- is) {
+ less1 = updatedLess(less1, newParams(i), entries1(i))
+ entries1(i) = nonParamType(entries1(i))
+ }
+ newConstraint(myMap.updated(poly, entries1), less1, params1)
+ }
+
+ /** A new constraint with all entries coming from `pt` removed. */
+ def remove(pt: PolyType)(implicit ctx: Context): This = {
+ val start = polyStart(pt)
+ val skipped = pt.paramNames.length
+
+ def shrinkSet(bits: BitSet): BitSet =
+ (BitSet() /: bits) ((res, i) =>
+ if (i < start) res + i
+ else if (i < start + skipped) res
+ else res + (i - skipped))
+ def shrinkArray[T: ClassTag](src: Array[T]) = {
+ val dst = new Array[T](src.length - skipped)
+ Array.copy(src, 0, dst, 0, start)
+ Array.copy(src, start + skipped, dst, start, dst.length - start)
+ dst
+ }
+ newConstraint(
+ myMap = myMap remove pt,
+ less = shrinkArray(less).map(shrinkSet(_)),
+ params = shrinkArray(params))
+ }
+
+ def isRemovable(pt: PolyType, removedParam: Int = -1): Boolean = {
+ val entries = myMap(pt)
+ var noneLeft = true
+ var i = paramCount(entries)
+ while (noneLeft && i > 0) {
+ i -= 1
+ if (i != removedParam && isBounds(entries(i))) noneLeft = false
+ else typeVar(entries, i) match {
+ case tv: TypeVar =>
+ if (!tv.inst.exists) noneLeft = false // need to keep line around to compute instType
+ case _ =>
+ }
+ }
+ noneLeft
+ }
+
+// ---------- Exploration --------------------------------------------------------
+
+ def domainPolys: List[PolyType] = polyTypes.toList
+
+ def domainParams: List[PolyParam] = params.toList
+
+ def forallParams(p: PolyParam => Boolean): Boolean = {
+ myMap.foreachBinding { (poly, entries) =>
+ for (i <- 0 until paramCount(entries))
+ if (isBounds(entries(i)) && !p(PolyParam(poly, i))) return false
+ }
+ true
+ }
+
+ def foreachTypeVar(op: TypeVar => Unit): Unit =
+ myMap.foreachBinding { (poly, entries) =>
+ for (i <- 0 until paramCount(entries)) {
+ typeVar(entries, i) match {
+ case tv: TypeVar if !tv.inst.exists => op(tv)
+ case _ =>
+ }
+ }
+ }
+
+ private var myUninstVars: mutable.ArrayBuffer[TypeVar] = _
+
+ /** The uninstantiated typevars of this constraint */
+ def uninstVars: collection.Seq[TypeVar] = {
+ if (myUninstVars == null) {
+ myUninstVars = new mutable.ArrayBuffer[TypeVar]
+ myMap.foreachBinding { (poly, entries) =>
+ for (i <- 0 until paramCount(entries)) {
+ typeVar(entries, i) match {
+ case tv: TypeVar if isBounds(entries(i)) => myUninstVars += tv
+ case _ =>
+ }
+ }
+ }
+ }
+ myUninstVars
+ }
+
+// ---------- Cyclic checking -------------------------------------------
+
+ private def checkNonCyclic(idx: Int)(implicit ctx: Context): Unit =
+ assert(!less(idx)(idx), i"cyclic constraint involving ${params(idx)}")
+
+ def checkNonCyclic(pt: PolyType, entries: Array[Type])(implicit ctx: Context): Unit =
+ for (i <- entries.indices) checkNonCyclic(paramIndex(PolyParam(pt, i)))
+
+ def checkNonCyclic()(implicit ctx: Context): Unit =
+ for (i <- params.indices) checkNonCyclic(i)
+
+ def checkNonCyclicTrans()(implicit ctx: Context): Unit = checkNonCyclic()
+
+// ---------- toText -----------------------------------------------------
+
+ override def toText(printer: Printer): Text = {
+ def entryText(tp: Type) = tp match {
+ case tp: TypeBounds =>
+ tp.toText(printer)
+ case _ =>
+ " := " ~ tp.toText(printer)
+ }
+ val indent = 3
+ val header: Text = "Constraint("
+ val uninstVarsText = " uninstVars = " ~
+ Text(uninstVars map (_.toText(printer)), ", ") ~ ";"
+ val constrainedText =
+ " constrained types = " ~ Text(domainPolys map (_.toText(printer)), ", ")
+ val boundsText =
+ " bounds = " ~ {
+ val assocs =
+ for (param <- domainParams)
+ yield (" " * indent) ~ param.toText(printer) ~ entryText(entry(param))
+ Text(assocs, "\n")
+ }
+ val orderingText =
+ " ordering = " ~ {
+ val deps =
+ for {
+ param <- domainParams
+ ups = minUpper(param)
+ if ups.nonEmpty
+ }
+ yield
+ (" " * indent) ~ param.toText(printer) ~ " <: " ~
+ Text(ups.map(_.toText(printer)), ", ")
+ Text(deps, "\n")
+ }
+ Text.lines(List(header, uninstVarsText, constrainedText, boundsText, orderingText, ")"))
+ }
+}
+
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 5d910c905..cb8538e26 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -17,7 +17,7 @@ class TyperState(r: Reporter) extends DotClass with Showable {
def reporter = r
/** The current constraint set */
- def constraint: Constraint = new NaiveConstraint(SimpleMap.Empty)
+ def constraint: Constraint = new NaiveConstraint(SimpleMap.Empty)//new TrackingConstraint(SimpleMap.Empty, Array(), Array())
def constraint_=(c: Constraint): Unit = {}
/** The uninstantiated variables */
@@ -38,7 +38,7 @@ class TyperState(r: Reporter) extends DotClass with Showable {
* is done only in a temporary way for contexts that may be retracted
* without also retracting the type var as a whole.
*/
- def instType(tvar: TypeVar): Type = constraint.at(tvar.origin) match {
+ def instType(tvar: TypeVar)(implicit ctx: Context): Type = constraint.at(tvar.origin) match {
case _: TypeBounds => NoType
case tp: PolyParam =>
var tvar1 = constraint.typeVarOfParam(tp)
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 98300f0b0..e16b83afd 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -375,7 +375,7 @@ object ProtoTypes {
tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
case tp: TypeAlias => // default case, inlined for speed
tp.derivedTypeAlias(wildApprox(tp.alias, theMap))
- case tp @ PolyParam(poly, pnum) =>
+ case tp @ PolyParam(poly, pnum) => // !!! todo adapt to TrackingConstraint
ctx.typerState.constraint.at(tp) match {
case bounds: TypeBounds => wildApprox(WildcardType(bounds))
case NoType => WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)