@@ -10,7 +10,7 @@ import core.Types._
1010import ast .Trees ._
1111import scala .collection .mutable
1212import config .Printers .simplify
13- import Simplify .desugarIdent
13+ import Simplify .{ desugarIdent , isEffectivelyMutable }
1414import transform .SymUtils ._
1515
1616/** Inline vals and remove vals that are aliases to other vals
@@ -164,56 +164,66 @@ class Devalify extends Optimisation {
164164 case _ => t
165165 }
166166
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)
193183 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+ }
218228 }
219229}
0 commit comments