Closed
Description
Summary
It should not be legal to reference constructor parameters in the supertypes of a class:
class Evil(val outer: Outer) extends Foo[outer.type](...)
class Evil(val outer: Outer) extends outer.Foo(...)
Either of those two things can be used to create unsoundness in the form of a ClassCastException
, as shown below.
Fundamentally, the specification should reject those, as in either case, the linearization of Evil
is ill-defined. Since the linearization is ill-defined, so is baseType
, and everything falls down.
Note that Scala 2 rejects both variants, at least as far back as 2.10.9. @smarter's thesis calculus does not include constructor parameters in the context when typing parent types either.
Compiler version
Today's main
, commit 7fd161f
Minimized code
First variant: outer
in a type parameter
class Outer {
type Smuggler
var smuggler: Option[Smuggler] = None
}
class Foo[T](var unpack: T)
class Evil(val outer: Outer, extract: outer.type => Unit) extends Foo[outer.type](outer) {
def doExtract(): Unit = extract(unpack)
}
object Test {
def main(args: Array[String]): Unit = {
val outer1 = new Outer { type Smuggler = Int }
outer1.smuggler = Some(5)
val evil1 = new Evil(outer1, _ => ())
val outer2 = new Outer { type Smuggler = String }
var extractedOuter2: Option[outer2.type] = None
val evil2 = new Evil(outer2, x => extractedOuter2 = Some(x))
evil2.unpack = evil1.unpack
evil2.doExtract()
val smuggled: String = extractedOuter2.get.smuggler.get // <-- Line 32 is here
println(smuggled)
}
}
Second variant: outer
in the path of the superclass
class Outer {
class Foo(var unpack: Outer.this.type)
type Smuggler
var smuggler: Option[Smuggler] = None
}
class Evil(val outer: Outer, extract: outer.type => Unit) extends outer.Foo(outer) {
def doExtract(): Unit = extract(unpack)
}
// same object Test
Then run:
> scalac Reproduction.scala
> scala Test
Output
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Test$.main(hello.scala:32)
at Test.main(hello.scala)
Expectation
The compiler should reject either of those.
Scala 2 reports:
tests/run/hello.scala:42: error: not found: value outer
class Evil(val outer: Outer) extends Foo[outer.type](outer)
^
and
tests/run/hello.scala:43: error: not found: value outer
class Evil(val outer: Outer) extends outer.Foo
^