Skip to content

Commit 8a7601c

Browse files
committed
Address review comments
1 parent f79bc08 commit 8a7601c

File tree

5 files changed

+36
-21
lines changed

5 files changed

+36
-21
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ class Compiler {
7272
new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods
7373
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
7474
new ClassOf, // Expand `Predef.classOf` calls.
75-
new CollectNullableFields, // Collect fields that can be nulled out after use in lazy initialization
7675
new RefChecks) :: // Various checks mostly related to abstract members and overriding
7776
List(new TryCatchPatterns, // Compile cases in try/catch
7877
new PatternMatcher, // Compile pattern matches
@@ -88,6 +87,7 @@ class Compiler {
8887
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods
8988
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
9089
new ElimByName, // Expand by-name parameter references
90+
new CollectNullableFields, // Collect fields that can be nulled out after use in lazy initialization
9191
new ElimOuterSelect, // Expand outer selections
9292
new AugmentScala2Traits, // Expand traits defined in Scala 2.x to simulate old-style rewritings
9393
new ResolveSuper, // Implement super accessors and add forwarders to trait methods

compiler/src/dotty/tools/dotc/transform/CollectNullableFields.scala

+19-13
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ class CollectNullableFields extends MiniPhase {
4545

4646
override def phaseName = CollectNullableFields.name
4747

48+
/** Running after `ElimByName` to see by names as nullable types.
49+
*
50+
* We don't necessary need to run after `Getters`, but the implementation
51+
* could be simplified if we were to run before.
52+
*/
53+
override def runsAfter = Set(Getters.name, ElimByName.name)
54+
4855
private[this] sealed trait FieldInfo
4956
private[this] case object NotNullable extends FieldInfo
5057
private[this] case class Nullable(by: Symbol) extends FieldInfo
@@ -53,21 +60,20 @@ class CollectNullableFields extends MiniPhase {
5360
private[this] var nullability: IdentityHashMap[Symbol, FieldInfo] = _
5461

5562
override def prepareForUnit(tree: Tree)(implicit ctx: Context) = {
56-
nullability = new IdentityHashMap
63+
if (nullability == null) nullability = new IdentityHashMap
5764
ctx
5865
}
5966

6067
private def recordUse(tree: Tree)(implicit ctx: Context): Tree = {
61-
val sym = tree.symbol
68+
def isField(sym: Symbol) =
69+
sym.isField || sym.isGetter // running after phase Getters
6270

63-
def isNullableType(tpe: Type) =
64-
tpe.isInstanceOf[ExprType] ||
65-
tpe.widenDealias.typeSymbol.isNullableClass
71+
val sym = tree.symbol
6672
val isNullablePrivateField =
67-
sym.isField &&
73+
isField(sym) &&
6874
sym.is(Private, butNot = Lazy) &&
6975
!sym.owner.is(Trait) &&
70-
isNullableType(sym.info)
76+
sym.info.widenDealias.typeSymbol.isNullableClass
7177

7278
if (isNullablePrivateField)
7379
nullability.get(sym) match {
@@ -76,8 +82,8 @@ class CollectNullableFields extends MiniPhase {
7682
case null => // not in the map
7783
val from = ctx.owner
7884
val isNullable =
79-
from.is(Lazy) && from.isField && // used in lazy field initializer
80-
from.owner.eq(sym.owner) // lazy val and field in the same class
85+
from.is(Lazy) && isField(from) && // used in lazy field initializer
86+
from.owner.eq(sym.owner) // lazy val and field defined in the same class
8187
val info = if (isNullable) Nullable(from) else NotNullable
8288
nullability.put(sym, info)
8389
case _ =>
@@ -96,16 +102,16 @@ class CollectNullableFields extends MiniPhase {
96102
recordUse(tree)
97103

98104
/** Map lazy values to the fields they should null after initialization. */
99-
def lazyValNullables(implicit ctx: Context): Map[Symbol, List[Symbol]] = {
100-
val result = new mutable.HashMap[Symbol, mutable.ListBuffer[Symbol]]
105+
def lazyValNullables(implicit ctx: Context): IdentityHashMap[Symbol, mutable.ListBuffer[Symbol]] = {
106+
val result = new IdentityHashMap[Symbol, mutable.ListBuffer[Symbol]]
101107

102108
nullability.forEach {
103109
case (sym, Nullable(from)) =>
104-
val bldr = result.getOrElseUpdate(from, new mutable.ListBuffer)
110+
val bldr = result.computeIfAbsent(from, _ => new mutable.ListBuffer)
105111
bldr += sym
106112
case _ =>
107113
}
108114

109-
result.mapValues(_.toList).toMap
115+
result
110116
}
111117
}

compiler/src/dotty/tools/dotc/transform/Getters.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import ValueClasses._
4949
class Getters extends MiniPhase with SymTransformer {
5050
import ast.tpd._
5151

52-
override def phaseName = "getters"
52+
override def phaseName = Getters.name
5353

5454
override def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = {
5555
def noGetterNeeded =
@@ -74,3 +74,7 @@ class Getters extends MiniPhase with SymTransformer {
7474
override def transformAssign(tree: Assign)(implicit ctx: Context): Tree =
7575
if (tree.lhs.symbol is Method) tree.lhs.becomes(tree.rhs).withPos(tree.pos) else tree
7676
}
77+
78+
object Getters {
79+
val name = "getters"
80+
}

compiler/src/dotty/tools/dotc/transform/LazyVals.scala

+10-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import dotty.tools.dotc.core.SymDenotations.SymDenotation
2626
import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, IdentityDenotTransformer, DenotTransformer}
2727
import Erasure.Boxing.adaptToType
2828

29+
import java.util.IdentityHashMap
30+
2931
class LazyVals extends MiniPhase with IdentityDenotTransformer {
3032
import LazyVals._
3133
import tpd._
@@ -51,14 +53,17 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
5153
val containerFlagsMask = Flags.Method | Flags.Lazy | Flags.Accessor | Flags.Module
5254

5355
/** A map of lazy values to the fields they should null after initialization. */
54-
private[this] var lazyValNullables: Map[Symbol, List[Symbol]] = _
55-
private def nullableFor(sym: Symbol)(implicit ctx: Context) =
56-
if (sym.is(Flags.Module)) Nil
57-
else lazyValNullables.getOrElse(sym, Nil)
56+
private[this] var lazyValNullables: IdentityHashMap[Symbol, mutable.ListBuffer[Symbol]] = _
57+
private def nullableFor(sym: Symbol)(implicit ctx: Context) = {
58+
val nullables = lazyValNullables.remove(sym)
59+
if (nullables == null || sym.is(Flags.Module)) Nil
60+
else nullables.toList
61+
}
5862

5963

6064
override def prepareForUnit(tree: Tree)(implicit ctx: Context) = {
61-
lazyValNullables = ctx.collectNullableFieldsPhase.asInstanceOf[CollectNullableFields].lazyValNullables
65+
if (lazyValNullables == null)
66+
lazyValNullables = ctx.collectNullableFieldsPhase.asInstanceOf[CollectNullableFields].lazyValNullables
6267
ctx
6368
}
6469

tests/run/i1692.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ object Test {
119119

120120
val fromTrait = new LazyTrait {}
121121
assert(fromTrait.l0 == "A")
122-
assert(readField("LazyTrait$$a", fromTrait) != null) // fragile: test will break if compiler generated name change
122+
assert(readField("LazyTrait$$a", fromTrait) != null) // fragile: test will break if compiler generated names change
123123
}
124124

125125
def readField(fieldName: String, target: Any): Any = {

0 commit comments

Comments
 (0)