From 54a1bce87b4682ccfb97504e2daa7c36cbf207b2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 12 Oct 2013 12:58:30 +0200 Subject: Tightening up typer state + printing refinements 1) Made consistency checking water tight, so that inconsistencies are always catched wehn they arise 2) Fixed problem in implicit search that led to inconsistencies 3) Refined printing of type parameters and type arguments --- src/dotty/tools/dotc/core/Contexts.scala | 3 +- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- src/dotty/tools/dotc/core/TyperState.scala | 53 ++++++++++++++++++++++++---- src/dotty/tools/dotc/core/Types.scala | 11 +++--- 4 files changed, 55 insertions(+), 14 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 3110d8fd9..3de6337b1 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -288,7 +288,8 @@ object Contexts { def withPeriod(period: Period): this.type = { this.period = period; this } def withNewMode(mode: Mode): this.type = { this.mode = mode; this } def withTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this } - def withNewTyperState: this.type = withTyperState(typerState.fresh) + def withNewTyperState: this.type = withTyperState(typerState.fresh(committable = true)) + def withExploreTyperState: this.type = withTyperState(typerState.fresh(committable = false)) def withPrinterFn(printer: Context => Printer): this.type = { this.printerFn = printer; this } def withOwner(owner: Symbol): this.type = { this.owner = owner; this } def withSettings(sstate: SettingsState): this.type = { this.sstate = sstate; this } diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 5701fcc95..cf24743bf 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -796,7 +796,7 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { } override def isSubType(tp1: Type, tp2: Type) = - traceIndented(s"${show(tp1)} <:< ${show(tp2)} ${tp1.getClass} ${tp2.getClass}") { + traceIndented(s"${show(tp1)} <:< ${show(tp2)}") { super.isSubType(tp1, tp2) } diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala index 4fcfa323e..8ee219cec 100644 --- a/src/dotty/tools/dotc/core/TyperState.scala +++ b/src/dotty/tools/dotc/core/TyperState.scala @@ -29,32 +29,45 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable { def undetVars_=(vs: Set[TypeVar]): Unit = unsupported("undetVars_=") def instType_=(m: SimpleMap[TypeVar, Type]): Unit = unsupported("instType_=") - def fresh: TyperState = this + def fresh(committable: Boolean): TyperState = this def commit()(implicit ctx: Context): Unit = unsupported("commit") @elidable(elidable.FINER) def checkConsistent(implicit ctx: Context) = () + @elidable(elidable.FINER) + def enableChecking(b: Boolean): Boolean = true + + def withCheckingDisabled[T](op: => T)(implicit ctx: Context): T = op + override def toText(printer: Printer): Text = "ImmutableTyperState" } -class MutableTyperState(previous: TyperState, reporter: Reporter) +class MutableTyperState(previous: TyperState, reporter: Reporter, committable: Boolean) extends TyperState(reporter) { private var myConstraint: Constraint = previous.constraint private var myUndetVars: Set[TypeVar] = previous.undetVars private var myInstType: SimpleMap[TypeVar, Type] = previous.instType + private var checkingEnabled: Boolean = committable override def constraint = myConstraint override def undetVars = myUndetVars override def instType = myInstType - override def constraint_=(c: Constraint) = myConstraint = c - override def undetVars_=(vs: Set[TypeVar]) = myUndetVars = vs + override def constraint_=(c: Constraint) = { + myConstraint = c + checkConsistent() + } + override def undetVars_=(vs: Set[TypeVar]) = { + myUndetVars = vs + checkConsistent() + } override def instType_=(m: SimpleMap[TypeVar, Type]): Unit = myInstType = m - override def fresh: TyperState = new MutableTyperState(this, new StoreReporter) + override def fresh(committable: Boolean): TyperState = + new MutableTyperState(this, new StoreReporter, committable) /** Commit typer state so that its information is copied into current typer state * In addition (1) the owning state of undetermined or temporarily instantiated @@ -63,10 +76,13 @@ extends TyperState(reporter) { * instantiated instead. */ override def commit()(implicit ctx: Context) = { + checkConsistent val targetState = ctx.typerState + val prev = targetState.enableChecking(false) targetState.constraint = constraint targetState.undetVars = undetVars targetState.instType = instType + targetState.enableChecking(prev) def adjustOwningState(tvar: TypeVar) = if (tvar.owningState eq this) tvar.owningState = targetState @@ -84,8 +100,8 @@ extends TyperState(reporter) { } @elidable(elidable.FINER) - override def checkConsistent(implicit ctx: Context) = { - def err(msg: String, what: Showable) = s"$msg: ${what.show}\n${this.show}" + def checkConsistent(show: Showable => String = MutableTyperState.toStr): Unit = if (checkingEnabled) { + def err(msg: String, what: Showable) = s"$msg: ${show(what)}\n${show(this)}" for (tvar <- undetVars) assert(constraint(tvar.origin).exists, err("unconstrained type var", tvar)) val undetParams = undetVars map (_.origin) @@ -96,6 +112,25 @@ extends TyperState(reporter) { } } + @elidable(elidable.FINER) + override def checkConsistent(implicit ctx: Context): Unit = checkConsistent(_.show) + + @elidable(elidable.FINER) + override def enableChecking(b: Boolean) = { + val prev = checkingEnabled + checkingEnabled = checkingEnabled && b + prev + } + + override def withCheckingDisabled[T](op: => T)(implicit ctx: Context): T = { + val prev = enableChecking(false) + try op + finally { + enableChecking(prev) + checkConsistent + } + } + override def toText(printer: Printer): Text = { val header: Text = "Typer state:" val undetVarsText = @@ -111,3 +146,7 @@ extends TyperState(reporter) { Text.lines(List(header, undetVarsText, constrainedText, constraintText, instTypeText)) } } + +object MutableTyperState { + private def toStr(x: Any) = x.toString +} diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 257128821..a7dadbd0e 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1862,7 +1862,6 @@ object Types { owningState.undetVars -= this if (ctx.typerState eq creatorState) inst = tp else ctx.typerState.instType = ctx.typerState.instType.updated(this, tp) - ctx.typerState.checkConsistent // !!! DEBUG tp } @@ -1881,10 +1880,12 @@ object Types { case OrType(tp1, tp2) => isSingleton(tp1) & isSingleton(tp2) case _ => false } - var inst = ctx.typeComparer.approximate(origin, fromBelow) - if (fromBelow && isSingleton(inst) && !isSingleton(upperBound)) - inst = inst.widen - instantiateWith(inst) + ctx.typerState.withCheckingDisabled { + var inst = ctx.typeComparer.approximate(origin, fromBelow) + if (fromBelow && isSingleton(inst) && !isSingleton(upperBound)) + inst = inst.widen + instantiateWith(inst) + } } /** If the variable is instantiated, its instance, otherwise its origin */ -- cgit v1.2.3