aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Memoize.scala25
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala22
-rw-r--r--tests/run/final-var.check4
-rw-r--r--tests/run/final-var.scala20
4 files changed, 51 insertions, 20 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala
index 3df9b0daa..8b5ceb0aa 100644
--- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala
@@ -99,26 +99,11 @@ import Decorators._
if (sym.is(Accessor, butNot = NoFieldNeeded))
if (sym.isGetter) {
- def skipBlocks(t: Tree): Tree = t match {
- case Block(_, t1) => skipBlocks(t1)
- case _ => t
- }
- skipBlocks(tree.rhs) match {
- case lit: Literal if sym.is(Final) && isIdempotentExpr(tree.rhs) =>
- // duplicating scalac behavior: for final vals that have rhs as constant, we do not create a field
- // and instead return the value. This seemingly minor optimization has huge effect on initialization
- // order and the values that can be observed during superconstructor call
-
- // see remark about idempotency in PostTyper#normalizeTree
- cpy.DefDef(tree)(rhs = lit)
- case _ =>
- var rhs = tree.rhs.changeOwnerAfter(sym, field, thisTransform)
- if (isWildcardArg(rhs)) rhs = EmptyTree
-
- val fieldDef = transformFollowing(ValDef(field, adaptToField(rhs)))
- val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field))(ctx.withOwner(sym), info))
- Thicket(fieldDef, getterDef)
- }
+ var rhs = tree.rhs.changeOwnerAfter(sym, field, thisTransform)
+ if (isWildcardArg(rhs)) rhs = EmptyTree
+ val fieldDef = transformFollowing(ValDef(field, adaptToField(rhs)))
+ val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field))(ctx.withOwner(sym), info))
+ Thicket(fieldDef, getterDef)
} else if (sym.isSetter) {
if (!sym.is(ParamAccessor)) { val Literal(Constant(())) = tree.rhs } // this is intended as an assertion
field.setFlag(Mutable) // necessary for vals mixed in from Scala2 traits
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index b70a51d1e..a053a0b0d 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1173,6 +1173,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (sym.is(Inline, butNot = DeferredOrParamAccessor))
checkInlineConformant(rhs1, em"right-hand side of inline $sym")
patchIfLazy(vdef1)
+ patchFinalVals(vdef1)
vdef1
}
@@ -1185,6 +1186,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
patch(Position(toUntyped(vdef).pos.start), "@volatile ")
}
+ /** Adds inline to final vals with idempotent rhs
+ *
+ * duplicating scalac behavior: for final vals that have rhs as constant, we do not create a field
+ * and instead return the value. This seemingly minor optimization has huge effect on initialization
+ * order and the values that can be observed during superconstructor call
+ *
+ * see remark about idempotency in PostTyper#normalizeTree
+ */
+ private def patchFinalVals(vdef: ValDef)(implicit ctx: Context): Unit = {
+ def isFinalInlinableVal(sym: Symbol): Boolean = {
+ sym.is(Final, butNot = Mutable) &&
+ isIdempotentExpr(vdef.rhs) /* &&
+ ctx.scala2Mode (stay compatible with Scala2 for now) */
+ }
+ val sym = vdef.symbol
+ sym.info match {
+ case info: ConstantType if isFinalInlinableVal(sym) && !ctx.settings.YnoInline.value => sym.setFlag(Inline)
+ case _ =>
+ }
+ }
+
def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") {
val DefDef(name, tparams, vparamss, tpt, _) = ddef
completeAnnotations(ddef, sym)
diff --git a/tests/run/final-var.check b/tests/run/final-var.check
new file mode 100644
index 000000000..7565230c0
--- /dev/null
+++ b/tests/run/final-var.check
@@ -0,0 +1,4 @@
+false
+true
+false
+true
diff --git a/tests/run/final-var.scala b/tests/run/final-var.scala
new file mode 100644
index 000000000..94a6c453c
--- /dev/null
+++ b/tests/run/final-var.scala
@@ -0,0 +1,20 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ println(Obj.myFinalVar)
+ Obj.myFinalVar = true
+ println(Obj.myFinalVar)
+
+ val o = new Cls
+ println(o.myFinalVar)
+ o.myFinalVar = true
+ println(o.myFinalVar)
+ }
+}
+
+object Obj {
+ final var myFinalVar: Boolean = false
+}
+
+class Cls {
+ final var myFinalVar: Boolean = false
+}