From 2324be56376aed8cd168e712001485f2202cdda6 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sun, 16 Apr 2017 18:48:53 +0200 Subject: Fix constant type val value inline in constructors. --- compiler/src/dotty/tools/dotc/ast/TreeInfo.scala | 13 +++++++++++-- compiler/src/dotty/tools/dotc/core/Constants.scala | 14 ++++++++++++++ compiler/test/dotc/scala-collections.blacklist | 2 ++ tests/run/inline-constant-in-constructor-1.check | 3 +++ tests/run/inline-constant-in-constructor-1.scala | 15 +++++++++++++++ tests/run/inline-constant-in-constructor-2.check | 3 +++ tests/run/inline-constant-in-constructor-2.scala | 14 ++++++++++++++ 7 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/run/inline-constant-in-constructor-1.check create mode 100644 tests/run/inline-constant-in-constructor-1.scala create mode 100644 tests/run/inline-constant-in-constructor-2.check create mode 100644 tests/run/inline-constant-in-constructor-2.scala 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 = {} +} -- cgit v1.2.3