From ba9ad1e1fe5a5043fe35bfc4cabc7abc15876b14 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Sep 2017 10:57:05 +0200 Subject: [PATCH 1/4] Avoid exploring TyperState creations Dotty bootstrap (from dotc directory) has 5924910 context creations. This commit brings that number down to 4307795. It also reduces the number of TyperStates created from 2'059'126 to 308'732. --- .../dotty/tools/dotc/core/TyperState.scala | 21 ++++++- .../dotty/tools/dotc/typer/Applications.scala | 55 +++++++------------ .../dotty/tools/dotc/typer/Implicits.scala | 20 ++++--- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- 4 files changed, 55 insertions(+), 43 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TyperState.scala b/compiler/src/dotty/tools/dotc/core/TyperState.scala index 051fb20ee02c..021bab685b17 100644 --- a/compiler/src/dotty/tools/dotc/core/TyperState.scala +++ b/compiler/src/dotty/tools/dotc/core/TyperState.scala @@ -73,17 +73,21 @@ class TyperState(r: Reporter) extends DotClass with Showable { /** Is it allowed to commit this state? */ def isCommittable: Boolean = false + def isCommittable_=(b: Boolean) = () /** Can this state be transitively committed until the top-level? */ def isGlobalCommittable: Boolean = false + /** Test using `op`, restoring typerState to previous state afterwards */ + def test(op: => Boolean): Boolean = op + override def toText(printer: Printer): Text = "ImmutableTyperState" /** A string showing the hashes of all nested mutable typerstates */ def hashesStr: String = "" } -class MutableTyperState(previous: TyperState, r: Reporter, override val isCommittable: Boolean) +class MutableTyperState(previous: TyperState, r: Reporter, override var isCommittable: Boolean) extends TyperState(r) { private var myReporter = r @@ -119,6 +123,21 @@ extends TyperState(r) { override def uncommittedAncestor: TyperState = if (isCommitted) previous.uncommittedAncestor else this + override def test(op: => Boolean): Boolean = { + val savedReporter = myReporter + val savedConstraint = myConstraint + val savedCommitted = isCommitted + val savedCommittable = isCommittable + isCommittable = false + try op + finally { + myReporter = savedReporter + myConstraint = savedConstraint + isCommitted = savedCommitted + isCommittable = savedCommittable + } + } + /** Commit typer state so that its information is copied into current typer state * In addition (1) the owning state of undetermined or temporarily instantiated * type variables changes from this typer state to the current one. (2) Variables diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 548824ce2684..718a5d8c2eda 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1002,26 +1002,20 @@ trait Applications extends Compatibility { self: Typer with Dynamic => /** Is given method reference applicable to type arguments `targs` and argument trees `args`? * @param resultType The expected result type of the application */ - def isApplicable(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context): Boolean = { - val nestedContext = ctx.fresh.setExploreTyperState - new ApplicableToTrees(methRef, targs, args, resultType)(nestedContext).success - } + def isApplicable(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context): Boolean = + ctx.typerState.test(new ApplicableToTrees(methRef, targs, args, resultType).success) /** Is given method reference applicable to type arguments `targs` and argument trees `args` without inferring views? * @param resultType The expected result type of the application */ - def isDirectlyApplicable(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context): Boolean = { - val nestedContext = ctx.fresh.setExploreTyperState - new ApplicableToTreesDirectly(methRef, targs, args, resultType)(nestedContext).success - } + def isDirectlyApplicable(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context): Boolean = + ctx.typerState.test(new ApplicableToTreesDirectly(methRef, targs, args, resultType).success) /** Is given method reference applicable to argument types `args`? * @param resultType The expected result type of the application */ - def isApplicable(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context): Boolean = { - val nestedContext = ctx.fresh.setExploreTyperState - new ApplicableToTypes(methRef, args, resultType)(nestedContext).success - } + def isApplicable(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context): Boolean = + ctx.typerState.test(new ApplicableToTypes(methRef, args, resultType).success) /** Is given type applicable to type arguments `targs` and argument trees `args`, * possibly after inserting an `apply`? @@ -1102,12 +1096,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => case tp2: MethodType => true // (3a) case tp2: PolyType if tp2.resultType.isInstanceOf[MethodType] => true // (3a) case tp2: PolyType => // (3b) - val nestedCtx = ctx.fresh.setExploreTyperState - - { - implicit val ctx = nestedCtx - isAsSpecificValueType(tp1, constrained(tp2).resultType) - } + ctx.typerState.test(isAsSpecificValueType(tp1, constrained(tp2).resultType)) case _ => // (3b) isAsSpecificValueType(tp1, tp2) } @@ -1253,22 +1242,20 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * probability of pruning the search. result type comparisons are neither cheap nor * do they prune much, on average. */ - def adaptByResult(chosen: TermRef) = { - def nestedCtx = ctx.fresh.setExploreTyperState - pt match { - case pt: FunProto if !resultConforms(chosen, pt.resultType)(nestedCtx) => - alts.filter(alt => - (alt ne chosen) && resultConforms(alt, pt.resultType)(nestedCtx)) match { - case Nil => chosen - case alt2 :: Nil => alt2 - case alts2 => - resolveOverloaded(alts2, pt) match { - case alt2 :: Nil => alt2 - case _ => chosen - } - } - case _ => chosen - } + def adaptByResult(chosen: TermRef) = pt match { + case pt: FunProto if !ctx.typerState.test(resultConforms(chosen, pt.resultType)) => + val conformingAlts = alts.filter(alt => + (alt ne chosen) && ctx.typerState.test(resultConforms(alt, pt.resultType))) + conformingAlts match { + case Nil => chosen + case alt2 :: Nil => alt2 + case alts2 => + resolveOverloaded(alts2, pt) match { + case alt2 :: Nil => alt2 + case _ => chosen + } + } + case _ => chosen } var found = resolveOverloaded(alts, pt, Nil)(ctx.retractMode(Mode.ImplicitsEnabled)) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 10cfcf87cf15..1ac1798d555a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -67,7 +67,7 @@ object Implicits { case mt: MethodType => mt.isImplicit || mt.paramInfos.length != 1 || - !(argType relaxed_<:< mt.paramInfos.head)(ctx.fresh.setExploreTyperState) + !ctx.typerState.test(argType relaxed_<:< mt.paramInfos.head) case poly: PolyType => // We do not need to call ProtoTypes#constrained on `poly` because // `refMatches` is always called with mode TypevarsMissContext enabled. @@ -75,7 +75,7 @@ object Implicits { case mt: MethodType => mt.isImplicit || mt.paramInfos.length != 1 || - !(argType relaxed_<:< wildApprox(mt.paramInfos.head, null, Set.empty)(ctx.fresh.setExploreTyperState)) + !ctx.typerState.test(argType relaxed_<:< wildApprox(mt.paramInfos.head, null, Set.empty)) case rtp => discardForView(wildApprox(rtp, null, Set.empty), argType) } @@ -131,8 +131,12 @@ object Implicits { } if (refs.isEmpty) Nil - else refs.filter(refMatches(_)(ctx.fresh.addMode(Mode.TypevarsMissContext).setExploreTyperState)) // create a defensive copy of ctx to avoid constraint pollution - .map(Candidate(_, level)) + else { + val nestedCtx = ctx.fresh.addMode(Mode.TypevarsMissContext) + refs + .filter(ref => nestedCtx.typerState.test(refMatches(ref)(nestedCtx))) + .map(Candidate(_, level)) + } } } @@ -507,6 +511,7 @@ trait Implicits { self: Typer => || inferView(dummyTreeOfType(from), to) (ctx.fresh.addMode(Mode.ImplicitExploration).setExploreTyperState) .isInstanceOf[SearchSuccess] + // TODO: investigate why we can't TyperState#test here ) ) @@ -578,7 +583,7 @@ trait Implicits { self: Typer => formal.argTypes match { case args @ (arg1 :: arg2 :: Nil) if !ctx.featureEnabled(defn.LanguageModuleClass, nme.strictEquality) && - validEqAnyArgs(arg1, arg2)(ctx.fresh.setExploreTyperState) => + ctx.typerState.test(validEqAnyArgs(arg1, arg2)) => ref(defn.Eq_eqAny).appliedToTypes(args).withPos(pos) case _ => EmptyTree @@ -822,7 +827,7 @@ trait Implicits { self: Typer => if (ctx.mode.is(Mode.ImplicitExploration) || isCoherent) best :: Nil else { val newPending = pending1.filter(cand1 => - isAsGood(cand1.ref, best.ref, cand1.level, best.level)(nestedContext.setExploreTyperState)) + ctx.typerState.test(isAsGood(cand1.ref, best.ref, cand1.level, best.level)(nestedContext))) rankImplicits(newPending, best :: acc) } } @@ -851,7 +856,8 @@ trait Implicits { self: Typer => /** Convert a (possibly empty) list of search successes into a single search result */ def condense(hits: List[SearchSuccess]): SearchResult = hits match { case best :: alts => - alts find (alt => isAsGood(alt.ref, best.ref, alt.level, best.level)(ctx.fresh.setExploreTyperState)) match { + alts.find(alt => + ctx.typerState.test(isAsGood(alt.ref, best.ref, alt.level, best.level))) match { case Some(alt) => typr.println(i"ambiguous implicits for $pt: ${best.ref} @ ${best.level}, ${alt.ref} @ ${alt.level}") /* !!! DEBUG diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index bd5ff738ff2d..86b7c346817f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1977,7 +1977,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val constraint = ctx.typerState.constraint def inst(tp: Type): Type = tp match { case TypeBounds(lo, hi) - if (lo eq hi) || (hi <:< lo)(ctx.fresh.setExploreTyperState) => + if (lo eq hi) || ctx.typerState.test(hi <:< lo) => inst(lo) case tp: TypeParamRef => constraint.typeVarOfParam(tp).orElse(tp) From f0b30801849c55a78cf253778078d26116e6b913 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Sep 2017 13:54:25 +0200 Subject: [PATCH 2/4] Simplify TyperState Have just one class instead of two. This will be important for inlining the `test` method. Also, fix test method - it needs to create a new StoreReporter. --- compiler/src/dotty/tools/dotc/Run.scala | 2 +- .../src/dotty/tools/dotc/core/Contexts.scala | 8 +- .../dotty/tools/dotc/core/TyperState.scala | 149 ++++++++---------- .../tools/dotc/reporting/StoreReporter.scala | 2 + 4 files changed, 69 insertions(+), 92 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 10ccc59a3e5f..6513de4ccdd0 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -49,7 +49,7 @@ class Run(comp: Compiler, ictx: Context) { .setOwner(defn.RootClass) .setTyper(new Typer) .addMode(Mode.ImplicitsEnabled) - .setTyperState(new MutableTyperState(ctx.typerState, ctx.typerState.reporter, isCommittable = true)) + .setTyperState(new TyperState(ctx.typerState)) .setFreshNames(new FreshNameCreator.Default) ctx.initialize()(start) // re-initialize the base context with start def addImport(ctx: Context, refFn: () => TermRef) = diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index bdc0be6e6ca3..85dc5e75012e 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -455,9 +455,9 @@ object Contexts { def setCompilerCallback(callback: CompilerCallback): this.type = { this.compilerCallback = callback; this } def setSbtCallback(callback: AnalysisCallback): this.type = { this.sbtCallback = callback; this } def setTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this } - def setReporter(reporter: Reporter): this.type = setTyperState(typerState.withReporter(reporter)) - def setNewTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true)) - def setExploreTyperState: this.type = setTyperState(typerState.fresh(isCommittable = false)) + def setReporter(reporter: Reporter): this.type = setTyperState(typerState.fresh().setReporter(reporter)) + def setNewTyperState(): this.type = setTyperState(typerState.fresh().setCommittable(true)) + def setExploreTyperState(): this.type = setTyperState(typerState.fresh().setCommittable(false)) def setPrinterFn(printer: Context => Printer): this.type = { this.printerFn = printer; this } def setOwner(owner: Symbol): this.type = { assert(owner != NoSymbol); this.owner = owner; this } def setSettings(sstate: SettingsState): this.type = { this.sstate = sstate; this } @@ -516,7 +516,7 @@ object Contexts { outer = NoContext period = InitialPeriod mode = Mode.None - typerState = new TyperState(new ConsoleReporter()) + typerState = new TyperState(null) printerFn = new RefinedPrinter(_) owner = NoSymbol sstate = settings.defaultState diff --git a/compiler/src/dotty/tools/dotc/core/TyperState.scala b/compiler/src/dotty/tools/dotc/core/TyperState.scala index 021bab685b17..df7c9e087423 100644 --- a/compiler/src/dotty/tools/dotc/core/TyperState.scala +++ b/compiler/src/dotty/tools/dotc/core/TyperState.scala @@ -13,18 +13,31 @@ import config.Config import collection.mutable import java.lang.ref.WeakReference -class TyperState(r: Reporter) extends DotClass with Showable { +class TyperState(previous: TyperState /* | Null */) extends DotClass with Showable { - /** The current reporter */ - def reporter = r + private var myReporter = + if (previous == null) new ConsoleReporter() else previous.reporter - /** The current constraint set */ - def constraint: Constraint = - new OrderingConstraint(SimpleMap.Empty, SimpleMap.Empty, SimpleMap.Empty) - def constraint_=(c: Constraint)(implicit ctx: Context): Unit = {} + def reporter: Reporter = myReporter - /** The uninstantiated variables */ - def uninstVars = constraint.uninstVars + /** A fresh type state with the same constraint as this one and the given reporter */ + def setReporter(reporter: Reporter): this.type = { myReporter = reporter; this } + + private var myConstraint: Constraint = + if (previous == null) new OrderingConstraint(SimpleMap.Empty, SimpleMap.Empty, SimpleMap.Empty) + else previous.constraint + + def constraint = myConstraint + def constraint_=(c: Constraint)(implicit ctx: Context) = { + if (Config.debugCheckConstraintsClosed && isGlobalCommittable) c.checkClosed() + myConstraint = c + } + + private val previousConstraint = + if (previous == null) constraint else previous.constraint + + private var myEphemeral: Boolean = + if (previous == null) false else previous.ephemeral /** The ephemeral flag is set as a side effect if an operation accesses * the underlying type of a type variable. The reason we need this flag is @@ -33,8 +46,26 @@ class TyperState(r: Reporter) extends DotClass with Showable { * check the ephemeral flag; If the flag is set during an operation, the result * of that operation should not be cached. */ - def ephemeral: Boolean = false - def ephemeral_=(x: Boolean): Unit = () + def ephemeral = myEphemeral + def ephemeral_=(x: Boolean): Unit = { myEphemeral = x } + + private var myIsCommittable = true + + def isCommittable = myIsCommittable + + def setCommittable(committable: Boolean): this.type = { this.myIsCommittable = committable; this } + + def isGlobalCommittable: Boolean = + isCommittable && (previous == null || previous.isGlobalCommittable) + + private var isCommitted = false + + /** A fresh typer state with the same constraint as this one. */ + def fresh(): TyperState = + new TyperState(this).setReporter(new StoreReporter(reporter)).setCommittable(isCommittable) + + /** The uninstantiated variables */ + def uninstVars = constraint.uninstVars /** Gives for each instantiated type var that does not yet have its `inst` field * set, the instance value stored in the constraint. Storing instances in constraints @@ -49,92 +80,33 @@ class TyperState(r: Reporter) extends DotClass with Showable { case tp => tp } - /** A fresh typer state with the same constraint as this one. - * @param isCommittable The constraint can be committed to an enclosing context. - */ - def fresh(isCommittable: Boolean): TyperState = this - - /** A fresh type state with the same constraint as this one and the given reporter */ - def withReporter(reporter: Reporter) = new TyperState(reporter) - - /** Commit state so that it gets propagated to enclosing context */ - def commit()(implicit ctx: Context): Unit = unsupported("commit") - /** The closest ancestor of this typer state (including possibly this typer state itself) * which is not yet committed, or which does not have a parent. */ - def uncommittedAncestor: TyperState = this - - /** Make type variable instances permanent by assigning to `inst` field if - * type variable instantiation cannot be retracted anymore. Then, remove - * no-longer needed constraint entries. - */ - def gc()(implicit ctx: Context): Unit = () - - /** Is it allowed to commit this state? */ - def isCommittable: Boolean = false - def isCommittable_=(b: Boolean) = () + def uncommittedAncestor: TyperState = + if (isCommitted) previous.uncommittedAncestor else this - /** Can this state be transitively committed until the top-level? */ - def isGlobalCommittable: Boolean = false + private var testReporter: StoreReporter = null /** Test using `op`, restoring typerState to previous state afterwards */ - def test(op: => Boolean): Boolean = op - - override def toText(printer: Printer): Text = "ImmutableTyperState" - - /** A string showing the hashes of all nested mutable typerstates */ - def hashesStr: String = "" -} - -class MutableTyperState(previous: TyperState, r: Reporter, override var isCommittable: Boolean) -extends TyperState(r) { - - private var myReporter = r - - override def reporter = myReporter - - private val previousConstraint = previous.constraint - private var myConstraint: Constraint = previousConstraint - - override def constraint = myConstraint - override def constraint_=(c: Constraint)(implicit ctx: Context) = { - if (Config.debugCheckConstraintsClosed && isGlobalCommittable) c.checkClosed() - myConstraint = c - } - - private var myEphemeral: Boolean = previous.ephemeral - - override def ephemeral = myEphemeral - override def ephemeral_=(x: Boolean): Unit = { myEphemeral = x } - - override def fresh(isCommittable: Boolean): TyperState = - new MutableTyperState(this, new StoreReporter(reporter), isCommittable) - - override def withReporter(reporter: Reporter) = - new MutableTyperState(this, reporter, isCommittable) - - override val isGlobalCommittable = - isCommittable && - (!previous.isInstanceOf[MutableTyperState] || previous.isGlobalCommittable) - - private var isCommitted = false - - override def uncommittedAncestor: TyperState = - if (isCommitted) previous.uncommittedAncestor else this - - override def test(op: => Boolean): Boolean = { + def test(op: => Boolean): Boolean = { val savedReporter = myReporter val savedConstraint = myConstraint + val savedCommittable = myIsCommittable val savedCommitted = isCommitted - val savedCommittable = isCommittable - isCommittable = false + myIsCommittable = false + myReporter = + if (testReporter == null) new StoreReporter(reporter) + else { + testReporter.reset() + testReporter + } try op finally { myReporter = savedReporter myConstraint = savedConstraint + myIsCommittable = savedCommittable isCommitted = savedCommitted - isCommittable = savedCommittable } } @@ -156,7 +128,7 @@ extends TyperState(r) { * isApplicableSafe but also for (e.g. erased-lubs.scala) as well as * many parts of dotty itself. */ - override def commit()(implicit ctx: Context) = { + def commit()(implicit ctx: Context) = { val targetState = ctx.typerState assert(isCommittable) targetState.constraint = @@ -171,7 +143,11 @@ extends TyperState(r) { isCommitted = true } - override def gc()(implicit ctx: Context): Unit = { + /** Make type variable instances permanent by assigning to `inst` field if + * type variable instantiation cannot be retracted anymore. Then, remove + * no-longer needed constraint entries. + */ + def gc()(implicit ctx: Context): Unit = { val toCollect = new mutable.ListBuffer[TypeLambda] constraint foreachTypeVar { tvar => if (!tvar.inst.exists) { @@ -189,6 +165,5 @@ extends TyperState(r) { override def toText(printer: Printer): Text = constraint.toText(printer) - override def hashesStr: String = hashCode.toString + " -> " + previous.hashesStr - + def hashesStr: String = hashCode.toString + " -> " + previous.hashesStr } diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala index 343e6a517712..ac60124ae86e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -22,6 +22,8 @@ class StoreReporter(outer: Reporter) extends Reporter { private var infos: mutable.ListBuffer[MessageContainer] = null + def reset() = infos = null + def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { typr.println(s">>>> StoredError: ${m.message}") // !!! DEBUG if (infos == null) infos = new mutable.ListBuffer From 3c99a20446ff897c2dca15648ee242253ea0ac8f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Sep 2017 14:00:36 +0200 Subject: [PATCH 3/4] Fix ()'s in new/exploreTyperState --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 6 +++--- compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala | 8 +++----- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 1ac1798d555a..ca1c8425245d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -509,7 +509,7 @@ trait Implicits { self: Typer => && from.isValueType && ( from.isValueSubType(to) || inferView(dummyTreeOfType(from), to) - (ctx.fresh.addMode(Mode.ImplicitExploration).setExploreTyperState) + (ctx.fresh.addMode(Mode.ImplicitExploration).setExploreTyperState()) .isInstanceOf[SearchSuccess] // TODO: investigate why we can't TyperState#test here ) @@ -787,7 +787,7 @@ trait Implicits { self: Typer => val generated1 = adapt(generated, pt) lazy val shadowing = typed(untpd.Ident(ref.name) withPos pos.toSynthetic, funProto)( - nestedContext.addMode(Mode.ImplicitShadowing).setExploreTyperState) + nestedContext.addMode(Mode.ImplicitShadowing).setExploreTyperState()) def refSameAs(shadowing: Tree): Boolean = ref.symbol == closureBody(shadowing).symbol || { shadowing match { @@ -819,7 +819,7 @@ trait Implicits { self: Typer => val history = ctx.searchHistory nest wildProto val result = if (history eq ctx.searchHistory) divergingImplicit(cand.ref) - else typedImplicit(cand)(nestedContext.setNewTyperState.setSearchHistory(history)) + else typedImplicit(cand)(nestedContext.setNewTyperState().setSearchHistory(history)) result match { case fail: SearchFailure => rankImplicits(pending1, acc) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 4906a26966a2..2b372640f51f 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -39,11 +39,9 @@ object ProtoTypes { (tp.widenExpr relaxed_<:< pt.widenExpr) || viewExists(tp, pt) /** Test compatibility after normalization in a fresh typerstate. */ - def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = { - val nestedCtx = ctx.fresh.setExploreTyperState - val normTp = normalize(tp, pt)(nestedCtx) - isCompatible(normTp, pt)(nestedCtx) || - pt.isRef(defn.UnitClass) && normTp.isParameterless + def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = ctx.typerState.test { + val normTp = normalize(tp, pt) + isCompatible(normTp, pt) || pt.isRef(defn.UnitClass) && normTp.isParameterless } private def disregardProto(pt: Type)(implicit ctx: Context): Boolean = pt.dealias match { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 86b7c346817f..8d258927173c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1755,7 +1755,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit typed(tree, selType)(ctx addMode Mode.Pattern) def tryEither[T](op: Context => T)(fallBack: (T, TyperState) => T)(implicit ctx: Context) = { - val nestedCtx = ctx.fresh.setNewTyperState + val nestedCtx = ctx.fresh.setNewTyperState() val result = op(nestedCtx) if (nestedCtx.reporter.hasErrors) fallBack(result, nestedCtx.typerState) From dfff891a55e9c587749c8df119632a04aa83974c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Sep 2017 14:35:36 +0200 Subject: [PATCH 4/4] More () fixes --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Inferencing.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 718a5d8c2eda..b0a6d12f27a5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -847,7 +847,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def followTypeAlias(tree: untpd.Tree): untpd.Tree = { tree match { case tree: untpd.RefTree => - val nestedCtx = ctx.fresh.setNewTyperState + val nestedCtx = ctx.fresh.setNewTyperState() val ttree = typedType(untpd.rename(tree, tree.name.toTypeName))(nestedCtx) ttree.tpe match { diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 99a6e5373fa9..a78a9582597f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -31,7 +31,7 @@ object Inferencing { * Variables that are successfully minimized do not count as uninstantiated. */ def isFullyDefined(tp: Type, force: ForceDegree.Value)(implicit ctx: Context): Boolean = { - val nestedCtx = ctx.fresh.setNewTyperState + val nestedCtx = ctx.fresh.setNewTyperState() val result = new IsFullyDefinedAccumulator(force)(nestedCtx).process(tp) if (result) nestedCtx.typerState.commit() result