bug
bug copied to clipboard
problem with anonymous class while using self-type + structural type
Problem occurred when I'm trying to instantiate following class (with self-type construct) by the means of anonymous class (new Foo {...}
)
type F0 = {
def apply() : Unit
}
class Foo {
this: F0 =>
def bar(): Unit = {
println("call apply")
apply()
}
}
Entire code snippet may look like this: ( fails with Error:(13, 19) illegal inheritance; self-type crafts.Main7.Foo does not conform to Main7.this.Foo's selftype crafts.Main7.Foo with crafts.Main7.F0 )
package crafts
object Main7 {
def main(args: Array[String]): Unit = {
val foo = new Foo {
def apply(): Unit = println(s"apply: this: $this")
}
print(s"foo: $foo")
foo.bar()
}
type F0 = {
def apply() : Unit
}
class Foo {
this: F0 =>
def bar(): Unit = {
println("call apply")
apply()
}
}
}
While alternative snippets with 'object foo{...}' or explicite subclassing works correctly
package crafts
object Main7 {
def main(args: Array[String]): Unit = {
{
object foo extends Foo {
def apply(): Unit = println(s"apply: this: $this")
}
print(s"foo: $foo")
foo.bar()
}
{
class Foo_ extends Foo {
def apply(): Unit = println(s"apply: this: $this")
}
val foo = new Foo_
print(s"foo: $foo")
foo.bar()
}
}
type F0 = {
def apply() : Unit
}
class Foo {
this: F0 =>
def bar(): Unit = {
println("call apply")
apply()
}
}
}
Does this count as a duplicate of #9487? That's the root cause, but I think this issue shows how serious it is. I've noticed that the "detect anonymous classes and make their innards private" bit in typedBlock
, the thing that's causing this, is royally broken. This specific issue can be fixed by making the hack more hacky, but I don't think that's a good idea, because it appears to be broken in other ways.
For one, the pattern match to find anonymous-class-new
-blocks is very weak. It catches actual anonymous classes, like new { def hello = "Hello" }
, but it also catches (and breaks)
class Something(val x: { def hello: String })
locally[Something] {
class AmIAnon { def hello = "Hello" }
new Something(new AmIAnon)
// type mismatch: AmIAnon does not conform to { def hello: String }
// are you sure about that, scalac?
// block looks like { class <_>; new <_> }, so scalac starts ruining things
// locally says it wants Something, so scalac lists its members
// then it privatizes stuff that doesn't match in AmIAnon
// scalac has confused *two entirely different classes*
}
except when it doesn't
class Something(val x: { def hello: String })
locally[Something] {
class AmIAnon { def hello = "Hello" }
() // what's a no-op?
new Something(new AmIAnon)
}
I'm not very good at reading the spec, but I think the following counts, too. The relevant parts are 6.10 and the following 6.11. Start with
def identityIsh(t: AnyRef): t.type = t
and try to find the type of
identityIsh(new { def hello = "Hello" })
The new
-expression can expand, producing
identityIsh { class anon extends AnyRef { def hello = "Hello" }; new anon }
The expected type of the block, and thus the simple-new
, is AnyRef
. However, new
doesn't care about expected types, so its type is anon
anyway. Once the type of the block's expression is known, the block's type can also be found without caring about the expected type. That is, the block above should have the same type as a new { def hello = "Hello" }
standing by itself, and that type is AnyRef { def hello: String }
. However, the privatizing is too strong, and it hides the hello
away, making the block have type AnyRef
. This is bad, because although identityIsh
only wants an AnyRef
, which seems to imply that it doesn't matter, the refinement type lets the difference shine through. I believe the spec says the type of the whole should be AnyRef { def hello: String }
, but we get just AnyRef
.
I agree with https://github.com/scala/bug/issues/9487#issuecomment-292438526 that making things private
by editing the anonymous class itself is too much. It would make more sense and (hopefully) be less broken to calculate the structural types of blocks correctly in the first place, even if it is hard.