scala3
scala3 copied to clipboard
[scala.js] Dotty does not produce null/undefined property on anonymous class
Compiler version
3.1.0
Minimized code
- With Scala.js 1.8.0
trait Foo extends js.Object {
var extra: js.UndefOr[String]
}
val anon1 = new js.Object() {
var extra = "a"
}
val anon2 = new js.Object() {
var extra = js.undefined
}
val anon3 = new js.Object() {
var extra = null
}
val foo1 = new Foo {
var extra = "a"
}
val foo2 = new Foo {
var extra: js.UndefOr[String] = js.undefined
}
val foo3 = new Foo {
var extra: js.UndefOr[String] = null
}
println(js.Object.hasProperty(anon1, "extra"))
println(js.Object.hasProperty(anon2, "extra"))
println(js.Object.hasProperty(anon3, "extra"))
println(js.Object.hasProperty(foo1, "extra"))
println(js.Object.hasProperty(foo2, "extra"))
println(js.Object.hasProperty(foo3, "extra"))
Output
On Scala 2.13.7 and 2.12.15,
true
true
true
true
true
true
However on Scala 3.1.0,
true
false
false
true
true
true
which means null or undefined property on anonymous class is missing.
val foo2 = new Foo {
var extra: js.UndefOr[String] = js.undefined
}
val foo3 = new Foo {
var extra: js.UndefOr[String] = null
}
Expectation
All properties should exist even if its value is null or undefined.
Thanks for the report. I'm starting my vacation today, so I won't be able to look at it in the next two weeks.
I think you forgot the definition of Foo in your reproduction.
Added Foo definition
This appears to happen only when the type of the var is Unit or Null (whether inferred, or explicitly written). It does not seem to be related to having a supertrait, since I can also reproduce the issue when the trait declares the member but the class implements it with a more specific type that is explicitly Null or Unit.
Also, I can reproduce this with a named class, local or top-level. So it's also not related to anonymous classes.
The situations where this issue pops up are therefore summarized as:
- A field of type
UnitorNullin a non-native JS class.
Related: constant-value fields are also lost:
class Bar extends Foo {
final val extra = "foo"
}
The culprits are https://github.com/lampepfl/dotty/blob/c99f6caa74e74a67dd42e8df6ede53c29cd7fce9/compiler/src/dotty/tools/dotc/transform/Memoize.scala#L151-L154 and https://github.com/lampepfl/dotty/blob/c99f6caa74e74a67dd42e8df6ede53c29cd7fce9/compiler/src/dotty/tools/dotc/transform/Memoize.scala#L162 They should not apply to members of non-native JS classes.
Both cases are also problematic for @JSExportTopLevel vals and vars.
@sjrd I also hit this issue when trying to implement an object comparison method like deepEquals(jsObjectA, jsObjectB) in Scala 3 + Scala.js.