From 37918e5d1eb53014b1116ea65381a56e93a3c855 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 28 Jan 2015 18:55:51 +0100 Subject: Cleanups prompted by reviews. --- src/dotty/tools/dotc/config/Config.scala | 2 +- src/dotty/tools/dotc/core/ConstraintHandling.scala | 67 +++++++++------------- src/dotty/tools/dotc/core/Symbols.scala | 4 +- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- src/dotty/tools/dotc/typer/Mode.scala | 6 ++ src/dotty/tools/dotc/typer/ProtoTypes.scala | 3 +- 6 files changed, 39 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index fe4e88829..a599b5892 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -37,7 +37,7 @@ object Config { * on only for specific debugging as normally instantiation to Nothing * is not an error consdition. */ - final val flagInstantiationToNothing = false + final val failOnInstantiationToNothing = false /** Enable noDoubleDef checking if option "-YnoDoubleDefs" is set. * The reason to have an option as well as the present global switch is diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala index 478fc5740..796960337 100644 --- a/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -9,27 +9,14 @@ import config.Printers._ /** Methods for adding constraints and solving them. * - * Constraints are required to be in normalized form. This means - * (1) if P <: Q in C then also Q >: P in C - * (2) if P r Q in C and Q r R in C then also P r R in C, where r is <: or :> - * - * "P <: Q in C" means here: There is a constraint P <: H[Q], - * where H is the multi-hole context given by: - * - * H = [] - * H & T - * T & H - * H | H - * - * (the idea is that a parameter Q in a H context is guaranteed to be a supertype of P). - * - * "P >: Q in C" means: There is a constraint P >: L[Q], - * where L is the multi-hole context given by: - * - * L = [] - * L | T - * T | L - * L & L + * What goes into a Constraint as opposed to a ConstrainHandler? + * + * Constraint code is purely functional: Operations get constraints and produce new ones. + * Constraint code does not have access to a type-comparer. Anything regarding lubs and glbs has to be done + * elsewhere. + * + * By comparison: Constraint handlers are parts of type comparers and can use their functionality. + * Constraint handlers update the current constraint as a side effect. */ trait ConstraintHandling { @@ -59,7 +46,7 @@ trait ConstraintHandling { def description = i"constraint $param <: $bound to\n$constraint" if (bound.isRef(defn.NothingClass) && ctx.typerState.isGlobalCommittable) { def msg = s"!!! instantiated to Nothing: $param, constraint = ${constraint.show}" - if (Config.flagInstantiationToNothing) assert(false, msg) + if (Config.failOnInstantiationToNothing) assert(false, msg) else ctx.log(msg) } constr.println(i"adding $description") @@ -86,9 +73,6 @@ trait ConstraintHandling { def description = i"ordering $p1 <: $p2 to\n$constraint" val res = if (constraint.isLess(p2, p1)) unify(p2, p1) - // !!! this is direction dependent - unify(p1, p2) makes i94-nada loop forever. - // Need to investigate why this is the case. - // The symptom is that we get a subtyping constraint of the form P { ... } <: P else { val down1 = p1 :: constraint.exclusiveLower(p1, p2) val up2 = p2 :: constraint.exclusiveUpper(p2, p1) @@ -193,20 +177,24 @@ trait ConstraintHandling { case _ => param.binder.paramBounds(param.paramNum) } - /** If `p` is a parameter of `pt`, propagate the non-parameter bounds - * of `p` to the parameters known to be less or greater than `p`. + /** Add polytype `pt`, possibly with type variables `tvars`, to current constraint + * and propagate all bounds. + * @param tvars See Constraint#add */ - def initialize(pt: PolyType): Boolean = - checkPropagated(i"initialized $pt") { - pt.paramNames.indices.forall { i => - val param = PolyParam(pt, i) - val bounds = constraint.nonParamBounds(param) - val lower = constraint.lower(param) - val upper = constraint.upper(param) - if (lower.nonEmpty && !bounds.lo.isRef(defn.NothingClass) || - upper.nonEmpty && !bounds.hi.isRef(defn.AnyClass)) println(i"INIT*** $pt") - lower.forall(addOneBound(_, bounds.hi, isUpper = true)) && - upper.forall(addOneBound(_, bounds.lo, isUpper = false)) + def addToConstraint(pt: PolyType, tvars: List[TypeVar]): Unit = + assert { + checkPropagated(i"initialized $pt") { + constraint = constraint.add(pt, tvars) + pt.paramNames.indices.forall { i => + val param = PolyParam(pt, i) + val bounds = constraint.nonParamBounds(param) + val lower = constraint.lower(param) + val upper = constraint.upper(param) + if (lower.nonEmpty && !bounds.lo.isRef(defn.NothingClass) || + upper.nonEmpty && !bounds.hi.isRef(defn.AnyClass)) println(i"INIT*** $pt") + lower.forall(addOneBound(_, bounds.hi, isUpper = true)) && + upper.forall(addOneBound(_, bounds.lo, isUpper = false)) + } } } @@ -239,6 +227,7 @@ trait ConstraintHandling { /** Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated */ def checkPropagated(msg: => String)(result: Boolean): Boolean = { if (Config.checkConstraintsPropagated && result && addConstraintInvocations == 0) { + val saved = frozenConstraint frozenConstraint = true for (p <- constraint.domainParams) { def check(cond: => Boolean, q: PolyParam, ordering: String, explanation: String): Unit = @@ -250,7 +239,7 @@ trait ConstraintHandling { check(constraint.isLess(l, p), l, ">:", "reverse ordering (<:) missing") } } - frozenConstraint = false + frozenConstraint = saved } result } diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 2854d7d2f..bff743fea 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -256,8 +256,8 @@ trait Symbols { this: Context => tparams } - /** Create a new skolem symbol. This is not the same as SkolemType, even thouggh the - * motivation (create a singleton referencing to a type)= is similar. + /** Create a new skolem symbol. This is not the same as SkolemType, even though the + * motivation (create a singleton referencing to a type) is similar. */ def newSkolem(tp: Type) = newSymbol(defn.RootClass, nme.SKOLEM, SyntheticArtifact | Permanent, tp) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 06f03b9f9..1d0ea03c1 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -249,7 +249,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi def flagNothingBound = { if (!frozenConstraint && tp2.isRef(defn.NothingClass) && state.isGlobalCommittable) { def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}" - if (Config.flagInstantiationToNothing) assert(false, msg) + if (Config.failOnInstantiationToNothing) assert(false, msg) else ctx.log(msg) } true diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala index 8e62adfdd..1a57fdc54 100644 --- a/src/dotty/tools/dotc/typer/Mode.scala +++ b/src/dotty/tools/dotc/typer/Mode.scala @@ -31,6 +31,12 @@ object Mode { val ImplicitsEnabled = newMode(2, "ImplicitsEnabled") val InferringReturnType = newMode(3, "InferringReturnType") + /** This mode bit is set if we collect information without reference to a valid + * context with typerstate and constraint. This is typically done when we + * cache the eligibility of implicits. Caching needs to be done across different constraints. + * Therefore, if TypevarsMissContext is set, subtyping becomes looser, and assumes + * that PolyParams can be sub- and supertypes of anything. See TypeComparer. + */ val TypevarsMissContext = newMode(4, "TypevarsMissContext") val CheckCyclic = newMode(5, "CheckCyclic") diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index e4d58cb19..24b4cb423 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -324,8 +324,7 @@ object ProtoTypes { if (state.constraint contains pt) pt.duplicate(pt.paramNames, pt.paramBounds, pt.resultType) else pt val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added) - state.constraint = state.constraint.add(added, tvars) - ctx.typeComparer.initialize(added) + ctx.typeComparer.addToConstraint(added, tvars) (added, tvars) } -- cgit v1.2.3