aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/dotc/ast/TreeInfo.scala13
-rw-r--r--compiler/src/dotty/tools/dotc/core/Constants.scala14
-rw-r--r--compiler/test/dotc/scala-collections.blacklist2
-rw-r--r--tests/run/inline-constant-in-constructor-1.check3
-rw-r--r--tests/run/inline-constant-in-constructor-1.scala15
-rw-r--r--tests/run/inline-constant-in-constructor-2.check3
-rw-r--r--tests/run/inline-constant-in-constructor-2.scala14
7 files changed, 62 insertions, 2 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
index cac0e4b91..46af1f1b4 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,17 @@ 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 = {
+ isIdempotentExpr(tree1) && // see note in documentation
+ // lazy value must be initialized (would not be needed with isPureExpr)
+ !tree1.symbol.is(Lazy) &&
+ // could hide initialization order issues (ex. val with constant type read before initialized)
+ (!ctx.owner.isLocalDummy || (tree1.symbol.is(Method) || value.isZero) ||
+ ctx.scala2Mode // ignore in Scala 2 because of inlined `final val` values
+ )
+ }
tree1.tpe.widenTermRefExpr match {
- case ConstantType(value) if isIdempotentExpr(tree1) && !tree1.symbol.is(Lazy) => 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/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
diff --git a/tests/run/inline-constant-in-constructor-1.check b/tests/run/inline-constant-in-constructor-1.check
new file mode 100644
index 000000000..05035c26d
--- /dev/null
+++ b/tests/run/inline-constant-in-constructor-1.check
@@ -0,0 +1,3 @@
+assert
+s
+r init
diff --git a/tests/run/inline-constant-in-constructor-1.scala b/tests/run/inline-constant-in-constructor-1.scala
new file mode 100644
index 000000000..11a727fd6
--- /dev/null
+++ b/tests/run/inline-constant-in-constructor-1.scala
@@ -0,0 +1,15 @@
+
+
+abstract class A {
+ def s: Boolean = { println("s"); r }
+ def r: Boolean
+}
+
+object Test extends A {
+ assert({ println("assert"); r == s }) // r constant type not replaced by true, r not initialized yet
+ override val r: true = {
+ println("r init")
+ true
+ }
+ def main(args: Array[String]): Unit = {}
+}
diff --git a/tests/run/inline-constant-in-constructor-2.check b/tests/run/inline-constant-in-constructor-2.check
new file mode 100644
index 000000000..05035c26d
--- /dev/null
+++ b/tests/run/inline-constant-in-constructor-2.check
@@ -0,0 +1,3 @@
+assert
+s
+r init
diff --git a/tests/run/inline-constant-in-constructor-2.scala b/tests/run/inline-constant-in-constructor-2.scala
new file mode 100644
index 000000000..a8d351ab6
--- /dev/null
+++ b/tests/run/inline-constant-in-constructor-2.scala
@@ -0,0 +1,14 @@
+
+abstract class A {
+ def s: Boolean = { println("s"); r }
+ def r: Boolean
+}
+
+object Test extends A {
+ assert({ println("assert"); r == s }) // r constant type replaced by false
+ override val r: false = {
+ println("r init")
+ false
+ }
+ def main(args: Array[String]): Unit = {}
+}