summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala29
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala8
7 files changed, 32 insertions, 27 deletions
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala
index 0f3e7648eb..29438278d0 100644
--- a/src/compiler/scala/reflect/internal/TreeInfo.scala
+++ b/src/compiler/scala/reflect/internal/TreeInfo.scala
@@ -60,18 +60,20 @@ abstract class TreeInfo {
| DefDef(_, _, _, _, _, _) =>
true
case ValDef(mods, _, _, rhs) =>
- !mods.isMutable && isPureExpr(rhs)
+ !mods.isMutable && isExprSafeToInline(rhs)
case _ =>
false
}
- /** Is tree a stable and pure expression?
- * !!! Clarification on what is meant by "pure" here would be appreciated.
- * This implementation allows both modules and lazy vals, which are pure in
- * the sense that they always return the same result, but which are also
- * side effecting. So for now, "pure" != "not side effecting".
+ /** Is tree an expression which can be inlined without affecting program semantics?
+ *
+ * Note that this is not called "isExprSafeToInline" since purity (lack of side-effects)
+ * is not the litmus test. References to modules and lazy vals are side-effecting,
+ * both because side-effecting code may be executed and because the first reference
+ * takes a different code path than all to follow; but they are safe to inline
+ * because the expression result from evaluating them is always the same.
*/
- def isPureExpr(tree: Tree): Boolean = tree match {
+ def isExprSafeToInline(tree: Tree): Boolean = tree match {
case EmptyTree
| This(_)
| Super(_, _)
@@ -84,24 +86,27 @@ abstract class TreeInfo {
case Select(Literal(const), name) =>
const.isAnyVal && (const.tpe.member(name) != NoSymbol)
case Select(qual, _) =>
- tree.symbol.isStable && isPureExpr(qual)
+ tree.symbol.isStable && isExprSafeToInline(qual)
case TypeApply(fn, _) =>
- isPureExpr(fn)
+ isExprSafeToInline(fn)
case Apply(fn, List()) =>
/* Note: After uncurry, field accesses are represented as Apply(getter, Nil),
* so an Apply can also be pure.
* However, before typing, applications of nullary functional values are also
* Apply(function, Nil) trees. To prevent them from being treated as pure,
* we check that the callee is a method. */
- fn.symbol.isMethod && !fn.symbol.isLazy && isPureExpr(fn)
+ fn.symbol.isMethod && !fn.symbol.isLazy && isExprSafeToInline(fn)
case Typed(expr, _) =>
- isPureExpr(expr)
+ isExprSafeToInline(expr)
case Block(stats, expr) =>
- (stats forall isPureDef) && isPureExpr(expr)
+ (stats forall isPureDef) && isExprSafeToInline(expr)
case _ =>
false
}
+ @deprecated("Use isExprSafeToInline instead", "2.10.0")
+ def isPureExpr(tree: Tree) = isExprSafeToInline(tree)
+
def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = {
val plen = params.length
val alen = args.length
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 033b049a92..5ba7465928 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -206,7 +206,7 @@ abstract class TreeGen extends reflect.internal.TreeGen {
*/
def evalOnce(expr: Tree, owner: Symbol, unit: CompilationUnit)(within: (() => Tree) => Tree): Tree = {
var used = false
- if (treeInfo.isPureExpr(expr)) {
+ if (treeInfo.isExprSafeToInline(expr)) {
within(() => if (used) expr.duplicate else { used = true; expr })
}
else {
@@ -223,7 +223,7 @@ abstract class TreeGen extends reflect.internal.TreeGen {
val used = new Array[Boolean](exprs.length)
var i = 0
for (expr <- exprs) {
- if (treeInfo.isPureExpr(expr)) {
+ if (treeInfo.isExprSafeToInline(expr)) {
exprs1 += {
val idx = i
() => if (used(idx)) expr.duplicate else { used(idx) = true; expr }
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index c21977cf9c..cc87ea7e06 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -433,7 +433,7 @@ abstract class Erasure extends AddInterfaces
case _ =>
typedPos(tree.pos)(tree.tpe.typeSymbol match {
case UnitClass =>
- if (treeInfo isPureExpr tree) REF(BoxedUnit_UNIT)
+ if (treeInfo isExprSafeToInline tree) REF(BoxedUnit_UNIT)
else BLOCK(tree, REF(BoxedUnit_UNIT))
case NothingClass => tree // a non-terminating expression doesn't need boxing
case x =>
@@ -472,7 +472,7 @@ abstract class Erasure extends AddInterfaces
case _ =>
typedPos(tree.pos)(pt.typeSymbol match {
case UnitClass =>
- if (treeInfo isPureExpr tree) UNIT
+ if (treeInfo isExprSafeToInline tree) UNIT
else BLOCK(tree, UNIT)
case x =>
assert(x != ArrayClass)
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 3965359094..864939ebfd 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -195,7 +195,7 @@ abstract class UnCurry extends InfoTransform
/** Undo eta expansion for parameterless and nullary methods */
def deEta(fun: Function): Tree = fun match {
- case Function(List(), Apply(expr, List())) if treeInfo.isPureExpr(expr) =>
+ case Function(List(), Apply(expr, List())) if treeInfo.isExprSafeToInline(expr) =>
if (expr hasSymbolWhich (_.isLazy))
fun
else
@@ -477,7 +477,7 @@ abstract class UnCurry extends InfoTransform
case Apply(Select(Function(vparams, body), nme.apply), args) =>
// if (List.forall2(vparams, args)((vparam, arg) => treeInfo.isAffineIn(body) ||
-// treeInfo.isPureExpr(arg))) =>
+// treeInfo.isExprSafeToInline(arg))) =>
// perform beta-reduction; this helps keep view applications small
println("beta-reduce2: "+tree)
withNeedLift(true) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
index ce206b55fd..92ce0e6de4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
@@ -64,7 +64,7 @@ trait EtaExpansion { self: Analyzer =>
*/
def liftoutPrefix(tree: Tree): Tree = {
def liftout(tree: Tree): Tree =
- if (treeInfo.isPureExpr(tree)) tree
+ if (treeInfo.isExprSafeToInline(tree)) tree
else {
val vname: Name = freshName()
// Problem with ticket #2351 here
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index bf7cc72fab..cc88f471ab 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -217,11 +217,11 @@ trait NamesDefaults { self: Analyzer =>
case Select(New(tp @ Select(qual, _)), _) if isConstr =>
// in `new q.C()', q is always stable
- assert(treeInfo.isPureExpr(qual), qual)
+ assert(treeInfo.isExprSafeToInline(qual), qual)
// 'moduleQual' fixes #2057
blockWithoutQualifier(moduleQual(tp.pos, tp.tpe))
case Select(TypeApply(New(tp @ Select(qual, _)), _), _) if isConstr =>
- assert(treeInfo.isPureExpr(qual), qual)
+ assert(treeInfo.isExprSafeToInline(qual), qual)
blockWithoutQualifier(moduleQual(tp.pos, tp.tpe))
// super constructor calls
@@ -232,7 +232,7 @@ trait NamesDefaults { self: Analyzer =>
// self constructor calls (in secondary constructors)
case Select(tp, name) if isConstr =>
- assert(treeInfo.isPureExpr(tp), tp)
+ assert(treeInfo.isExprSafeToInline(tp), tp)
blockWithoutQualifier(moduleQual(tp.pos, tp.tpe))
// other method calls
@@ -241,7 +241,7 @@ trait NamesDefaults { self: Analyzer =>
blockWithoutQualifier(None)
case Select(qual, name) =>
- if (treeInfo.isPureExpr(qual))
+ if (treeInfo.isExprSafeToInline(qual))
blockWithoutQualifier(Some(qual.duplicate))
else
blockWithQualifier(qual, name)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index d01cd829ac..0ecb8efea8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -202,7 +202,7 @@ trait Typers extends Modes with Adaptations {
* @return ...
*/
def checkStable(tree: Tree): Tree =
- if (treeInfo.isPureExpr(tree)) tree
+ if (treeInfo.isExprSafeToInline(tree)) tree
else errorTree(
tree,
"stable identifier required, but "+tree+" found."+
@@ -223,7 +223,7 @@ trait Typers extends Modes with Adaptations {
val savedSTABLE = tree.symbol getFlag STABLE
tree.symbol setInfo AnyRefClass.tpe
tree.symbol setFlag STABLE
- val result = treeInfo.isPureExpr(tree)
+ val result = treeInfo.isExprSafeToInline(tree)
tree.symbol setInfo savedTpe
tree.symbol setFlag savedSTABLE
result
@@ -1976,7 +1976,7 @@ trait Typers extends Modes with Adaptations {
val stats1 = typedStats(block.stats, context.owner)
val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt)
treeCopy.Block(block, stats1, expr1)
- .setType(if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst)
+ .setType(if (treeInfo.isExprSafeToInline(block)) expr1.tpe else expr1.tpe.deconst)
} finally {
// enable escaping privates checking from the outside and recycle
// transient flag
@@ -2136,7 +2136,7 @@ trait Typers extends Modes with Adaptations {
private def isWarnablePureExpression(tree: Tree) = tree match {
case EmptyTree | Literal(Constant(())) => false
case _ =>
- (treeInfo isPureExpr tree) && {
+ (treeInfo isExprSafeToInline tree) && {
val sym = tree.symbol
(sym == null) || !(sym.isModule || sym.isLazy) || {
debuglog("'Pure' but side-effecting expression in statement position: " + tree)