Skip to content

Commit e159fa1

Browse files
committed
Local classes are uncheckable (type tests)
1 parent f0dd0eb commit e159fa1

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ object TypeTestsCasts {
152152
case AnnotatedType(t, _) => recur(X, t)
153153
case tp2: RefinedType => recur(X, tp2.parent) && TypeComparer.hasMatchingMember(tp2.refinedName, X, tp2)
154154
case tp2: RecType => recur(X, tp2.parent)
155+
case tp2
156+
if tp2.typeSymbol.isLocal =>
157+
val sym = tp2.typeSymbol
158+
val methodSymbol = sym.owner
159+
val tpSyms = typer.ErrorReporting.substitutableTypeSymbolsInScope(sym).toSet
160+
def isAccessible(sym: Symbol): Boolean = sym == methodSymbol || sym.isType && isAccessible(sym.owner)
161+
def hasPoison(tp: Type): Boolean =
162+
tp.baseClasses.filter(isAccessible).exists { sym =>
163+
sym.info.decls.exists { sym =>
164+
sym.info.existsPart(tp => tpSyms.contains(tp.typeSymbol))
165+
|| isAccessible(sym.info.typeSymbol.maybeOwner) && hasPoison(sym.info)
166+
}
167+
}
168+
!hasPoison(tp2)
155169
case _ => true
156170
})
157171

tests/neg/i4812.check

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- Error: tests/neg/i4812.scala:8:11 -----------------------------------------------------------------------------------
2+
8 | case prev: A => // error: the type test for A cannot be checked at runtime
3+
| ^
4+
| the type test for A cannot be checked at runtime
5+
-- Error: tests/neg/i4812.scala:18:11 ----------------------------------------------------------------------------------
6+
18 | case prev: A => // error: the type test for A cannot be checked at runtime
7+
| ^
8+
| the type test for A cannot be checked at runtime
9+
-- Error: tests/neg/i4812.scala:28:11 ----------------------------------------------------------------------------------
10+
28 | case prev: A => // error: the type test for A cannot be checked at runtime
11+
| ^
12+
| the type test for A cannot be checked at runtime
13+
-- Error: tests/neg/i4812.scala:38:11 ----------------------------------------------------------------------------------
14+
38 | case prev: A => // error: the type test for A cannot be checked at runtime
15+
| ^
16+
| the type test for A cannot be checked at runtime
17+
-- Error: tests/neg/i4812.scala:50:13 ----------------------------------------------------------------------------------
18+
50 | case prev: A => // error: the type test for A cannot be checked at runtime
19+
| ^
20+
| the type test for A cannot be checked at runtime

tests/neg/i4812.scala

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// scalac: -Werror
2+
object Test:
3+
var prev: Any = _
4+
5+
def test[T](x: T): T =
6+
class A(val elem: (T, Boolean))
7+
prev match
8+
case prev: A => // error: the type test for A cannot be checked at runtime
9+
prev.elem._1
10+
case _ =>
11+
prev = new A((x, true))
12+
x
13+
14+
def test2[T](x: T): T =
15+
abstract class Parent(_elem: T) { def elem: T = _elem }
16+
class A extends Parent(x)
17+
prev match
18+
case prev: A => // error: the type test for A cannot be checked at runtime
19+
prev.elem
20+
case _ =>
21+
prev = new A
22+
x
23+
24+
def test3[T](x: T): T =
25+
class Holder(val elem: T)
26+
class A(val holder: Holder)
27+
prev match
28+
case prev: A => // error: the type test for A cannot be checked at runtime
29+
prev.holder.elem
30+
case _ =>
31+
prev = new A(new Holder(x))
32+
x
33+
34+
def test4[T](x: T): T =
35+
class Holder(val elem: (Int, (Unit, (T, Boolean))))
36+
class A { var holder: Holder = null }
37+
prev match
38+
case prev: A => // error: the type test for A cannot be checked at runtime
39+
prev.holder.elem._2._2._1
40+
case _ =>
41+
val a = new A
42+
a.holder = new Holder((42, ((), (x, true))))
43+
prev = a
44+
x
45+
46+
class Foo[U]:
47+
def test5(x: U): U =
48+
class A(val elem: U)
49+
prev match
50+
case prev: A => // error: the type test for A cannot be checked at runtime
51+
prev.elem
52+
case _ =>
53+
prev = new A(x)
54+
x
55+
56+
def main(args: Array[String]): Unit =
57+
test(1)
58+
val x: String = test("") // was: ClassCastException: java.lang.Integer cannot be cast to java.lang.String

0 commit comments

Comments
 (0)