Skip to content

Commit c640a35

Browse files
committed
Make more contexts Ctx instances
- outer of a Ctx - fresh in a Ctx - ContextOps extension methods now all yield Ctx.
1 parent 8257e8a commit c640a35

36 files changed

+164
-103
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class Compiler {
147147
reset()
148148
val rctx =
149149
if ctx.settings.Ysemanticdb.value
150-
currentContext.addMode(Mode.ReadPositions)
150+
currentContext.withAddedMode(Mode.ReadPositions)
151151
else
152152
currentContext
153153
new Run(this, rctx)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
200200
profiler.finished()
201201
}
202202

203-
val runCtx = ctx.fresh
203+
val runCtx = currentContext.fresh
204204
runCtx.setProfiler(Profiler())
205205
unfusedPhases.foreach(_.initContext(runCtx))
206206
runPhases(using runCtx)

compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class TreeMapWithImplicits extends tpd.TreeMap {
6060
traverse(stats)
6161
}
6262

63-
private def nestedScopeCtx(defs: List[Tree])(using Ctx, CState): Context = {
63+
private def nestedScopeCtx(defs: List[Tree])(using Ctx, CState): Ctx = {
6464
val nestedCtx = ctx.fresh.setNewScope
6565
defs foreach {
6666
case d: DefTree if d.symbol.isOneOf(GivenOrImplicit) => nestedCtx.enter(d.symbol)
@@ -69,7 +69,7 @@ class TreeMapWithImplicits extends tpd.TreeMap {
6969
nestedCtx
7070
}
7171

72-
private def patternScopeCtx(pattern: Tree)(using Ctx, CState): Context = {
72+
private def patternScopeCtx(pattern: Tree)(using Ctx, CState): Ctx = {
7373
val nestedCtx = ctx.fresh.setNewScope
7474
new TreeTraverser {
7575
def traverse(tree: Tree)(using Ctx, CState): Unit = {

compiler/src/dotty/tools/dotc/ast/tpd.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
12231223
* EmptyTree calls (for parameters) cancel the next-enclosing call in the list instead of being added to it.
12241224
* We assume parameters are never nested inside parameters.
12251225
*/
1226-
override def inlineContext(call: Tree)(using Ctx, CState): Context = {
1226+
override def inlineContext(call: Tree)(using Ctx, CState): Ctx = {
12271227
// We assume enclosingInlineds is already normalized, and only process the new call with the head.
12281228
val oldIC = enclosingInlineds
12291229

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

+9-9
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,22 @@ object ContextOps:
6464
* Owner might not exist (can happen for self valdefs), in which case
6565
* no owner is set in result context
6666
*/
67-
def localContext(tree: untpd.Tree, owner: Symbol)(using CState): FreshContext =
67+
def localContext(tree: untpd.Tree, owner: Symbol)(using CState): FreshCtx =
6868
given Ctx = ctx
6969
val freshCtx = fresh.setTree(tree)
7070
if (owner.exists) freshCtx.setOwner(owner) else freshCtx
7171

7272
/** A new context for the interior of a class */
73-
def inClassContext(selfInfo: TypeOrSymbol)(using CState): Context =
73+
def inClassContext(selfInfo: TypeOrSymbol)(using CState): Ctx =
7474
given Ctx = ctx
75-
val localCtx: Context = fresh.setNewScope
75+
val localCtx = fresh.setNewScope
7676
selfInfo match {
7777
case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => localCtx.scope.openForMutations.enter(sym)
7878
case _ =>
7979
}
8080
localCtx
8181

82-
def packageContext(tree: untpd.PackageDef, pkg: Symbol)(using CState): Context =
82+
def packageContext(tree: untpd.PackageDef, pkg: Symbol)(using CState): Ctx =
8383
given Ctx = ctx
8484
if (pkg.is(Package)) fresh.setOwner(pkg.moduleClass).setTree(tree)
8585
else combinedContext
@@ -104,7 +104,7 @@ object ContextOps:
104104
* context see the constructor parameters instead, but then we'd need a final substitution step
105105
* from constructor parameters to class parameter accessors.
106106
*/
107-
def superCallContext(using CState): Context =
107+
def superCallContext(using CState): Ctx =
108108
given Ctx = ctx
109109
val locals = newScopeWith(owner.typeParams ++ owner.asClass.paramAccessors: _*)
110110
superOrThisCallContext(owner.primaryConstructor, locals)
@@ -117,7 +117,7 @@ object ContextOps:
117117
* - as outer context: The context enclosing the enclosing class context
118118
* - as scope: The parameters of the auxiliary constructor.
119119
*/
120-
def thisCallArgContext(using CState): Context =
120+
def thisCallArgContext(using CState): Ctx =
121121
given Ctx = ctx
122122
val constrCtx = outersIterator.dropWhile(_.outer.owner == owner).next()
123123
superOrThisCallContext(owner, constrCtx.scope)
@@ -127,22 +127,22 @@ object ContextOps:
127127
.setScope(ctx.scope)
128128

129129
/** The super- or this-call context with given owner and locals. */
130-
def superOrThisCallContext(owner: Symbol, locals: Scope)(using CState): FreshContext =
130+
def superOrThisCallContext(owner: Symbol, locals: Scope)(using CState): FreshCtx =
131131
given Ctx = ctx
132132
var classCtx = ctx.outersIterator.dropWhile(!_.isClassDefContext).next()
133133
classCtx.outer.fresh.setOwner(owner)
134134
.setScope(locals)
135135
.setMode(classCtx.mode)
136136

137137
/** The context of expression `expr` seen as a member of a statement sequence */
138-
def exprContext(stat: Tree[? >: Untyped], exprOwner: Symbol)(using CState): Context =
138+
def exprContext(stat: Tree[? >: Untyped], exprOwner: Symbol)(using CState): Ctx =
139139
given Ctx = ctx
140140
if (exprOwner == ctx.owner) combinedContext
141141
else if (untpd.isSuperConstrCall(stat) && ctx.owner.isClass) superCallContext
142142
else fresh.setOwner(exprOwner)
143143

144144
/** A new context that summarizes an import statement */
145-
def importContext(imp: Import[?], sym: Symbol)(using CState): FreshContext =
145+
def importContext(imp: Import[?], sym: Symbol)(using CState): FreshCtx =
146146
given Ctx = ctx
147147
val impNameOpt = imp.expr match {
148148
case ref: RefTree[?] => Some(ref.name.asTermName)

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

+81-20
Original file line numberDiff line numberDiff line change
@@ -172,19 +172,66 @@ object Contexts {
172172
def uniqueNamedTypes: Uniques.NamedTypeUniques
173173
def uniques: util.HashSet[Type]
174174

175-
def fresh: FreshContext
176-
def freshOver(outer: Context): FreshContext
175+
def fresh: FreshCtx
176+
def freshOver(outer: Ctx): FreshCtx
177177

178178
def withPeriod(pd: Period): Context
179179
def withPhase(phaseId: PhaseId): Context
180180
def withPhase(phase: Phase): Context
181181
def withOwner(owner: Symbol): Ctx
182182
def withSource(source: SourceFile): Ctx
183183
def withProperty[T](key: Key[T], value: Option[T]): Ctx
184+
def withAddedMode(mode: Mode): Ctx
185+
def withRetractedMode(mode: Mode): Ctx
186+
187+
def toContext(using cs: CState) = withPeriod(cs)
188+
189+
private[Contexts] def storedSourceCtx(source: SourceFile): Ctx
184190

185191
def toContextUNSAFE = asInstanceOf[Context]
186192
end Ctx
187193

194+
trait FreshCtx extends Ctx:
195+
def setPeriod(period: Period): this.type
196+
def setMode(mode: Mode): this.type
197+
def addMode(mode: Mode): this.type
198+
def retractMode(mode: Mode): this.type
199+
def setOwner(owner: Symbol): this.type
200+
def setTree(tree: Tree[? >: Untyped]): this.type
201+
def setScope(scope: Scope): this.type
202+
def setNewScope: this.type
203+
def setTyperState(typerState: TyperState): this.type
204+
def setNewTyperState(): this.type
205+
def setExploreTyperState(): this.type
206+
def setReporter(reporter: Reporter): this.type
207+
def setTypeAssigner(typeAssigner: TypeAssigner): this.type
208+
def setTyper(typer: Typer): this.type
209+
def setGadt(gadt: GadtConstraint): this.type
210+
def setFreshGADTBounds: this.type
211+
def setSearchHistory(searchHistory: SearchHistory): this.type
212+
def setSource(source: SourceFile): this.type
213+
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type
214+
def setImplicits(implicits: ContextualImplicits): this.type
215+
def setCompilationUnit(compilationUnit: CompilationUnit): this.type
216+
def setCompilerCallback(callback: CompilerCallback): this.type
217+
def setSbtCallback(callback: AnalysisCallback): this.type
218+
def setPrinterFn(printer: Context => Printer): this.type
219+
def setSettings(settingsState: SettingsState): this.type
220+
def setRun(run: Run): this.type
221+
def setProfiler(profiler: Profiler): this.type
222+
def setNotNullInfos(notNullInfos: List[NotNullInfo]): this.type
223+
def setImportInfo(importInfo: ImportInfo): this.type
224+
def setProperty[T](key: Key[T], value: T): this.type
225+
def dropProperty(key: Key[?]): this.type
226+
def addLocation[T](initial: T): Store.Location[T]
227+
def addLocation[T](): Store.Location[T]
228+
def updateStore[T](loc: Store.Location[T], value: T): this.type
229+
def setPhase(pid: PhaseId): this.type
230+
def setPhase(phase: Phase): this.type
231+
def setSetting[T](setting: Setting[T], value: T): this.type
232+
def setDebug: this.type
233+
end FreshCtx
234+
188235
/** A context is passed basically everywhere in dotc.
189236
* This is convenient but carries the risk of captured contexts in
190237
* objects that turn into space leaks. To combat this risk, here are some
@@ -210,16 +257,16 @@ object Contexts {
210257
protected given CState = cstate
211258

212259
/** All outer contexts, ending in `base.initialCtx` and then `NoContext` */
213-
def outersIterator: Iterator[Context] = new Iterator[Context] {
214-
var current = thiscontext
260+
def outersIterator: Iterator[Ctx] = new Iterator[Ctx] {
261+
var current: Ctx = thiscontext
215262
def hasNext = current != NoContext
216263
def next = { val c = current; current = current.outer; c }
217264
}
218265

219266
/** The outer context */
220-
private var _outer: Context = _
221-
protected def outer_=(outer: Context): Unit = _outer = outer
222-
final def outer: Context = _outer
267+
private var _outer: Ctx = _
268+
protected def outer_=(outer: Ctx): Unit = _outer = outer
269+
final def outer: Ctx = _outer
223270

224271
/** The current context */
225272
private var _period: Period = _
@@ -487,9 +534,12 @@ object Contexts {
487534
* @param outer The outer context
488535
* @param origin The context from which fields are copied
489536
*/
490-
private[Contexts] def init(outer: Context, origin: Context): this.type = {
537+
private[Contexts] def init(outer: Ctx, origin: Context): this.type =
538+
init(outer, origin, origin.cstate)
539+
540+
private[Contexts] def init(outer: Ctx, origin: Ctx, cstate: CState): this.type = {
491541
_outer = outer
492-
_period = origin.period
542+
_period = cstate
493543
_mode = origin.mode
494544
_owner = origin.owner
495545
_tree = origin.tree
@@ -514,20 +564,23 @@ object Contexts {
514564
def fresh: FreshContext = freshOver(this)
515565

516566
/** A fresh clone of this context embedded in the specified `outer` context. */
517-
def freshOver(outer: Context): FreshContext =
567+
def freshOver(outer: Ctx): FreshContext =
518568
util.Stats.record("Context.fresh")
519569
FreshContext(base).init(outer, this).setTyperState(this.typerState)
520570

521571
final def withOwner(owner: Symbol): Context =
522572
if (owner ne this.owner) fresh.setOwner(owner) else this
523573

524-
private var sourceCtx: SimpleIdentityMap[SourceFile, Context] = null
574+
private var sourceCtx: SimpleIdentityMap[SourceFile, Ctx] = null
575+
576+
private[Contexts] def storedSourceCtx(source: SourceFile): Ctx =
577+
if sourceCtx == null then null
578+
else sourceCtx(source)
525579

526-
final def withSource(source: SourceFile): Context =
527-
if (source `eq` this.source) this
528-
else if ((source `eq` outer.source) &&
529-
outer.sourceCtx != null &&
530-
(outer.sourceCtx(this.source) `eq` this)) outer
580+
final def withSource(source: SourceFile): Ctx =
581+
if source eq this.source then this
582+
else if (source eq outer.source)
583+
&& (outer.storedSourceCtx(this.source) eq this) then outer
531584
else {
532585
if (sourceCtx == null) sourceCtx = SimpleIdentityMap.Empty
533586
val prev = sourceCtx(source)
@@ -551,6 +604,12 @@ object Contexts {
551604
case None => fresh.dropProperty(key)
552605
}
553606

607+
private def withModeBits(mode: Mode): Context =
608+
if (mode != this.mode) fresh.setMode(mode) else this
609+
610+
def withAddedMode(mode: Mode): Context = withModeBits(this.mode | mode)
611+
def withRetractedMode(mode: Mode): Context = withModeBits(this.mode &~ mode)
612+
554613
def typer: Typer = this.typeAssigner match {
555614
case typer: Typer => typer
556615
case _ => new Typer
@@ -585,7 +644,7 @@ object Contexts {
585644
/** A fresh context allows selective modification
586645
* of its attributes using the with... methods.
587646
*/
588-
class FreshContext(base: ContextBase) extends Context(base) {
647+
class FreshContext(base: ContextBase) extends Context(base), FreshCtx {
589648
def setPeriod(period: Period): this.type =
590649
util.Stats.record("Context.setPeriod")
591650
this.period = period
@@ -594,6 +653,8 @@ object Contexts {
594653
util.Stats.record("Context.setMode")
595654
this.mode = mode
596655
this
656+
final def addMode(mode: Mode): this.type = setMode(this.mode | mode)
657+
final def retractMode(mode: Mode): this.type = setMode(this.mode &~ mode)
597658
def setOwner(owner: Symbol): this.type =
598659
util.Stats.record("Context.setOwner")
599660
assert(owner != NoSymbol)
@@ -696,7 +757,7 @@ object Contexts {
696757
def withNotNullInfos(infos: List[NotNullInfo])(using CState): Ctx =
697758
if c.notNullInfos eq infos then c else c.fresh.setNotNullInfos(infos)
698759
end ops
699-
760+
/*
700761
// TODO: Fix issue when converting ModeChanges and FreshModeChanges to extension givens
701762
implicit class ModeChanges(val c: Context) extends AnyVal {
702763
final def withModeBits(mode: Mode): Context =
@@ -710,7 +771,7 @@ object Contexts {
710771
final def addMode(mode: Mode): c.type = c.setMode(c.mode | mode)
711772
final def retractMode(mode: Mode): c.type = c.setMode(c.mode &~ mode)
712773
}
713-
774+
*/
714775
/** Test `op` in a fresh context with a typerstate that is not committable.
715776
* The passed context may not survive the operation.
716777
*/
@@ -725,7 +786,7 @@ object Contexts {
725786
val ts = TyperState()
726787
.setReporter(TestingReporter())
727788
.setCommittable(false)
728-
val c = FreshContext(ctx.base).init(ctx.toContextUNSAFE, ctx.toContextUNSAFE).setTyperState(ts)
789+
val c = FreshContext(ctx.base).init(ctx, ctx, currentPeriod).setTyperState(ts)
729790
testContexts += c
730791
c
731792
testsInUse += 1

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,10 @@ object Phases {
291291
/** @pre `isRunnable` returns true */
292292
def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
293293
units.map { unit =>
294-
val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit)
295-
assert(unitCtx.compilationUnit != null)
296-
run(using unitCtx, unitCtx.cstate)
297-
unitCtx.compilationUnit
294+
val unitContext = currentContext.fresh.setPhase(this.start).setCompilationUnit(unit)
295+
assert(unitContext.compilationUnit != null)
296+
run(using unitContext, unitContext.cstate)
297+
unitContext.compilationUnit
298298
}
299299

300300
def description: String = phaseName
@@ -326,7 +326,7 @@ object Phases {
326326

327327
def exists: Boolean = true
328328

329-
def initContext(ctx: FreshContext): Unit = ()
329+
def initContext(ctx: FreshCtx): Unit = ()
330330

331331
private var myPeriod: Period = Periods.InvalidPeriod
332332
private var myBase: ContextBase = null

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ object StagingContext {
2828
ctx.property(QuotationLevel).getOrElse(0)
2929

3030
/** Context with an incremented quotation level. */
31-
def quoteContext(using Ctx, CState): Context =
31+
def quoteContext(using Ctx, CState): Ctx =
3232
ctx.fresh.setProperty(QuotationLevel, level + 1)
3333

3434
/** Context with an incremented quotation level and pushes a refecence to a QuoteContext on the quote context stack */
35-
def pushQuoteContext(qctxRef: tpd.Tree)(using Ctx, CState): Context =
35+
def pushQuoteContext(qctxRef: tpd.Tree)(using Ctx, CState): Ctx =
3636
val old = ctx.property(QuoteContextStack).getOrElse(List.empty)
3737
ctx.fresh.setProperty(QuotationLevel, level + 1)
3838
.setProperty(QuoteContextStack, qctxRef :: old)
3939

4040
/** Context with a decremented quotation level. */
41-
def spliceContext(using Ctx, CState): Context =
41+
def spliceContext(using Ctx, CState): Ctx =
4242
ctx.fresh.setProperty(QuotationLevel, level - 1)
4343

4444
def contextWithQuoteTypeTags(taggedTypes: PCPCheckAndHeal.QuoteTypeTags)(using Ctx, CState) =
@@ -50,7 +50,7 @@ object StagingContext {
5050
/** Context with a decremented quotation level and pops the Some of top of the quote context stack or None if the stack is empty.
5151
* The quotation stack could be empty if we are in a top level splice or an eroneous splice directly witin a top level splice.
5252
*/
53-
def popQuoteContext()(using Ctx, CState): (Option[tpd.Tree], Context) =
53+
def popQuoteContext()(using Ctx, CState): (Option[tpd.Tree], Ctx) =
5454
val ctx1 = ctx.fresh.setProperty(QuotationLevel, level - 1)
5555
val head =
5656
ctx.property(QuoteContextStack) match

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ object TypeOps:
636636

637637
val childTp = if (child.isTerm) child.termRef else child.typeRef
638638

639-
inContext(ctx.fresh.setExploreTyperState().setFreshGADTBounds) {
639+
inCtx(ctx.fresh.setExploreTyperState().setFreshGADTBounds) {
640640
instantiateToSubType(childTp, parent).dealias
641641
}
642642
}
@@ -725,7 +725,7 @@ object TypeOps:
725725
// we manually patch subtyping check instead of changing TypeComparer.
726726
// See tests/patmat/i3645b.scala
727727
def parentQualify = tp1.widen.classSymbol.info.parents.exists { parent =>
728-
inContext(ctx.fresh.setNewTyperState()) {
728+
inCtx(ctx.fresh.setNewTyperState()) {
729729
parent.argInfos.nonEmpty && minTypeMap.apply(parent) <:< maxTypeMap.apply(tp2)
730730
}
731731
}

0 commit comments

Comments
 (0)