Skip to content

Commit 16756e4

Browse files
committed
Don't generate fields for BoxedUnit val and var
This is intended as a way to not generate fields for phantom fields, which by this time are erased to BoxedUnit fields.
1 parent a391a58 commit 16756e4

14 files changed

+175
-5
lines changed

compiler/src/dotty/tools/dotc/core/PhantomErasure.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import dotty.tools.dotc.core.Types.Type
99
*
1010
* - Parameters/arguments are erased to BoxedUnit. The next step will remove the parameters
1111
* from the method definitions and calls (implemented in branch implement-phantom-types-part-2).
12-
* - Definitions of `def`, `val`, `lazy val` and `var` returning a phantom type to return a BoxedUnit. The next step
13-
* is to erase the fields for phantom types (implemented in branch implement-phantom-types-part-3)
12+
* - Definitions of `def`, `val`, `lazy val` and `var` returning a phantom type to return a BoxedUnit. Where fields
13+
* with BoxedUnit type are not memoized (see transform/Memoize.scala).
1414
* - Calls to Phantom.assume become calls to BoxedUnit. Intended to be optimized away by local optimizations.
1515
*
1616
* BoxedUnit is used as it fits perfectly and homogeneously in all locations where phantoms can be found.

compiler/src/dotty/tools/dotc/transform/Memoize.scala

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,20 @@ import Decorators._
103103
var rhs = tree.rhs.changeOwnerAfter(sym, field, thisTransform)
104104
if (isWildcardArg(rhs)) rhs = EmptyTree
105105
val fieldDef = transformFollowing(ValDef(field, adaptToField(rhs)))
106-
val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field))(ctx.withOwner(sym), info))
106+
val isUnitField = tree.tpt.tpe.widenDealias =:= defn.BoxedUnitType
107+
val getterRhs =
108+
if (isUnitField) ref(defn.BoxedUnit_UNIT)
109+
else transformFollowingDeep(ref(field))(ctx.withOwner(sym), info)
110+
val getterDef = cpy.DefDef(tree)(rhs = getterRhs)
107111
Thicket(fieldDef, getterDef)
108112
} else if (sym.isSetter) {
109113
if (!sym.is(ParamAccessor)) { val Literal(Constant(())) = tree.rhs } // this is intended as an assertion
110114
field.setFlag(Mutable) // necessary for vals mixed in from Scala2 traits
111-
val initializer = Assign(ref(field), adaptToField(ref(tree.vparamss.head.head.symbol)))
112-
cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer)(ctx.withOwner(sym), info))
115+
if (tree.vparamss.head.head.tpt.tpe =:= defn.BoxedUnitType) tree
116+
else {
117+
val initializer = Assign(ref(field), adaptToField(ref(tree.vparamss.head.head.symbol)))
118+
cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer)(ctx.withOwner(sym), info))
119+
}
113120
}
114121
else tree // curiously, some accessors from Scala2 have ' ' suffixes. They count as
115122
// neither getters nor setters

tests/run/phantom-lazy-val-2.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
1
2+
foo
3+
2

tests/run/phantom-lazy-val-2.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
object Test {
3+
4+
def main(args: Array[String]): Unit = {
5+
val f = new Foo
6+
println(1)
7+
f.foo
8+
println(2)
9+
f.foo
10+
// Currently not erasing fields for lazy phantom vals
11+
// assert(!f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "field foo not erased")
12+
}
13+
14+
15+
}
16+
17+
class Foo {
18+
import Boo._
19+
20+
lazy val foo = {
21+
println("foo")
22+
any
23+
}
24+
}
25+
26+
object Boo extends Phantom {
27+
type BooAny = this.Any
28+
def any: BooAny = assume
29+
}

tests/run/phantom-val-2.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
foo
2+
1

tests/run/phantom-val-2.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
val f = new Foo
5+
println(1)
6+
f.foo
7+
f.foo
8+
assert(!f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "field foo not erased")
9+
}
10+
}
11+
12+
class Foo {
13+
import Boo._
14+
val foo = {
15+
println("foo")
16+
any
17+
}
18+
}
19+
20+
object Boo extends Phantom {
21+
type BooAny = this.Any
22+
def any: BooAny = assume
23+
}

tests/run/phantom-var-2.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
foo
2+
foo2
3+
foo3

tests/run/phantom-var-2.scala

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
object Test {
3+
import Boo._
4+
5+
def main(args: Array[String]): Unit = {
6+
val f = new Foo
7+
f.foo
8+
f.foo
9+
f.foo = {
10+
println("foo3")
11+
any
12+
}
13+
f.foo
14+
assert(!f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "field foo not erased")
15+
}
16+
}
17+
18+
class Foo {
19+
import Boo._
20+
21+
var foo = {
22+
println("foo")
23+
any
24+
}
25+
26+
foo = {
27+
println("foo2")
28+
any
29+
}
30+
}
31+
32+
object Boo extends Phantom {
33+
type BooAny = this.Any
34+
def any: BooAny = assume
35+
}

tests/run/unit-lazy-val.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
1
2+
foo
3+
2

tests/run/unit-lazy-val.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
object Test {
3+
4+
def main(args: Array[String]): Unit = {
5+
val f = new Foo
6+
println(1)
7+
f.foo
8+
println(2)
9+
f.foo
10+
// Currently not erasing fields for lazy vals
11+
// assert(!f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "field foo not erased")
12+
}
13+
14+
15+
}
16+
17+
class Foo {
18+
lazy val foo: Unit = {
19+
println("foo")
20+
}
21+
}

tests/run/unit-val.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
foo
2+
1

tests/run/unit-val.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
val f = new Foo
5+
println(1)
6+
f.foo
7+
f.foo
8+
assert(!f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "field foo not erased")
9+
}
10+
}
11+
12+
class Foo {
13+
val foo: Unit = {
14+
println("foo")
15+
}
16+
}

tests/run/unit-var.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
foo
2+
foo2
3+
foo3

tests/run/unit-var.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
val f = new Foo
5+
f.foo
6+
f.foo
7+
f.foo = {
8+
println("foo3")
9+
}
10+
f.foo
11+
assert(!f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "field foo not erased")
12+
}
13+
}
14+
15+
class Foo {
16+
var foo: Unit = {
17+
println("foo")
18+
}
19+
20+
foo = {
21+
println("foo2")
22+
}
23+
}

0 commit comments

Comments
 (0)