Skip to content

Avoid Context#clone #6029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 57 additions & 47 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,20 @@ object Contexts {
* of all class fields of type context; allow them only in whitelisted
* classes (which should be short-lived).
*/
abstract class Context extends Periods
with Substituters
with TypeOps
with Phases
with Printers
with Symbols
with SymDenotations
with Reporting
with NamerContextOps
with Plugins
with Cloneable { thiscontext =>
implicit def ctx: Context = this
abstract class Context(val base: ContextBase)
extends Periods
with Substituters
with TypeOps
with Phases
with Printers
with Symbols
with SymDenotations
with Reporting
with NamerContextOps
with Plugins
with Cloneable { thiscontext =>

/** The context base at the root */
val base: ContextBase
implicit def ctx: Context = this

/** All outer contexts, ending in `base.initialCtx` and then `NoContext` */
def outersIterator: Iterator[Context] = new Iterator[Context] {
Expand All @@ -94,83 +93,85 @@ object Contexts {
/** The outer context */
private[this] var _outer: Context = _
protected def outer_=(outer: Context): Unit = _outer = outer
def outer: Context = _outer
final def outer: Context = _outer

/** The current context */
private[this] var _period: Period = _
protected def period_=(period: Period): Unit = {
assert(period.firstPhaseId == period.lastPhaseId, period)
_period = period
}
def period: Period = _period
final def period: Period = _period

/** The scope nesting level */
private[this] var _mode: Mode = _
protected def mode_=(mode: Mode): Unit = _mode = mode
def mode: Mode = _mode
final def mode: Mode = _mode

/** The current owner symbol */
private[this] var _owner: Symbol = _
protected def owner_=(owner: Symbol): Unit = _owner = owner
def owner: Symbol = _owner
final def owner: Symbol = _owner

/** The current tree */
private[this] var _tree: Tree[_ >: Untyped]= _
protected def tree_=(tree: Tree[_ >: Untyped]): Unit = _tree = tree
def tree: Tree[_ >: Untyped] = _tree
final def tree: Tree[_ >: Untyped] = _tree

/** The current scope */
private[this] var _scope: Scope = _
protected def scope_=(scope: Scope): Unit = _scope = scope
def scope: Scope = _scope
final def scope: Scope = _scope

/** The current type comparer */
private[this] var _typerState: TyperState = _
protected def typerState_=(typerState: TyperState): Unit = _typerState = typerState
def typerState: TyperState = _typerState
final def typerState: TyperState = _typerState

/** The current type assigner or typer */
private[this] var _typeAssigner: TypeAssigner = _
protected def typeAssigner_=(typeAssigner: TypeAssigner): Unit = _typeAssigner = typeAssigner
def typeAssigner: TypeAssigner = _typeAssigner
final def typeAssigner: TypeAssigner = _typeAssigner

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

/** The current bounds in force for type parameters appearing in a GADT */
private[this] var _gadt: GADTMap = _
protected def gadt_=(gadt: GADTMap): Unit = _gadt = gadt
def gadt: GADTMap = _gadt
final def gadt: GADTMap = _gadt

/** The history of implicit searches that are currently active */
private[this] var _searchHistory: SearchHistory = null
protected def searchHistory_= (searchHistory: SearchHistory): Unit = _searchHistory = searchHistory
def searchHistory: SearchHistory = _searchHistory
final def searchHistory: SearchHistory = _searchHistory

/** The current type comparer. This ones updates itself automatically for
* each new context.
*/
private[this] var _typeComparer: TypeComparer = _
protected def typeComparer_=(typeComparer: TypeComparer): Unit = _typeComparer = typeComparer
def typeComparer: TypeComparer = {
if (_typeComparer.ctx ne this)
_typeComparer = _typeComparer.copyIn(this)
private[this] var _typeComparer: TypeComparer = null
protected def typeComparer_=(typeComparer: TypeComparer): Unit = {
assert(typeComparer.ctx eq this)
_typeComparer = typeComparer
}
final def typeComparer: TypeComparer = {
if (_typeComparer == null) _typeComparer = outer.typeComparer.copyIn(this)
_typeComparer
}

/** The current source file */
private[this] var _source: SourceFile = _
protected def source_=(source: SourceFile): Unit = _source = source
def source: SourceFile = _source
final def source: SourceFile = _source

/** A map in which more contextual properties can be stored
* Typically used for attributes that are read and written only in special situations.
*/
private[this] var _moreProperties: Map[Key[Any], Any] = _
protected def moreProperties_=(moreProperties: Map[Key[Any], Any]): Unit = _moreProperties = moreProperties
def moreProperties: Map[Key[Any], Any] = _moreProperties
final def moreProperties: Map[Key[Any], Any] = _moreProperties

def property[T](key: Key[T]): Option[T] =
moreProperties.get(key).asInstanceOf[Option[T]]
Expand All @@ -182,7 +183,7 @@ object Contexts {
*/
private var _store: Store = _
protected def store_=(store: Store): Unit = _store = store
def store: Store = _store
final def store: Store = _store

/** The compiler callback implementation, or null if no callback will be called. */
def compilerCallback: CompilerCallback = store(compilerCallbackLoc)
Expand Down Expand Up @@ -258,7 +259,7 @@ object Contexts {
* phasedCtxs is array that uses phaseId's as indexes,
* contexts are created only on request and cached in this array
*/
private[this] var phasedCtx: Context = _
private[this] var phasedCtx: Context = this
private[this] var phasedCtxs: Array[Context] = _

/** This context at given phase.
Expand Down Expand Up @@ -422,18 +423,28 @@ object Contexts {
base.settings.color.value == "always"

protected def init(outer: Context): this.type = {
this.outer = outer
this.implicitsCache = null
this.phasedCtx = this
this.phasedCtxs = null
this.sourceCtx = null
// See comment related to `creationTrace` in this file
// setCreationTrace()
_outer = outer
_period = outer.period
_mode = outer.mode
_owner = outer.owner
_tree = outer.tree
_scope = outer.scope
_typerState = outer.typerState
_typeAssigner = outer.typeAssigner
_importInfo = outer.importInfo
_gadt = outer.gadt
_searchHistory = outer.searchHistory
_source = outer.source
_moreProperties = outer.moreProperties
_store = outer.store
this
}

/** A fresh clone of this context. */
def fresh: FreshContext = clone.asInstanceOf[FreshContext].init(this)
def fresh: FreshContext = {
util.Stats.record("Context.fresh")
new FreshContext(base).init(this)
}

final def withOwner(owner: Symbol): Context =
if (owner ne this.owner) fresh.setOwner(owner) else this
Expand Down Expand Up @@ -508,7 +519,7 @@ object Contexts {
/** A fresh context allows selective modification
* of its attributes using the with... methods.
*/
abstract class FreshContext extends Context {
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 }
Expand Down Expand Up @@ -592,7 +603,7 @@ object Contexts {
/** A class defining the initial context with given context base
* and set of possible settings.
*/
private class InitialContext(val base: ContextBase, settingsGroup: SettingGroup) extends FreshContext {
private class InitialContext(base: ContextBase, settingsGroup: SettingGroup) extends FreshContext(base) {
outer = NoContext
period = InitialPeriod
mode = Mode.None
Expand All @@ -608,9 +619,8 @@ object Contexts {
gadt = EmptyGADTMap
}

@sharable object NoContext extends Context {
override def source = NoSource
val base: ContextBase = null
@sharable object NoContext extends Context(null) {
source = NoSource
override val implicits: ContextualImplicits = new ContextualImplicits(Nil, null)(this)
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/TyperState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import reporting._
import config.Config
import collection.mutable
import java.lang.ref.WeakReference
import util.Stats

import scala.annotation.internal.sharable

Expand All @@ -18,6 +19,8 @@ object TyperState {

class TyperState(previous: TyperState /* | Null */) {

Stats.record("typerState")

val id: Int = TyperState.nextId
TyperState.nextId += 1

Expand Down Expand Up @@ -138,6 +141,7 @@ class TyperState(previous: TyperState /* | Null */) {
* many parts of dotty itself.
*/
def commit()(implicit ctx: Context): Unit = {
Stats.record("typerState.commit")
val targetState = ctx.typerState
assert(isCommittable)
targetState.constraint =
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package typer
import core._
import ast.{Trees, tpd, untpd}
import util.Spans._
import util.Stats.track
import util.Stats.{track, record}
import util.{SourcePosition, NoSourcePosition, SourceFile}
import Trees.Untyped
import Contexts._
Expand Down Expand Up @@ -782,6 +782,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>

def realApply(implicit ctx: Context): Tree = track("realApply") {
val originalProto = new FunProto(tree.args, IgnoredProto(pt))(this, tree.isContextual)(argCtx(tree))
record("typedApply")
val fun1 = typedExpr(tree.fun, originalProto)

// Warning: The following lines are dirty and fragile. We record that auto-tupling was demanded as
Expand Down Expand Up @@ -916,6 +917,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") {
val isNamed = hasNamedArg(tree.args)
val typedArgs = if (isNamed) typedNamedArgs(tree.args) else tree.args.mapconserve(typedType(_))
record("typedTypeApply")
handleMeta(typedExpr(tree.fun, PolyProto(typedArgs, pt)) match {
case ExtMethodApply(app) =>
app
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2190,9 +2190,12 @@ class Typer extends Namer
def tryEither[T](op: Context => T)(fallBack: (T, TyperState) => T)(implicit ctx: Context): T = {
val nestedCtx = ctx.fresh.setNewTyperState()
val result = op(nestedCtx)
if (nestedCtx.reporter.hasErrors)
if (nestedCtx.reporter.hasErrors) {
record("tryEither.fallBack")
fallBack(result, nestedCtx.typerState)
}
else {
record("tryEither.commit")
nestedCtx.typerState.commit()
result
}
Expand Down