aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2017-04-19 06:58:40 -0500
committerGitHub <noreply@github.com>2017-04-19 06:58:40 -0500
commit02e38832668ed2a0504a77dd4f86270fa1a1d4bf (patch)
tree5f931022c36fc3cf8ef585e4bcc08f554f92142e /compiler
parent4623e1282ebe7dfc31cb12411fed16457ed289ca (diff)
parent983ce8da3ce321bed7f8100c00b4aa709528208e (diff)
downloaddotty-02e38832668ed2a0504a77dd4f86270fa1a1d4bf.tar.gz
dotty-02e38832668ed2a0504a77dd4f86270fa1a1d4bf.tar.bz2
dotty-02e38832668ed2a0504a77dd4f86270fa1a1d4bf.zip
Merge pull request #2267 from dotty-staging/fix-constant-lazy-vals
Fix #2266: Do not replace constant type lazy vals with constant.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/src/dotty/tools/dotc/ast/TreeInfo.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/core/Constants.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/transform/FirstTransform.scala17
-rw-r--r--compiler/test/dotc/scala-collections.blacklist2
4 files changed, 40 insertions, 7 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
index f3bce4000..49187492e 100644
--- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -3,7 +3,7 @@ package dotc
package ast
import core._
-import Flags._, Trees._, Types._, Contexts._
+import Flags._, Trees._, Types._, Contexts._, Constants._
import Names._, StdNames._, NameOps._, Decorators._, Symbols._
import util.HashSet
import typer.ConstFold
@@ -426,8 +426,18 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
*/
def constToLiteral(tree: Tree)(implicit ctx: Context): Tree = {
val tree1 = ConstFold(tree)
+ def canInlineConstant(value: Constant): Boolean = {
+ val sym = tree1.symbol
+ isIdempotentExpr(tree1) && // see note in documentation
+ // lazy value must be initialized (would not be needed with isPureExpr)
+ !sym.is(Lazy) &&
+ // could hide initialization order issues (ex. val with constant type read before initialized)
+ (!ctx.owner.isLocalDummy || (!sym.is(Method) && !sym.is(Lazy) && value.isZero) ||
+ ctx.scala2Mode // ignore in Scala 2 because of inlined `final val` values
+ )
+ }
tree1.tpe.widenTermRefExpr match {
- case ConstantType(value) if isIdempotentExpr(tree1) => Literal(value)
+ case ConstantType(value) if canInlineConstant(value) => Literal(value)
case _ => tree1
}
}
diff --git a/compiler/src/dotty/tools/dotc/core/Constants.scala b/compiler/src/dotty/tools/dotc/core/Constants.scala
index ed388b7ec..8ea285c8d 100644
--- a/compiler/src/dotty/tools/dotc/core/Constants.scala
+++ b/compiler/src/dotty/tools/dotc/core/Constants.scala
@@ -53,6 +53,20 @@ object Constants {
def isNonUnitAnyVal = BooleanTag <= tag && tag <= DoubleTag
def isAnyVal = UnitTag <= tag && tag <= DoubleTag
+ /** Is the zero or un-initialized value of the type */
+ def isZero(implicit ctx: Context): Boolean = tag match {
+ case BooleanTag => !value.asInstanceOf[Boolean]
+ case ByteTag => value.asInstanceOf[Byte] == 0
+ case ShortTag => value.asInstanceOf[Short] == 0
+ case CharTag => value.asInstanceOf[Char] == 0
+ case IntTag => value.asInstanceOf[Int] == 0
+ case LongTag => value.asInstanceOf[Long] == 0L
+ case FloatTag => value.asInstanceOf[Float] == 0.0
+ case DoubleTag => value.asInstanceOf[Double] == 0.0
+ case NullTag => true
+ case _ => false
+ }
+
def tpe(implicit ctx: Context): Type = tag match {
case UnitTag => defn.UnitType
case BooleanTag => defn.BooleanType
diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala
index a3cf71ef2..767ee0901 100644
--- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala
+++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala
@@ -9,7 +9,7 @@ import dotty.tools.dotc.transform.TreeTransforms._
import ast.Trees._
import Flags._
import Types._
-import Constants.Constant
+import Constants._
import Contexts.Context
import Symbols._
import SymDenotations._
@@ -34,6 +34,8 @@ import StdNames._
* - drops branches of ifs using the rules
* if (true) A else B --> A
* if (false) A else B --> B
+ * if (C: true) A else B --> C; A
+ * if (C: false) A else B --> C; B
*/
class FirstTransform extends MiniPhaseTransform with InfoTransformer with AnnotationTransformer { thisTransformer =>
import ast.tpd._
@@ -190,11 +192,16 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota
override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo) =
constToLiteral(tree)
- override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo) =
- tree.cond match {
- case Literal(Constant(c: Boolean)) => if (c) tree.thenp else tree.elsep
- case _ => tree
+ override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo) = {
+ tree.cond.tpe.widenTermRefExpr match {
+ case ConstantType(Constant(condVal: Boolean)) =>
+ val selected = if (condVal) tree.thenp else tree.elsep
+ if (isPureExpr(tree.cond)) selected
+ else Block(tree.cond :: Nil, selected)
+ case _ =>
+ tree
}
+ }
// invariants: all modules have companion objects
// all types are TypeTrees
diff --git a/compiler/test/dotc/scala-collections.blacklist b/compiler/test/dotc/scala-collections.blacklist
index d6972a645..ae43e6eb4 100644
--- a/compiler/test/dotc/scala-collections.blacklist
+++ b/compiler/test/dotc/scala-collections.blacklist
@@ -81,3 +81,5 @@ scala/util/control/Exception.scala
# 51 | implicit def throwableSubtypeToCatcher[Ex <: Throwable: ClassTag, T](pf: PartialFunction[Ex, T]) =
# | ^
# | cyclic reference involving method mkCatcher
+
+scala/concurrent/duration/Duration.scala