@@ -312,6 +312,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
312312 /** The purity level of this statement.
313313 * @return pure if statement has no side effects
314314 * idempotent if running the statement a second time has no side effects
315+ * readonly if statement has only read effects
315316 * impure otherwise
316317 */
317318 private def statPurity (tree : Tree )(implicit ctx : Context ): PurityLevel = unsplice(tree) match {
@@ -331,6 +332,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
331332 /** The purity level of this expression.
332333 * @return pure if expression has no side effects
333334 * idempotent if running the expression a second time has no side effects
335+ * readonly if statement has only read effects
334336 * impure otherwise
335337 *
336338 * Note that purity and idempotency are different. References to modules and lazy
@@ -351,12 +353,6 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
351353 refPurity(tree).min(exprPurity(qual))
352354 case TypeApply (fn, _) =>
353355 exprPurity(fn)
354- /*
355- * Not sure we'll need that. Comment out until we find out
356- case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
357- // see a detailed explanation of this trick in `GenSymbols.reifyFreeTerm`
358- free.symbol.hasStableFlag && isIdempotentExpr(free)
359- */
360356 case Apply (fn, args) =>
361357 def isKnownPureOp (sym : Symbol ) =
362358 sym.owner.isPrimitiveValueClass || sym.owner == defn.StringClass
@@ -381,25 +377,31 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
381377
382378 def isPureExpr (tree : Tree )(implicit ctx : Context ) = exprPurity(tree) == Pure
383379 def isIdempotentExpr (tree : Tree )(implicit ctx : Context ) = exprPurity(tree) >= Idempotent
380+ def isReadOnlyExpr (tree : Tree )(implicit ctx : Context ) = exprPurity(tree) >= ReadOnly
384381
385382 /** The purity level of this reference.
386383 * @return
387384 * pure if reference is (nonlazy and stable) or to a parameterized function
388385 * idempotent if reference is lazy and stable
386+ * readonly if reference is to a val/var or to an accessor
389387 * impure otherwise
390388 * @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
391389 * flags set.
392390 */
393391 private def refPurity (tree : Tree )(implicit ctx : Context ): PurityLevel =
394392 if (! tree.tpe.widen.isParameterless) Pure
395- else if (! tree.symbol.isStable) Impure
393+ else if (! tree.symbol.isStable)
394+ if (! tree.symbol.is(Method ) || tree.symbol.is(AnyAccessor )) ReadOnly
395+ else Impure
396396 else if (tree.symbol.is(Lazy )) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
397397 else Pure
398398
399399 def isPureRef (tree : Tree )(implicit ctx : Context ) =
400400 refPurity(tree) == Pure
401401 def isIdempotentRef (tree : Tree )(implicit ctx : Context ) =
402402 refPurity(tree) >= Idempotent
403+ def isReadOnlyRef (tree : Tree )(implicit ctx : Context ) =
404+ refPurity(tree) >= ReadOnly
403405
404406 /** If `tree` is a constant expression, its value as a Literal,
405407 * or `tree` itself otherwise.
@@ -706,11 +708,12 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
706708
707709object TreeInfo {
708710 class PurityLevel (val x : Int ) extends AnyVal {
709- def >= (that : PurityLevel ) = x > = that.x
710- def min (that : PurityLevel ) = new PurityLevel (x min that.x)
711+ def >= (that : PurityLevel ) = (x & that.x) = = that.x
712+ def min (that : PurityLevel ) = new PurityLevel (x & that.x)
711713 }
712714
713- val Pure = new PurityLevel (2 )
715+ val Pure = new PurityLevel (3 )
716+ val ReadOnly = new PurityLevel (2 )
714717 val Idempotent = new PurityLevel (1 )
715718 val Impure = new PurityLevel (0 )
716719}
0 commit comments