@@ -312,6 +312,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
312
312
/** The purity level of this statement.
313
313
* @return pure if statement has no side effects
314
314
* idempotent if running the statement a second time has no side effects
315
+ * readonly if statement has only read effects
315
316
* impure otherwise
316
317
*/
317
318
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] =>
331
332
/** The purity level of this expression.
332
333
* @return pure if expression has no side effects
333
334
* idempotent if running the expression a second time has no side effects
335
+ * readonly if statement has only read effects
334
336
* impure otherwise
335
337
*
336
338
* 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] =>
351
353
refPurity(tree).min(exprPurity(qual))
352
354
case TypeApply (fn, _) =>
353
355
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
- */
360
356
case Apply (fn, args) =>
361
357
def isKnownPureOp (sym : Symbol ) =
362
358
sym.owner.isPrimitiveValueClass || sym.owner == defn.StringClass
@@ -381,25 +377,31 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
381
377
382
378
def isPureExpr (tree : Tree )(implicit ctx : Context ) = exprPurity(tree) == Pure
383
379
def isIdempotentExpr (tree : Tree )(implicit ctx : Context ) = exprPurity(tree) >= Idempotent
380
+ def isReadOnlyExpr (tree : Tree )(implicit ctx : Context ) = exprPurity(tree) >= ReadOnly
384
381
385
382
/** The purity level of this reference.
386
383
* @return
387
384
* pure if reference is (nonlazy and stable) or to a parameterized function
388
385
* idempotent if reference is lazy and stable
386
+ * readonly if reference is to a val/var or to an accessor
389
387
* impure otherwise
390
388
* @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
391
389
* flags set.
392
390
*/
393
391
private def refPurity (tree : Tree )(implicit ctx : Context ): PurityLevel =
394
392
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
396
396
else if (tree.symbol.is(Lazy )) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
397
397
else Pure
398
398
399
399
def isPureRef (tree : Tree )(implicit ctx : Context ) =
400
400
refPurity(tree) == Pure
401
401
def isIdempotentRef (tree : Tree )(implicit ctx : Context ) =
402
402
refPurity(tree) >= Idempotent
403
+ def isReadOnlyRef (tree : Tree )(implicit ctx : Context ) =
404
+ refPurity(tree) >= ReadOnly
403
405
404
406
/** If `tree` is a constant expression, its value as a Literal,
405
407
* or `tree` itself otherwise.
@@ -706,11 +708,12 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
706
708
707
709
object TreeInfo {
708
710
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)
711
713
}
712
714
713
- val Pure = new PurityLevel (2 )
715
+ val Pure = new PurityLevel (3 )
716
+ val ReadOnly = new PurityLevel (2 )
714
717
val Idempotent = new PurityLevel (1 )
715
718
val Impure = new PurityLevel (0 )
716
719
}
0 commit comments