1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
// Summary of incorrect or questionable behavior.
// Full code and successful parts follow.
object Summary {
class Outer {
class Inner { }
def f() = { class MethodInner ; new MethodInner }
}
// 1 static issue:
//
// Given method in MethodInner: def g(other: MethodInner) = ()
// method1.g(method1) fails to compile with type error.
//
// Note that this cannot be worked around by widening the return type
// of f() because MethodInner is declared inside of f. So there is no way
// I see for a class declared inside a method to receive members of its
// own declared type -- not only the narrow type of those from this
// instance, but ANY members, because there is no Foo#Bar syntax which will
// traverse a method.
//
// 4 runtime issues:
//
// From the outside: inner1.isInstanceOf[outer2.Inner] is true, should (maybe) be false
// From inside inner1: inner2.isInstanceOf[Outer.this.Inner] is true, should (maybe) be false
// From the outside: inner1 match { case _: outer2.Inner => true ... } is true, should definitely be false
// From inside method1: method2 match { case _: MethodInner => true ... } is true, should definitely be false
//
// Note that the fact that every test returns true on instances of MethodInner means
// that it is impossible to draw any type distinction between instances. As far as one
// can tell, they are all of the same type regardless not only of whether they were
// created on the same method invocation but whether they are contained in the same
// instance of Outer.
//
// WRT "same method invocation", see Iterator.duplicate for an example of this.
}
// Tests
class Outer {
class Inner {
def passOuter(other: Outer) = () // pass any Outer
def passThisType(other: Outer.this.type) = () // pass only this Outer instance
def passInner(other: Inner) = () // pass only Inners from this Outer instance
def passInner2(other: Outer.this.Inner) = () // same as above
def passInnerSharp(other: Outer#Inner) = () // pass any Inner
def compareSimpleWithTypeMatch(other: Any) = other match {
case _: Inner => true
case _ => false
}
def compareSimpleWithInstanceOf(other: Any) = other.isInstanceOf[Inner]
def compareSharpWithTypeMatch(other: Any) = {
other match {
case _: Outer#Inner => true
case _ => false
}
}
def compareSharpWithInstanceOf(other: Any) = other.isInstanceOf[Outer#Inner]
def comparePathWithTypeMatch(other: Any) = other match {
case _: Outer.this.Inner => true
case _ => false
}
def comparePathWithInstanceOf(other: Any) = other.isInstanceOf[Outer.this.Inner]
}
def f() = {
class MethodInner {
def passOuter(other: Outer) = () // pass any Outer
def passThisType(other: Outer.this.type) = () // pass only this Outer instance
def passInner(other: Inner) = () // pass only Inners from this Outer instance
def passInner2(other: Outer.this.Inner) = () // same as above
def passInnerSharp(other: Outer#Inner) = () // pass any Inner
def passMethodInner(other: MethodInner) = () // pass only MethodInners from this Outer instance
// is there any way to refer to Outer#MethodInner? Not that there should be.
def compareWithInstanceOf(other: Any) = other.isInstanceOf[MethodInner]
def compareWithTypeMatch(other: Any) = other match {
case _: MethodInner => true
case _ => false
}
}
new MethodInner
}
}
object Test {
val outer1 = new Outer
val outer2 = new Outer
val inner1 = new outer1.Inner
val inner2 = new outer2.Inner
val method1 = outer1.f()
val method2 = outer2.f()
def testInnerStatic = {
// these should all work
inner1.passOuter(outer1)
inner1.passOuter(outer2)
inner1.passThisType(outer1)
inner1.passInner(inner1)
inner1.passInner2(inner1)
inner1.passInnerSharp(inner1)
inner1.passInnerSharp(inner2)
// these should all fail to compile, and do
//
// inner1.passThisType(outer2)
// inner1.passInner(inner2)
// inner1.passInner2(inner2)
}
def testInnerRuntime = {
println("testInnerRuntime\n")
List("These should be true under any scenario: ",
inner1.isInstanceOf[outer1.Inner] ,
inner1.isInstanceOf[Outer#Inner] ,
(inner1: Any) match { case _: Outer#Inner => true ; case _ => false } ,
(inner1: Any) match { case _: outer1.Inner => true ; case _ => false } ,
inner1.compareSharpWithTypeMatch(inner2) ,
inner1.compareSharpWithInstanceOf(inner2)
) foreach println
List("These should be true under current proposal: ",
inner1.compareSimpleWithInstanceOf(inner2)
) foreach println
List("These should be false under current proposal: ",
inner1.compareSimpleWithTypeMatch(inner2) ,
inner1.comparePathWithTypeMatch(inner2)
) foreach println
List("These return true but I think should return false: ",
inner1.isInstanceOf[outer2.Inner] , // true
inner1.comparePathWithInstanceOf(inner2) // true
) foreach println
List("These are doing the wrong thing under current proposal",
(inner1: Any) match { case _: outer2.Inner => true ; case _ => false } // should be false
) foreach println
}
def testMethodInnerStatic = {
// these should all work
method1.passOuter(outer1)
method1.passOuter(outer2)
method1.passThisType(outer1)
method1.passInner(inner1)
method1.passInner2(inner1)
method1.passInnerSharp(inner1)
method1.passInnerSharp(inner2)
// This fails with:
//
// a.scala:114: error: type mismatch;
// found : Test.method1.type (with underlying type MethodInner forSome { type MethodInner <: java.lang.Object with ScalaObject{def passOuter(other: Outer): Unit; def passThisType(other: Test.outer1.type): Unit; def passInner(other: Test.outer1.Inner): Unit; def passInner2(other: Test.outer1.Inner): Unit; def passInnerSharp(other: Outer#Inner): Unit; def passMethodInner(other: MethodInner): Unit} })
// required: MethodInner where type MethodInner <: java.lang.Object with ScalaObject{def passOuter(other: Outer): Unit; def passThisType(other: Test.outer1.type): Unit; def passInner(other: Test.outer1.Inner): Unit; def passInner2(other: Test.outer1.Inner): Unit; def passInnerSharp(other: Outer#Inner): Unit; def passMethodInner(other: MethodInner): Unit}
// method1.passMethodInner(method1)
// ^
method1.passMethodInner(method1)
// these should all fail to compile, and do
//
// method1.passThisType(outer2)
// method1.passInner(inner2)
// method1.passInner2(inner2)
// method1.passMethodInner(method2)
}
def testMethodInnerRuntime = {
println("\ntestMethodInnerRuntime\n")
List("These should be true under any scenario: ",
method1.compareWithInstanceOf(method1) ,
method1.compareWithTypeMatch(method1)
) foreach println
List("These should be true under current proposal: ",
method1.compareWithInstanceOf(method2)
) foreach println
List("These are doing the wrong thing under current proposal",
method1.compareWithTypeMatch(method2) // should be false
) foreach println
}
def main(args: Array[String]): Unit = {
testInnerRuntime
testMethodInnerRuntime
}
}
|