@@ -10,7 +10,7 @@ import core.Types._
10
10
import ast .Trees ._
11
11
import scala .collection .mutable
12
12
import config .Printers .simplify
13
- import Simplify .desugarIdent
13
+ import Simplify .{ desugarIdent , isEffectivelyMutable }
14
14
import transform .SymUtils ._
15
15
16
16
/** Inline vals and remove vals that are aliases to other vals
@@ -164,56 +164,66 @@ class Devalify extends Optimisation {
164
164
case _ => t
165
165
}
166
166
167
- def readingOnlyVals (t : Tree )(implicit ctx : Context ): Boolean = dropCasts(t) match {
168
- case Typed (exp, _) => readingOnlyVals(exp)
169
- case TypeApply (fun @ Select (rec, _), List (tp)) =>
170
- if ((fun.symbol eq defn.Any_asInstanceOf ) && rec.tpe.derivesFrom(tp.tpe.classSymbol))
171
- readingOnlyVals(rec)
172
- else false
173
- case Apply (Select (rec, _), Nil ) =>
174
- def isGetterOfAImmutableField = t.symbol.isGetter && ! t.symbol.is(Mutable )
175
- def isCaseClassWithVar = t.symbol.info.decls.exists(_.is(Mutable ))
176
- def isAccessingProductField = t.symbol.exists &&
177
- t.symbol.owner.derivesFrom(defn.ProductClass ) &&
178
- t.symbol.owner.is(CaseClass ) &&
179
- t.symbol.name.isSelectorName &&
180
- ! isCaseClassWithVar // Conservative Covers case class A(var x: Int)
181
- def isImmutableCaseAccessor = t.symbol.is(CaseAccessor ) && ! t.symbol.is(Mutable )
182
- if (isGetterOfAImmutableField || isAccessingProductField || isImmutableCaseAccessor)
183
- readingOnlyVals(rec)
184
- else false
185
- case Select (rec, _) if t.symbol.is(Method ) =>
186
- if (t.symbol.isGetter && ! t.symbol.is(Mutable )) readingOnlyVals(rec) // getter of a immutable field
187
- else if (t.symbol.owner.derivesFrom(defn.ProductClass ) && t.symbol.owner.is(CaseClass ) && t.symbol.name.isSelectorName) {
188
- def isImmutableField = {
189
- val fieldId = t.symbol.name.toString.drop(1 ).toInt - 1
190
- ! t.symbol.owner.caseAccessors(ctx)(fieldId).is(Mutable )
191
- }
192
- if (isImmutableField) readingOnlyVals(rec) // accessing a field of a product
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)
193
183
else false
194
- } else if (t.symbol.is(CaseAccessor ) && ! t.symbol.is(Mutable ))
195
- readingOnlyVals(rec)
196
- else false
197
- case Select (qual, _) if ! t.symbol.is(Mutable ) =>
198
- readingOnlyVals(qual)
199
- case t : Ident if ! t.symbol.is(Mutable ) && ! t.symbol.is(Method ) && ! t.symbol.info.dealias.isInstanceOf [ExprType ] =>
200
- desugarIdent(t) match {
201
- case Some (t) => readingOnlyVals(t)
202
- case None => true
203
- }
204
- case t : This => true
205
- // null => false, or the following fails devalify:
206
- // trait I {
207
- // def foo: Any = null
208
- // }
209
- // object Main {
210
- // def main = {
211
- // val s: I = null
212
- // s.foo
213
- // }
214
- // }
215
- case Literal (Constant (null )) => false
216
- case t : Literal => true
217
- case _ => 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
+ }
218
228
}
219
229
}
0 commit comments