package dotty.tools package dotc package core import Types._, Contexts._ import util.SimpleMap /** Constraint over undetermined type parameters * @param map a map from PolyType to the type bounds that constrain the * polytype's type parameters. A type parameter that does not * have a constraint is represented by a `NoType` in the corresponding * array entry. */ class Constraint(val map: SimpleMap[PolyType, Array[Type]]) extends AnyVal { /** Does the constraint's domain contain the type parameters of `pt`? */ def contains(pt: PolyType): Boolean = map(pt) != null /** The constraint for given type parameter `param`, or NoType if `param` is not part of * the constraint domain. */ def apply(param: PolyParam): Type = { val entries = map(param.binder) if (entries == null) NoType else entries(param.paramNum) } /** The constraint for the type parameters of `pt`. * @pre The polytype's type parameters are contained in the constraint's domain. */ def apply(pt: PolyType): Array[Type] = map(pt) /** A new constraint which is derived from this constraint by adding or replacing * the entries corresponding to `pt` with `entries`. */ def updated(pt: PolyType, entries: Array[Type]) = new Constraint(map.updated(pt, entries)) /** A new constraint which is derived from this constraint by removing * the type parameter `param` from the domain. */ def - (param: PolyParam) = { val pt = param.binder val pnum = param.paramNum val entries = map(pt) var noneLeft = true var i = 0 while (noneLeft && (i < entries.length)) { noneLeft = (entries(i) eq NoType) || i == pnum i += 1 } new Constraint( if (noneLeft) map remove pt else { val newEntries = entries.clone newEntries(pnum) = NoType map.updated(pt, newEntries) }) } def +(pt: PolyType) = new Constraint(map.updated(pt, pt.paramBounds.toArray)) /** 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) = { def subst(entries: Array[Type]) = { var result = entries var i = 0 while (i < entries.length) { entries(i) match { case oldBounds: TypeBounds => val newBounds = oldBounds.substParam(param, tp) if (oldBounds ne newBounds) { if (result eq entries) result = entries.clone result(i) = newBounds } case _ => } i += 1 } result } new Constraint((this - param).map mapValues subst) } }