Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
.setOwner(defn.RootClass)
.setTyper(new Typer)
.addMode(Mode.ImplicitsEnabled)
.setTyperState(new TyperState(ctx.typerState))
.setTyperState(ctx.typerState.fresh(ctx.reporter))
ctx.initialize()(using start) // re-initialize the base context with start
def addImport(ctx: Context, rootRef: ImportInfo.RootRef) =
ctx.fresh.setImportInfo(ImportInfo.rootImport(rootRef))
Expand Down
6 changes: 0 additions & 6 deletions compiler/src/dotty/tools/dotc/core/Constraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,4 @@ abstract class Constraint extends Showable {

/** Check that constraint only refers to TypeParamRefs bound by itself */
def checkClosed()(using Context): Unit

/** Constraint has not yet been retracted from a typer state */
def isRetracted: Boolean

/** Indicate that constraint has been retracted from a typer state */
def markRetracted(): Unit
}
133 changes: 102 additions & 31 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ object Contexts {
private val (runLoc, store6) = store5.newLocation[Run]()
private val (profilerLoc, store7) = store6.newLocation[Profiler]()
private val (notNullInfosLoc, store8) = store7.newLocation[List[NotNullInfo]]()
private val initialStore = store8
private val (importInfoLoc, store9) = store8.newLocation[ImportInfo]()

private val initialStore = store9

/** The current context */
inline def ctx(using ctx: Context): Context = ctx
Expand Down Expand Up @@ -156,11 +158,6 @@ object Contexts {
protected def typeAssigner_=(typeAssigner: TypeAssigner): Unit = _typeAssigner = typeAssigner
final def typeAssigner: TypeAssigner = _typeAssigner

/** The currently active import info */
private var _importInfo: ImportInfo = _
protected def importInfo_=(importInfo: ImportInfo): Unit = _importInfo = importInfo
final def importInfo: ImportInfo = _importInfo

/** The current bounds in force for type parameters appearing in a GADT */
private var _gadt: GadtConstraint = _
protected def gadt_=(gadt: GadtConstraint): Unit = _gadt = gadt
Expand Down Expand Up @@ -230,6 +227,9 @@ object Contexts {
/** The paths currently known to be not null */
def notNullInfos = store(notNullInfosLoc)

/** The currently active import info */
def importInfo = store(importInfoLoc)

/** The new implicit references that are introduced by this scope */
protected var implicitsCache: ContextualImplicits = null
def implicits: ContextualImplicits = {
Expand Down Expand Up @@ -286,7 +286,7 @@ object Contexts {
* contexts are created only on request and cached in this array
*/
private var phasedCtx: Context = this
private var phasedCtxs: Array[Context] = _
private var phasedCtxs: Array[Context] = null

/** This context at given phase.
* This method will always return a phase period equal to phaseId, thus will never return squashed phases
Expand Down Expand Up @@ -340,18 +340,15 @@ object Contexts {
/** The current reporter */
def reporter: Reporter = typerState.reporter

/** Run `op` as if it was run in a fresh explore typer state, but possibly
* optimized to re-use the current typer state.
*/
final def test[T](op: Context ?=> T): T = typerState.test(op)(using this)

/** Is this a context for the members of a class definition? */
def isClassDefContext: Boolean =
owner.isClass && (owner ne outer.owner)

/** Is this a context that introduces an import clause? */
def isImportContext: Boolean =
(this ne NoContext) && (this.importInfo ne outer.importInfo)
(this ne NoContext)
&& (outer ne NoContext)
&& (this.importInfo ne outer.importInfo)

/** Is this a context that introduces a non-empty scope? */
def isNonEmptyScopeContext: Boolean =
Expand Down Expand Up @@ -451,17 +448,18 @@ object Contexts {
/** Is the explicit nulls option set? */
def explicitNulls: Boolean = base.settings.YexplicitNulls.value

protected def init(outer: Context, origin: Context): this.type = {
util.Stats.record("Context.fresh")
/** Initialize all context fields, except typerState, which has to be set separately
* @param outer The outer context
* @param origin The context from which fields are copied
*/
private[Contexts] def init(outer: Context, origin: Context): this.type = {
_outer = outer
_period = origin.period
_mode = origin.mode
_owner = origin.owner
_tree = origin.tree
_scope = origin.scope
_typerState = origin.typerState
_typeAssigner = origin.typeAssigner
_importInfo = origin.importInfo
_gadt = origin.gadt
_searchHistory = origin.searchHistory
_typeComparer = origin.typeComparer
Expand All @@ -471,11 +469,19 @@ object Contexts {
this
}

def reuseIn(outer: Context): this.type =
implicitsCache = null
phasedCtxs = null
sourceCtx = null
Comment on lines +473 to +475
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be done in init, that way we only have one correct way to initialize things, no matter if it's the first or a latter initialization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it here in order to avoid the additional stores in init. We already have

implicitsCache = null 

in the definition. I assume that the JVM will be smart enough to avoid the store since the object is pre-initialzied to zeroes anyway. But i don't think it can avoid the store in a separate initializer method.

init(outer, outer)

/** A fresh clone of this context embedded in this context. */
def fresh: FreshContext = freshOver(this)

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

final def withOwner(owner: Symbol): Context =
if (owner ne this.owner) fresh.setOwner(owner) else this
Expand Down Expand Up @@ -538,26 +544,59 @@ object Contexts {
* of its attributes using the with... methods.
*/
class FreshContext(base: ContextBase) extends Context(base) {
def setPeriod(period: Period): this.type = { this.period = period; this }
def setMode(mode: Mode): this.type = { this.mode = mode; this }
def setOwner(owner: Symbol): this.type = { assert(owner != NoSymbol); this.owner = owner; this }
def setTree(tree: Tree[? >: Untyped]): this.type = { this.tree = tree; this }
def setPeriod(period: Period): this.type =
util.Stats.record("Context.setPeriod")
this.period = period
this
def setMode(mode: Mode): this.type =
util.Stats.record("Context.setMode")
this.mode = mode
this
def setOwner(owner: Symbol): this.type =
util.Stats.record("Context.setOwner")
assert(owner != NoSymbol)
this.owner = owner
this
def setTree(tree: Tree[? >: Untyped]): this.type =
util.Stats.record("Context.setTree")
this.tree = tree
this
def setScope(scope: Scope): this.type = { this.scope = scope; this }
def setNewScope: this.type = { this.scope = newScope; this }
def setNewScope: this.type =
util.Stats.record("Context.setScope")
this.scope = newScope
this
def setTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this }
def setNewTyperState(): this.type = setTyperState(typerState.fresh().setCommittable(true))
def setExploreTyperState(): this.type = setTyperState(typerState.fresh().setCommittable(false))
def setReporter(reporter: Reporter): this.type = setTyperState(typerState.fresh().setReporter(reporter))
def setTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this }
def setTypeAssigner(typeAssigner: TypeAssigner): this.type =
util.Stats.record("Context.setTypeAssigner")
this.typeAssigner = typeAssigner
this
def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) }
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
def setGadt(gadt: GadtConstraint): this.type = { this.gadt = gadt; this }
def setGadt(gadt: GadtConstraint): this.type =
util.Stats.record("Context.setGadt")
this.gadt = gadt
this
def setFreshGADTBounds: this.type = setGadt(gadt.fresh)
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
def setSource(source: SourceFile): this.type = { this.source = source; this }
def setSearchHistory(searchHistory: SearchHistory): this.type =
util.Stats.record("Context.setSearchHistory")
this.searchHistory = searchHistory
this
def setSource(source: SourceFile): this.type =
util.Stats.record("Context.setSource")
this.source = source
this
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
private def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type = { this.moreProperties = moreProperties; this }
private def setStore(store: Store): this.type = { this.store = store; this }
private def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type =
util.Stats.record("Context.setMoreProperties")
this.moreProperties = moreProperties
this
private def setStore(store: Store): this.type =
util.Stats.record("Context.setStore")
this.store = store
this
def setImplicits(implicits: ContextualImplicits): this.type = { this.implicitsCache = implicits; this }

def setCompilationUnit(compilationUnit: CompilationUnit): this.type = {
Expand All @@ -572,6 +611,7 @@ object Contexts {
def setRun(run: Run): this.type = updateStore(runLoc, run)
def setProfiler(profiler: Profiler): this.type = updateStore(profilerLoc, profiler)
def setNotNullInfos(notNullInfos: List[NotNullInfo]): this.type = updateStore(notNullInfosLoc, notNullInfos)
def setImportInfo(importInfo: ImportInfo): this.type = updateStore(importInfoLoc, importInfo)

def setProperty[T](key: Key[T], value: T): this.type =
setMoreProperties(moreProperties.updated(key, value))
Expand Down Expand Up @@ -629,14 +669,42 @@ object Contexts {
final def retractMode(mode: Mode): c.type = c.setMode(c.mode &~ mode)
}

/** Test `op` in a fresh context with a typerstate that is not committable.
* The passed context may not survive the operation.
*/
def explore[T](op: Context ?=> T)(using Context): T =
util.Stats.record("Context.test")
val base = ctx.base
import base._
val nestedCtx =
if testsInUse < testContexts.size then
testContexts(testsInUse).reuseIn(ctx)
else
val ts = TyperState()
.setReporter(TestingReporter())
.setCommittable(false)
val c = FreshContext(ctx.base).init(ctx, ctx).setTyperState(ts)
testContexts += c
c
testsInUse += 1
val nestedTS = nestedCtx.typerState
nestedTS.init(ctx.typerState, ctx.typerState.constraint)
val result =
try op(using nestedCtx)
finally
nestedTS.reporter.asInstanceOf[TestingReporter].reset()
testsInUse -= 1
result
end explore

/** A class defining the initial context with given context base
* and set of possible settings.
*/
private class InitialContext(base: ContextBase, settingsGroup: SettingGroup) extends FreshContext(base) {
outer = NoContext
period = InitialPeriod
mode = Mode.None
typerState = new TyperState(null)
typerState = TyperState.initialState()
owner = NoSymbol
tree = untpd.EmptyTree
typeAssigner = TypeAssigner
Expand Down Expand Up @@ -782,6 +850,9 @@ object Contexts {

protected[dotc] val indentTab: String = " "

private[dotc] val testContexts = new mutable.ArrayBuffer[FreshContext]
private[dotc] var testsInUse: Int = 0

def reset(): Unit = {
for ((_, set) <- uniqueSets) set.clear()
errorTypeMsg.clear()
Expand Down
8 changes: 0 additions & 8 deletions compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -640,14 +640,6 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
upperMap.foreachBinding((_, paramss) => paramss.foreach(_.foreach(checkClosedType(_, "upper"))))
end checkClosed

// ---------- Invalidation -------------------------------------------

private var retracted = false

def isRetracted: Boolean = retracted

def markRetracted(): Unit = retracted = true

// ---------- toText -----------------------------------------------------

override def toText(printer: Printer): Text = {
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/core/Scopes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,9 @@ object Scopes {
extends Scope {

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

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

Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -477,25 +477,29 @@ object Symbols {

/** Set the denotation of this symbol */
private[core] def denot_=(d: SymDenotation): Unit = {
util.Stats.record("Symbol.denot_=")
lastDenot = d
checkedPeriod = Nowhere
}

/** The current denotation of this symbol */
final def denot(using Context): SymDenotation = {
util.Stats.record("Symbol.denot")
val lastd = lastDenot
if (checkedPeriod == ctx.period) lastd
else computeDenot(lastd)
}

private def computeDenot(lastd: SymDenotation)(using Context): SymDenotation = {
util.Stats.record("Symbol.computeDenot")
val now = ctx.period
checkedPeriod = now
if (lastd.validFor contains now) lastd else recomputeDenot(lastd)
}

/** Overridden in NoSymbol */
protected def recomputeDenot(lastd: SymDenotation)(using Context): SymDenotation = {
util.Stats.record("Symbol.recomputeDenot")
val newd = lastd.current.asInstanceOf[SymDenotation]
lastDenot = newd
newd
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1133,19 +1133,19 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
if (recCount >= Config.LogPendingSubTypesThreshold) monitored = true
val result = if (monitored) monitoredIsSubType else firstTry
recCount = recCount - 1
if (!result) state.resetConstraintTo(saved)
else if (recCount == 0 && needsGc) {
if !result then
state.constraint = saved
else if recCount == 0 && needsGc then
state.gc()
needsGc = false
}
if (Stats.monitored) recordStatistics(result, savedSuccessCount)
result
}
catch {
case NonFatal(ex) =>
if (ex.isInstanceOf[AssertionError]) showGoal(tp1, tp2)
recCount -= 1
state.resetConstraintTo(saved)
state.constraint = saved
successCount = savedSuccessCount
throw ex
}
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import typer.ProtoTypes._
import typer.ForceDegree
import typer.Inferencing._
import typer.IfBottom
import reporting.TestingReporter

import scala.annotation.internal.sharable
import scala.annotation.threadUnsafe
Expand Down
Loading