Skip to content

Migrating the main compiler to explicit nulls #14032

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 12 commits into from
Mar 6, 2022
Prev Previous commit
Next Next commit
Fix more according to comments
  • Loading branch information
noti0na1 committed Mar 6, 2022
commit 2987afe0c190fd82790c77a4fdcfc23b1bfe10d0
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ object Symbols {

private[core] def invalidateDenotCache(): Unit = { checkedPeriod = Nowhere }

/** Set the denotation of this symbol */
/** Set the denotation of this symbol
* `denot` should always be initialized when a new Symbol is created.
*/
private[core] def denot_=(d: SymDenotation): Unit = {
util.Stats.record("Symbol.denot_=")
lastDenot = d
Expand Down
14 changes: 7 additions & 7 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling

protected given [DummySoItsADef]: Context = myContext

protected var state: TyperState | Null = null
def constraint: Constraint = state.nn.constraint
def constraint_=(c: Constraint): Unit = state.nn.constraint = c
protected var state: TyperState = compiletime.uninitialized
def constraint: Constraint = state.constraint
def constraint_=(c: Constraint): Unit = state.constraint = c

def init(c: Context): Unit =
myContext = c
Expand Down Expand Up @@ -220,7 +220,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
def monitoredIsSubType = {
if (pendingSubTypes == null) {
pendingSubTypes = util.HashSet[(Type, Type)]()
report.log(s"!!! deep subtype recursion involving ${tp1.show} <:< ${tp2.show}, constraint = ${state.nn.constraint.show}")
report.log(s"!!! deep subtype recursion involving ${tp1.show} <:< ${tp2.show}, constraint = ${state.constraint.show}")
report.log(s"!!! constraint = ${constraint.show}")
//if (ctx.settings.YnoDeepSubtypes.value) {
// new Error("deep subtype").printStackTrace()
Expand Down Expand Up @@ -390,7 +390,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
thirdTry
case tp1: TypeParamRef =>
def flagNothingBound = {
if (!frozenConstraint && isBottom(tp2) && state.nn.isGlobalCommittable) {
if (!frozenConstraint && isBottom(tp2) && state.isGlobalCommittable) {
def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}"
if (Config.failOnInstantiationToNothing) assert(false, msg)
else report.log(msg)
Expand Down Expand Up @@ -1309,7 +1309,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
val saved = constraint
val savedGadt = ctx.gadt.fresh
inline def restore() =
state.nn.constraint = saved
state.constraint = saved
ctx.gadt.restore(savedGadt)
val savedSuccessCount = successCount
try
Expand All @@ -1319,7 +1319,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
recCount -= 1
if !result then restore()
else if recCount == 0 && needsGc then
state.nn.gc()
state.gc()
needsGc = false
if (Stats.monitored) recordStatistics(result, savedSuccessCount)
result
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TyperState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ class TyperState() {
Stats.record("typerState.gc")
val toCollect = new mutable.ListBuffer[TypeLambda]
for tvar <- ownedVars do
val tvaros = tvar.owningState.nn.get
assert(tvaros != null && (tvaros eq this), s"Inconsistent state in $this: it owns $tvar whose owningState is ${tvaros}")
val tvarState = tvar.owningState.nn.get
assert(tvarState eqn this, s"Inconsistent state in $this: it owns $tvar whose owningState is ${tvarState}")
assert(!tvar.inst.exists, s"Inconsistent state in $this: it owns $tvar which is already instantiated")
val inst = constraint.instType(tvar)
if inst.exists then
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ object Types {
NoDenotation
}
def goRec(tp: RecType) =
// TODO: test remove this check
// TODO: change tp.parent to nullable or other values
if ((tp.parent: Type | Null) == null) NoDenotation
else if (tp eq pre) go(tp.parent)
else {
Expand Down
4 changes: 1 addition & 3 deletions compiler/src/dotty/tools/dotc/core/Uniques.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import scala.annotation.tailrec

class Uniques extends WeakHashSet[Type](Config.initialUniquesCapacity):
override def hash(x: Type): Int = x.hash
override def isEqual(x: Type | Null, y: Type | Null) =
if x == null then y == null
else y != null && x.eql(y)
override def isEqual(x: Type, y: Type) = x.eql(y)

/** Defines operation `unique` for hash-consing types.
* Also defines specialized hash sets for hash consing uniques of a specific type.
Expand Down
41 changes: 21 additions & 20 deletions compiler/src/dotty/tools/dotc/util/WeakHashSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ abstract class WeakHashSet[A <: AnyRef](initialCapacity: Int = 8, loadFactor: Do
private def computeThreshold: Int = (table.size * loadFactor).ceil.toInt

protected def hash(key: A): Int
protected def isEqual(x: A | Null, y: A | Null): Boolean =
if x == null then y == null else x.equals(y)
protected def isEqual(x: A, y: A): Boolean = x.equals(y)

/** Turn hashcode `x` into a table index */
protected def index(x: Int): Int = x & (table.length - 1)
Expand Down Expand Up @@ -135,24 +134,25 @@ abstract class WeakHashSet[A <: AnyRef](initialCapacity: Int = 8, loadFactor: Do
tableLoop(0)
}

def lookup(elem: A): A | Null = {
// case null => throw new NullPointerException("WeakHashSet cannot hold nulls")
// case _ =>
// TODO: remove the `case null` when we can enable explicit nulls in regular compiling,
// since the type `A <: AnyRef` of `elem` can ensure the value is not null.
def lookup(elem: A): A | Null = (elem: A | Null) match {
case null => throw new NullPointerException("WeakHashSet cannot hold nulls")
case _ =>
Stats.record(statsItem("lookup"))
removeStaleEntries()
val bucket = index(hash(elem))

Stats.record(statsItem("lookup"))
removeStaleEntries()
val bucket = index(hash(elem))

@tailrec
def linkedListLoop(entry: Entry[A] | Null): A | Null = entry match {
case null => null
case _ =>
val entryElem = entry.get
if (isEqual(elem, entryElem)) entryElem
else linkedListLoop(entry.tail)
}
@tailrec
def linkedListLoop(entry: Entry[A] | Null): A | Null = entry match {
case null => null
case _ =>
val entryElem = entry.get
if entryElem != null && isEqual(elem, entryElem) then entryElem
else linkedListLoop(entry.tail)
}

linkedListLoop(table(bucket))
linkedListLoop(table(bucket))
}

protected def addEntryAt(bucket: Int, elem: A, elemHash: Int, oldHead: Entry[A] | Null): A = {
Expand All @@ -175,7 +175,7 @@ abstract class WeakHashSet[A <: AnyRef](initialCapacity: Int = 8, loadFactor: Do
case null => addEntryAt(bucket, elem, h, oldHead)
case _ =>
val entryElem = entry.get
if (isEqual(elem, entryElem)) entryElem.uncheckedNN
if entryElem != null && isEqual(elem, entryElem) then entryElem.uncheckedNN
else linkedListLoop(entry.tail)
}

Expand All @@ -192,7 +192,8 @@ abstract class WeakHashSet[A <: AnyRef](initialCapacity: Int = 8, loadFactor: Do
@tailrec
def linkedListLoop(prevEntry: Entry[A] | Null, entry: Entry[A] | Null): Unit =
if entry != null then
if isEqual(elem, entry.get) then remove(bucket, prevEntry, entry)
val entryElem = entry.get
if entryElem != null && isEqual(elem, entryElem) then remove(bucket, prevEntry, entry)
else linkedListLoop(entry, entry.tail)

linkedListLoop(null, table(bucket))
Expand Down