Skip to content

Commit 55b9b17

Browse files
Factor out isImmutableAccessor
1 parent 3a06f0a commit 55b9b17

File tree

4 files changed

+51
-78
lines changed

4 files changed

+51
-78
lines changed

compiler/src/dotty/tools/dotc/transform/localopt/Devalify.scala

Lines changed: 34 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ package transform.localopt
44
import core.Constants.Constant
55
import core.Contexts.Context
66
import core.Flags._
7-
import core.NameOps._
87
import core.Symbols._
98
import core.Types._
109
import ast.Trees._
1110
import scala.collection.mutable
1211
import config.Printers.simplify
13-
import Simplify.{desugarIdent, isEffectivelyMutable}
12+
import Simplify._
1413
import transform.SymUtils._
1514

1615
/** Inline vals and remove vals that are aliases to other vals
@@ -164,66 +163,38 @@ class Devalify extends Optimisation {
164163
case _ => t
165164
}
166165

167-
def readingOnlyVals(t: Tree)(implicit ctx: Context): Boolean = {
168-
def isGetterOfAImmutableField = t.symbol.isGetter && !t.symbol.is(Mutable)
169-
def isCaseClassWithVar = t.symbol.info.decls.exists(_.is(Mutable))
170-
def isAccessingProductField = t.symbol.exists &&
171-
t.symbol.owner.derivesFrom(defn.ProductClass) &&
172-
t.symbol.owner.is(CaseClass) &&
173-
t.symbol.name.isSelectorName &&
174-
!isCaseClassWithVar // Conservatively covers case class A(var x: Int)
175-
def isImmutableCaseAccessor = t.symbol.is(CaseAccessor) && !t.symbol.is(Mutable)
176-
177-
dropCasts(t) match {
178-
case Typed(exp, _) => readingOnlyVals(exp)
179-
180-
case TypeApply(fun @ Select(rec, _), List(tp)) =>
181-
if ((fun.symbol eq defn.Any_asInstanceOf) && rec.tpe.derivesFrom(tp.tpe.classSymbol))
182-
readingOnlyVals(rec)
183-
else false
184-
185-
case Apply(Select(rec, _), Nil) =>
186-
if (isGetterOfAImmutableField || isAccessingProductField || isImmutableCaseAccessor)
187-
readingOnlyVals(rec)
188-
else false
189-
190-
case Select(rec, _) if t.symbol.is(Method) =>
191-
if (isGetterOfAImmutableField)
192-
readingOnlyVals(rec) // Getter of an immutable field
193-
else if (isAccessingProductField) {
194-
def isImmutableField = {
195-
val fieldId = t.symbol.name.toString.drop(1).toInt - 1
196-
!t.symbol.owner.caseAccessors(ctx)(fieldId).is(Mutable)
197-
}
198-
if (isImmutableField) readingOnlyVals(rec) // Accessing a field of a product
199-
else false
200-
} else if (isImmutableCaseAccessor)
201-
readingOnlyVals(rec)
202-
else false
203-
204-
case t @ Select(qual, _) if !isEffectivelyMutable(t) =>
205-
readingOnlyVals(qual)
206-
207-
case t: Ident if !t.symbol.is(Mutable | Method) && !t.symbol.info.dealias.isInstanceOf[ExprType] =>
208-
desugarIdent(t) match {
209-
case Some(t) => readingOnlyVals(t)
210-
case None => true
211-
}
212-
213-
case t: This => true
214-
// null => false, or the following fails devalify:
215-
// trait I {
216-
// def foo: Any = null
217-
// }
218-
// object Main {
219-
// def main = {
220-
// val s: I = null
221-
// s.foo
222-
// }
223-
// }
224-
case Literal(Constant(null)) => false
225-
case t: Literal => true
226-
case _ => false
227-
}
166+
def readingOnlyVals(t: Tree)(implicit ctx: Context): Boolean = dropCasts(t) match {
167+
case Typed(exp, _) => readingOnlyVals(exp)
168+
169+
case TypeApply(fun @ Select(rec, _), List(tp)) =>
170+
val isAsInstanceOf = fun.symbol == defn.Any_asInstanceOf && rec.tpe.derivesFrom(tp.tpe.classSymbol)
171+
isAsInstanceOf && readingOnlyVals(rec)
172+
173+
case t @ Apply(Select(rec, _), Nil) =>
174+
isImmutableAccessor(t) && readingOnlyVals(rec)
175+
176+
case t @ Select(rec, _) if t.symbol.is(Method) =>
177+
isImmutableAccessor(t) && readingOnlyVals(rec)
178+
179+
case t @ Select(qual, _) if !isEffectivelyMutable(t) =>
180+
readingOnlyVals(qual)
181+
182+
case t: Ident if !t.symbol.is(Mutable | Method) && !t.symbol.info.dealias.isInstanceOf[ExprType] =>
183+
desugarIdent(t).forall(readingOnlyVals)
184+
185+
case t: This => true
186+
// null => false, or the following fails devalify:
187+
// trait I {
188+
// def foo: Any = null
189+
// }
190+
// object Main {
191+
// def main = {
192+
// val s: I = null
193+
// s.foo
194+
// }
195+
// }
196+
case Literal(Constant(null)) => false
197+
case t: Literal => true
198+
case _ => false
228199
}
229200
}

compiler/src/dotty/tools/dotc/transform/localopt/DropNoEffects.scala

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ package transform.localopt
33

44
import core.TypeErasure
55
import core.Contexts.Context
6-
import core.NameOps._
76
import core.Symbols._
87
import core.Types._
98
import core.Flags._
109
import ast.Trees._
11-
import Simplify.desugarIdent
10+
import Simplify._
1211

1312
/** Removes side effect free statements in blocks and Defdef.
1413
* Flattens blocks (except Closure-blocks)
@@ -79,11 +78,7 @@ class DropNoEffects(val simplifyPhase: Simplify) extends Optimisation {
7978
elsep = nelsep.orElse(if (elsep.isInstanceOf[Literal]) elsep else unitLiteral))
8079

8180
// Accessing a field of a product
82-
case t @ Select(rec, _)
83-
if (t.symbol.isGetter && !t.symbol.is(Mutable | Lazy)) ||
84-
(t.symbol.owner.derivesFrom(defn.ProductClass) && t.symbol.owner.is(CaseClass) && t.symbol.name.isSelectorName) ||
85-
(t.symbol.is(CaseAccessor) && !t.symbol.is(Mutable)) =>
86-
81+
case t @ Select(rec, _) if isImmutableAccessor(t) =>
8782
keepOnlySideEffects(rec)
8883

8984
// !name.eq(nme.TYPE_) && // Keep the .TYPE added by ClassOf, would be needed for AfterErasure

compiler/src/dotty/tools/dotc/transform/localopt/InlineLocalObjects.scala

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import core.Contexts.Context
66
import core.Decorators._
77
import core.Names.Name
88
import core.Types.Type
9-
import core.NameOps._
109
import core.StdNames._
1110
import core.Symbols._
1211
import core.Flags._
1312
import ast.Trees._
1413
import scala.collection.mutable
1514
import transform.SymUtils._
1615
import config.Printers.simplify
16+
import Simplify._
1717

1818
/** Inline case classes as vals.
1919
*
@@ -74,10 +74,7 @@ class InlineLocalObjects extends Optimisation {
7474
case Assign(lhs, rhs) if !lhs.symbol.owner.isClass =>
7575
checkGood.put(lhs.symbol, checkGood.getOrElse(lhs.symbol, Set.empty) + rhs.symbol)
7676

77-
case t @ Select(qual, _) if
78-
(t.symbol.isGetter && !t.symbol.is(Mutable | Lazy)) ||
79-
(t.symbol.maybeOwner.derivesFrom(defn.ProductClass) && t.symbol.maybeOwner.is(CaseClass) && t.symbol.name.isSelectorName) ||
80-
(t.symbol.is(CaseAccessor) && !t.symbol.is(Mutable)) =>
77+
case t @ Select(qual, _) if isImmutableAccessor(t) =>
8178
gettersCalled(qual.symbol) = true
8279

8380
case t: DefDef if t.symbol.is(Label) =>
@@ -204,9 +201,7 @@ class InlineLocalObjects extends Optimisation {
204201
Thicket(t :: updates)
205202
}
206203

207-
case t @ Select(rec, _) if (t.symbol.isGetter && !t.symbol.is(Mutable | Lazy)) ||
208-
(t.symbol.maybeOwner.derivesFrom(defn.ProductClass) && t.symbol.owner.is(CaseClass) && t.symbol.name.isSelectorName) ||
209-
(t.symbol.is(CaseAccessor) && !t.symbol.is(Mutable)) =>
204+
case t @ Select(rec, _) if isImmutableAccessor(t) =>
210205
newMappings.getOrElse(rec.symbol, Map.empty).get(t.symbol) match {
211206
case None => t
212207
case Some(newSym) => ref(newSym)

compiler/src/dotty/tools/dotc/transform/localopt/Simplify.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import core.Symbols._
77
import core.Types._
88
import core.Flags._
99
import core.Decorators._
10+
import core.NameOps._
1011
import transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
1112
import config.Printers.simplify
1213
import ast.tpd
@@ -157,4 +158,15 @@ object Simplify {
157158
case i: Ident => desugarIdent(i).exists(isEffectivelyMutable)
158159
case _ => false
159160
}
161+
162+
def isImmutableAccessor(t: Tree)(implicit ctx: Context): Boolean = {
163+
val isImmutableGetter = t.symbol.isGetter && !t.symbol.is(Mutable | Lazy)
164+
val isCaseAccessor = t.symbol.is(CaseAccessor) && !t.symbol.is(Mutable | Lazy)
165+
val isProductAccessor = t.symbol.exists &&
166+
t.symbol.owner.derivesFrom(defn.ProductClass) &&
167+
t.symbol.owner.is(CaseClass) &&
168+
t.symbol.name.isSelectorName &&
169+
!t.symbol.info.decls.exists(_.is(Mutable | Lazy)) // Conservatively covers case class A(var x: Int)
170+
isImmutableGetter || isCaseAccessor || isProductAccessor
171+
}
160172
}

0 commit comments

Comments
 (0)