Skip to content

Commit 8032171

Browse files
committed
Handle unchecked scrutinee
1 parent d2a12f1 commit 8032171

File tree

3 files changed

+30
-12
lines changed

3 files changed

+30
-12
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ object TypeTestsCasts {
123123

124124
}
125125

126+
lazy val scrutineeIsUnchecked = X.widenTermRefExpr.existsPart {
127+
case AnnotatedType(_, annot) if annot.symbol == defn.UncheckedAnnot => true
128+
case _ => false
129+
}
130+
126131
def recur(X: Type, P: Type): Boolean = (X <:< P) || (P.dealias match {
127132
case _: SingletonType => true
128133
case _: TypeProxy
@@ -153,7 +158,7 @@ object TypeTestsCasts {
153158
case tp2: RefinedType => recur(X, tp2.parent) && TypeComparer.hasMatchingMember(tp2.refinedName, X, tp2)
154159
case tp2: RecType => recur(X, tp2.parent)
155160
case tp2
156-
if tp2.typeSymbol.isLocal =>
161+
if tp2.typeSymbol.isLocal && !scrutineeIsUnchecked =>
157162
val sym = tp2.typeSymbol
158163
val methodSymbol = sym.owner
159164
val tpSyms = typer.ErrorReporting.substitutableTypeSymbolsInScope(sym).toSet

tests/neg/i4812.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
| ^
2020
| the type test for A cannot be checked at runtime
2121
-- Error: tests/neg/i4812.scala:60:11 ----------------------------------------------------------------------------------
22-
60 | case prev: Foo => // error: the type test for A cannot be checked at runtime
22+
60 | case prev: A => // error: the type test for A cannot be checked at runtime
2323
| ^
24-
| the type test for Foo cannot be checked at runtime
24+
| the type test for A cannot be checked at runtime

tests/neg/i4812.scala

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,32 @@ object Test:
5454
x
5555

5656
def test6[T](x: T): T =
57-
class Foo { var bar: Bar = null }
58-
class Bar { var foo: Foo = null; var elem: T = _ }
57+
class A { var b: B = null }
58+
class B { var a: A = null; var elem: T = _ }
5959
prev match
60-
case prev: Foo => // error: the type test for A cannot be checked at runtime
61-
prev.bar.elem
60+
case prev: A => // error: the type test for A cannot be checked at runtime
61+
prev.b.elem
6262
case _ =>
63-
val foo = new Foo
64-
val bar = new Bar
65-
bar.elem = x
66-
foo.bar = bar
67-
prev = foo
63+
val a = new A
64+
val b = new B
65+
b.elem = x
66+
a.b = b
67+
prev = a
6868
x
6969

70+
def test7[T](x: T): T =
71+
class A(val elem: T)
72+
prev match
73+
case prev: A @unchecked => prev.elem
74+
case _ => prev = new A(x); x
75+
76+
def test8[T](x: T): T =
77+
class A(val elem: T)
78+
val p = prev
79+
(p: @unchecked) match
80+
case prev: A => prev.elem
81+
case _ => prev = new A(x); x
82+
7083
def main(args: Array[String]): Unit =
7184
test(1)
7285
val x: String = test("") // was: ClassCastException: java.lang.Integer cannot be cast to java.lang.String

0 commit comments

Comments
 (0)