Skip to content

Commit 2e7385a

Browse files
committed
Change test logic.
Use a freelist of unsused contexts instead of overwriting typerstate variables. Rename from `ctx.test` to `explore`.
1 parent 5b14510 commit 2e7385a

14 files changed

+174
-133
lines changed

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
7272
.setOwner(defn.RootClass)
7373
.setTyper(new Typer)
7474
.addMode(Mode.ImplicitsEnabled)
75-
.setTyperState(new TyperState(ctx.typerState))
75+
.setTyperState(ctx.typerState.fresh(ctx.reporter))
7676
ctx.initialize()(using start) // re-initialize the base context with start
7777
def addImport(ctx: Context, rootRef: ImportInfo.RootRef) =
7878
ctx.fresh.setImportInfo(ImportInfo.rootImport(rootRef))

compiler/src/dotty/tools/dotc/core/Constraint.scala

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,4 @@ abstract class Constraint extends Showable {
161161

162162
/** Check that constraint only refers to TypeParamRefs bound by itself */
163163
def checkClosed()(using Context): Unit
164-
165-
/** Constraint has not yet been retracted from a typer state */
166-
def isRetracted: Boolean
167-
168-
/** Indicate that constraint has been retracted from a typer state */
169-
def markRetracted(): Unit
170164
}

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ object Contexts {
286286
* contexts are created only on request and cached in this array
287287
*/
288288
private var phasedCtx: Context = this
289-
private var phasedCtxs: Array[Context] = _
289+
private var phasedCtxs: Array[Context] = null
290290

291291
/** This context at given phase.
292292
* This method will always return a phase period equal to phaseId, thus will never return squashed phases
@@ -340,11 +340,6 @@ object Contexts {
340340
/** The current reporter */
341341
def reporter: Reporter = typerState.reporter
342342

343-
/** Run `op` as if it was run in a fresh explore typer state, but possibly
344-
* optimized to re-use the current typer state.
345-
*/
346-
final def test[T](op: Context ?=> T): T = typerState.test(op)(using this)
347-
348343
/** Is this a context for the members of a class definition? */
349344
def isClassDefContext: Boolean =
350345
owner.isClass && (owner ne outer.owner)
@@ -453,15 +448,17 @@ object Contexts {
453448
/** Is the explicit nulls option set? */
454449
def explicitNulls: Boolean = base.settings.YexplicitNulls.value
455450

456-
protected def init(outer: Context, origin: Context): this.type = {
457-
util.Stats.record("Context.fresh")
451+
/** Initialize all context fields, except typerState, which has to be set separately
452+
* @param outer The outer context
453+
* @param origin The context from which fields are copied
454+
*/
455+
private[Contexts] def init(outer: Context, origin: Context): this.type = {
458456
_outer = outer
459457
_period = origin.period
460458
_mode = origin.mode
461459
_owner = origin.owner
462460
_tree = origin.tree
463461
_scope = origin.scope
464-
_typerState = origin.typerState
465462
_typeAssigner = origin.typeAssigner
466463
_gadt = origin.gadt
467464
_searchHistory = origin.searchHistory
@@ -472,11 +469,19 @@ object Contexts {
472469
this
473470
}
474471

472+
def reuseIn(outer: Context): this.type =
473+
implicitsCache = null
474+
phasedCtxs = null
475+
sourceCtx = null
476+
init(outer, outer)
477+
475478
/** A fresh clone of this context embedded in this context. */
476479
def fresh: FreshContext = freshOver(this)
477480

478481
/** A fresh clone of this context embedded in the specified `outer` context. */
479-
def freshOver(outer: Context): FreshContext = new FreshContext(base).init(outer, this)
482+
def freshOver(outer: Context): FreshContext =
483+
util.Stats.record("Context.fresh")
484+
FreshContext(base).init(outer, this).setTyperState(this.typerState)
480485

481486
final def withOwner(owner: Symbol): Context =
482487
if (owner ne this.owner) fresh.setOwner(owner) else this
@@ -539,25 +544,59 @@ object Contexts {
539544
* of its attributes using the with... methods.
540545
*/
541546
class FreshContext(base: ContextBase) extends Context(base) {
542-
def setPeriod(period: Period): this.type = { this.period = period; this }
543-
def setMode(mode: Mode): this.type = { this.mode = mode; this }
544-
def setOwner(owner: Symbol): this.type = { assert(owner != NoSymbol); this.owner = owner; this }
545-
def setTree(tree: Tree[? >: Untyped]): this.type = { this.tree = tree; this }
547+
def setPeriod(period: Period): this.type =
548+
util.Stats.record("Context.setPeriod")
549+
this.period = period
550+
this
551+
def setMode(mode: Mode): this.type =
552+
util.Stats.record("Context.setMode")
553+
this.mode = mode
554+
this
555+
def setOwner(owner: Symbol): this.type =
556+
util.Stats.record("Context.setOwner")
557+
assert(owner != NoSymbol)
558+
this.owner = owner
559+
this
560+
def setTree(tree: Tree[? >: Untyped]): this.type =
561+
util.Stats.record("Context.setTree")
562+
this.tree = tree
563+
this
546564
def setScope(scope: Scope): this.type = { this.scope = scope; this }
547-
def setNewScope: this.type = { this.scope = newScope; this }
565+
def setNewScope: this.type =
566+
util.Stats.record("Context.setScope")
567+
this.scope = newScope
568+
this
548569
def setTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this }
549570
def setNewTyperState(): this.type = setTyperState(typerState.fresh().setCommittable(true))
550571
def setExploreTyperState(): this.type = setTyperState(typerState.fresh().setCommittable(false))
551572
def setReporter(reporter: Reporter): this.type = setTyperState(typerState.fresh().setReporter(reporter))
552-
def setTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this }
573+
def setTypeAssigner(typeAssigner: TypeAssigner): this.type =
574+
util.Stats.record("Context.setTypeAssigner")
575+
this.typeAssigner = typeAssigner
576+
this
553577
def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) }
554-
def setGadt(gadt: GadtConstraint): this.type = { this.gadt = gadt; this }
578+
def setGadt(gadt: GadtConstraint): this.type =
579+
util.Stats.record("Context.setGadt")
580+
this.gadt = gadt
581+
this
555582
def setFreshGADTBounds: this.type = setGadt(gadt.fresh)
556-
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
557-
def setSource(source: SourceFile): this.type = { this.source = source; this }
583+
def setSearchHistory(searchHistory: SearchHistory): this.type =
584+
util.Stats.record("Context.setSearchHistory")
585+
this.searchHistory = searchHistory
586+
this
587+
def setSource(source: SourceFile): this.type =
588+
util.Stats.record("Context.setSource")
589+
this.source = source
590+
this
558591
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
559-
private def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type = { this.moreProperties = moreProperties; this }
560-
private def setStore(store: Store): this.type = { this.store = store; this }
592+
private def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type =
593+
util.Stats.record("Context.setMoreProperties")
594+
this.moreProperties = moreProperties
595+
this
596+
private def setStore(store: Store): this.type =
597+
util.Stats.record("Context.setStore")
598+
this.store = store
599+
this
561600
def setImplicits(implicits: ContextualImplicits): this.type = { this.implicitsCache = implicits; this }
562601

563602
def setCompilationUnit(compilationUnit: CompilationUnit): this.type = {
@@ -632,14 +671,42 @@ object Contexts {
632671
final def retractMode(mode: Mode): c.type = c.setMode(c.mode &~ mode)
633672
}
634673

674+
/** Test `op` in a fresh context with a typerstate that is not committable.
675+
* The passed context may not survive the operation.
676+
*/
677+
def explore[T](op: Context ?=> T)(using Context): T =
678+
util.Stats.record("Context.test")
679+
val base = ctx.base
680+
import base._
681+
val nestedCtx =
682+
if testsInUse < testContexts.size then
683+
testContexts(testsInUse).reuseIn(ctx)
684+
else
685+
val ts = TyperState()
686+
.setReporter(TestingReporter())
687+
.setCommittable(false)
688+
val c = FreshContext(ctx.base).init(ctx, ctx).setTyperState(ts)
689+
testContexts += c
690+
c
691+
testsInUse += 1
692+
val nestedTS = nestedCtx.typerState
693+
nestedTS.init(ctx.typerState, ctx.typerState.constraint)
694+
val result =
695+
try op(using nestedCtx)
696+
finally
697+
nestedTS.reporter.asInstanceOf[TestingReporter].reset()
698+
testsInUse -= 1
699+
result
700+
end explore
701+
635702
/** A class defining the initial context with given context base
636703
* and set of possible settings.
637704
*/
638705
private class InitialContext(base: ContextBase, settingsGroup: SettingGroup) extends FreshContext(base) {
639706
outer = NoContext
640707
period = InitialPeriod
641708
mode = Mode.None
642-
typerState = new TyperState(null)
709+
typerState = TyperState.initialState()
643710
owner = NoSymbol
644711
tree = untpd.EmptyTree
645712
typeAssigner = TypeAssigner
@@ -785,6 +852,9 @@ object Contexts {
785852

786853
protected[dotc] val indentTab: String = " "
787854

855+
private[dotc] val testContexts = new mutable.ArrayBuffer[FreshContext]
856+
private[dotc] var testsInUse: Int = 0
857+
788858
def reset(): Unit = {
789859
for ((_, set) <- uniqueSets) set.clear()
790860
errorTypeMsg.clear()

compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -640,14 +640,6 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
640640
upperMap.foreachBinding((_, paramss) => paramss.foreach(_.foreach(checkClosedType(_, "upper"))))
641641
end checkClosed
642642

643-
// ---------- Invalidation -------------------------------------------
644-
645-
private var retracted = false
646-
647-
def isRetracted: Boolean = retracted
648-
649-
def markRetracted(): Unit = retracted = true
650-
651643
// ---------- toText -----------------------------------------------------
652644

653645
override def toText(printer: Printer): Text = {

compiler/src/dotty/tools/dotc/core/Scopes.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,9 @@ object Scopes {
192192
extends Scope {
193193

194194
/** Scope shares elements with `base` */
195-
protected[Scopes] def this(base: Scope)(using Context) = {
195+
protected[Scopes] def this(base: Scope)(using Context) =
196196
this(base.lastEntry, base.size, base.nestingLevel + 1)
197197
ensureCapacity(MinHashedScopeSize)
198-
}
199198

200199
def this() = this(null, 0, 0)
201200

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,19 +1133,19 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
11331133
if (recCount >= Config.LogPendingSubTypesThreshold) monitored = true
11341134
val result = if (monitored) monitoredIsSubType else firstTry
11351135
recCount = recCount - 1
1136-
if (!result) state.resetConstraintTo(saved)
1137-
else if (recCount == 0 && needsGc) {
1136+
if !result then
1137+
state.constraint = saved
1138+
else if recCount == 0 && needsGc then
11381139
state.gc()
11391140
needsGc = false
1140-
}
11411141
if (Stats.monitored) recordStatistics(result, savedSuccessCount)
11421142
result
11431143
}
11441144
catch {
11451145
case NonFatal(ex) =>
11461146
if (ex.isInstanceOf[AssertionError]) showGoal(tp1, tp2)
11471147
recCount -= 1
1148-
state.resetConstraintTo(saved)
1148+
state.constraint = saved
11491149
successCount = savedSuccessCount
11501150
throw ex
11511151
}

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import typer.ProtoTypes._
2020
import typer.ForceDegree
2121
import typer.Inferencing._
2222
import typer.IfBottom
23+
import reporting.TestingReporter
2324

2425
import scala.annotation.internal.sharable
2526
import scala.annotation.threadUnsafe

0 commit comments

Comments
 (0)