blob: 231dca4ce71daa9f6a58207c0c6291a120243872 (
plain) (
blame)
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
|
class Outer {
def assertNoFields(c: Class[_]) {
assert(c.getDeclaredFields.isEmpty)
}
def assertHasOuter(c: Class[_]) {
assert(c.getDeclaredFields.exists(_.getName.contains("outer")))
}
class Member
final class FinalMember
def test {
assertHasOuter(classOf[Member])
assertNoFields(classOf[FinalMember])
final class C
assertNoFields(classOf[C])
class D
assertNoFields(classOf[D])
(() => {class E; assertNoFields(classOf[E])}).apply()
// The outer reference elision currently runs on a class-by-class basis. If it cannot rule out that a class has
// subclasses, it will not remove the outer reference. A smarter analysis here could detect if no members of
// a sealed (or effectively sealed) hierarchy use the outer reference, the optimization could be performed.
class Parent
class Child extends Parent
assertHasOuter(classOf[Parent])
// Note: outer references (if they haven't been elided) are used in pattern matching as follows.
// This isn't relevant to term-owned classes, as you can't refer to them with a prefix that includes
// the outer class.
val outer1 = new Outer
val outer2 = new Outer
(new outer1.Member: Any) match {
case _: outer2.Member => sys.error("wrong match!")
case _: outer1.Member => // okay
}
// ... continuing on that theme, note that `Member` isn't considered as a local class, it is owned by a the class
// `LocalOuter`, which itself happens to be term-owned. So we expect that it has an outer reference, and that this
// is respected in type tests.
class LocalOuter {
class Member
final class FinalMember
}
assertNoFields(classOf[LocalOuter])
assertHasOuter(classOf[LocalOuter#Member])
val localOuter1 = new LocalOuter
val localOuter2 = new LocalOuter
(new localOuter1.Member: Any) match {
case _: localOuter2.Member => sys.error("wrong match!")
case _: localOuter1.Member => // okay
}
// Final member classes still lose the outer reference.
assertNoFields(classOf[LocalOuter#FinalMember])
}
}
object Test {
def main(args: Array[String]): Unit = {
new Outer().test
}
}
|