-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15134 from dwijnand/local-classes-are-uncheckable
Local classes are uncheckable (type tests)
- Loading branch information
Showing
5 changed files
with
214 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
compiler/test/dotty/tools/dotc/transform/TypeTestsCastsTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package dotty.tools | ||
package dotc | ||
package transform | ||
|
||
import core.* | ||
import Contexts.*, Decorators.*, Denotations.*, SymDenotations.*, Symbols.*, Types.* | ||
import Annotations.* | ||
|
||
import org.junit.Test | ||
import org.junit.Assert.* | ||
|
||
class TypeTestsCastsTest extends DottyTest: | ||
val defn = ctx.definitions; import defn.* | ||
|
||
@Test def orL = checkFound(List(StringType, LongType), OrType(LongType, StringType, false)) | ||
@Test def orR = checkFound(List(LongType, StringType), OrType(StringType, LongType, false)) | ||
|
||
@Test def annot = checkFound(List(StringType, LongType), AnnotatedType(OrType(LongType, StringType, false), Annotation(defn.UncheckedAnnot))) | ||
|
||
@Test def andL = checkFound(List(StringType), AndType(StringType, AnyType)) | ||
@Test def andR = checkFound(List(StringType), AndType(AnyType, StringType)) | ||
@Test def andX = checkFound(List(NoType), AndType(StringType, BooleanType)) | ||
|
||
// (A | B) & C => {(A & B), (A & C)} | ||
// A & (B | C) => {(A & B), (A & C)} | ||
// (A | B) & (C | D) => {(A & C), (A & D), (B & C), (B & D)} | ||
@Test def orInAndL = checkFound(List(StringType, LongType), AndType(OrType(LongType, StringType, false), AnyType)) | ||
@Test def orInAndR = checkFound(List(StringType, LongType), AndType(AnyType, OrType(LongType, StringType, false))) | ||
@Test def orInAndZ = | ||
// (Throwable | Exception) & (RuntimeException | Any) = | ||
// Throwable & RuntimeException = RuntimeException | ||
// Throwable & Any = Throwable | ||
// Exception & RuntimeException = RuntimeException | ||
// Exception & Any = Exception | ||
val ExceptionType = defn.ExceptionClass.typeRef | ||
val RuntimeExceptionType = defn.RuntimeExceptionClass.typeRef | ||
val tp = AndType(OrType(ThrowableType, ExceptionType, false), OrType(RuntimeExceptionType, AnyType, false)) | ||
val exp = List(ExceptionType, RuntimeExceptionType, ThrowableType, RuntimeExceptionType) | ||
checkFound(exp, tp) | ||
|
||
def checkFound(found: List[Type], tp: Type) = | ||
val expected = found.map(_.classSymbol) | ||
val obtained = TypeTestsCasts.foundClasses(tp) | ||
assertEquals(expected, obtained) | ||
end TypeTestsCastsTest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
-- Error: tests/neg/i4812.scala:8:11 ----------------------------------------------------------------------------------- | ||
8 | case prev: A => // error: the type test for A cannot be checked at runtime | ||
| ^ | ||
| the type test for A cannot be checked at runtime | ||
-- Error: tests/neg/i4812.scala:18:11 ---------------------------------------------------------------------------------- | ||
18 | case prev: A => // error: the type test for A cannot be checked at runtime | ||
| ^ | ||
| the type test for A cannot be checked at runtime | ||
-- Error: tests/neg/i4812.scala:28:11 ---------------------------------------------------------------------------------- | ||
28 | case prev: A => // error: the type test for A cannot be checked at runtime | ||
| ^ | ||
| the type test for A cannot be checked at runtime | ||
-- Error: tests/neg/i4812.scala:38:11 ---------------------------------------------------------------------------------- | ||
38 | case prev: A => // error: the type test for A cannot be checked at runtime | ||
| ^ | ||
| the type test for A cannot be checked at runtime | ||
-- Error: tests/neg/i4812.scala:50:13 ---------------------------------------------------------------------------------- | ||
50 | case prev: A => // error: the type test for A cannot be checked at runtime | ||
| ^ | ||
| the type test for A cannot be checked at runtime | ||
-- Error: tests/neg/i4812.scala:60:11 ---------------------------------------------------------------------------------- | ||
60 | case prev: A => // error: the type test for A cannot be checked at runtime | ||
| ^ | ||
| the type test for A cannot be checked at runtime | ||
-- Error: tests/neg/i4812.scala:96:11 ---------------------------------------------------------------------------------- | ||
96 | case x: B => // error: the type test for B cannot be checked at runtime | ||
| ^ | ||
| the type test for B cannot be checked at runtime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// scalac: -Werror | ||
object Test: | ||
var prev: Any = _ | ||
|
||
def test[T](x: T): T = | ||
class A(val elem: (T, Boolean)) | ||
prev match | ||
case prev: A => // error: the type test for A cannot be checked at runtime | ||
prev.elem._1 | ||
case _ => | ||
prev = new A((x, true)) | ||
x | ||
|
||
def test2[T](x: T): T = | ||
abstract class Parent(_elem: T) { def elem: T = _elem } | ||
class A extends Parent(x) | ||
prev match | ||
case prev: A => // error: the type test for A cannot be checked at runtime | ||
prev.elem | ||
case _ => | ||
prev = new A | ||
x | ||
|
||
def test3[T](x: T): T = | ||
class Holder(val elem: T) | ||
class A(val holder: Holder) | ||
prev match | ||
case prev: A => // error: the type test for A cannot be checked at runtime | ||
prev.holder.elem | ||
case _ => | ||
prev = new A(new Holder(x)) | ||
x | ||
|
||
def test4[T](x: T): T = | ||
class Holder(val elem: (Int, (Unit, (T, Boolean)))) | ||
class A { var holder: Holder = null } | ||
prev match | ||
case prev: A => // error: the type test for A cannot be checked at runtime | ||
prev.holder.elem._2._2._1 | ||
case _ => | ||
val a = new A | ||
a.holder = new Holder((42, ((), (x, true)))) | ||
prev = a | ||
x | ||
|
||
class Foo[U]: | ||
def test5(x: U): U = | ||
class A(val elem: U) | ||
prev match | ||
case prev: A => // error: the type test for A cannot be checked at runtime | ||
prev.elem | ||
case _ => | ||
prev = new A(x) | ||
x | ||
|
||
def test6[T](x: T): T = | ||
class A { var b: B = null } | ||
class B { var a: A = null; var elem: T = _ } | ||
prev match | ||
case prev: A => // error: the type test for A cannot be checked at runtime | ||
prev.b.elem | ||
case _ => | ||
val a = new A | ||
val b = new B | ||
b.elem = x | ||
a.b = b | ||
prev = a | ||
x | ||
|
||
def test7[T](x: T): T = | ||
class A(val elem: T) | ||
prev match | ||
case prev: A @unchecked => prev.elem | ||
case _ => prev = new A(x); x | ||
|
||
def test8[T](x: T): T = | ||
class A(val elem: T) | ||
val p = prev | ||
(p: @unchecked) match | ||
case prev: A => prev.elem | ||
case _ => prev = new A(x); x | ||
|
||
def test9 = | ||
trait A | ||
class B extends A | ||
val x: A = new B | ||
x match | ||
case x: B => x | ||
|
||
sealed class A | ||
var prevA: A = _ | ||
def test10: A = | ||
val methodCallId = System.nanoTime() | ||
class B(val id: Long) extends A | ||
prevA match | ||
case x: B => // error: the type test for B cannot be checked at runtime | ||
x.ensuring(x.id == methodCallId, s"Method call id $methodCallId != ${x.id}") | ||
case _ => | ||
val x = new B(methodCallId) | ||
prevA = x | ||
x | ||
|
||
def test11 = | ||
trait A | ||
trait B | ||
class C extends A with B | ||
val x: A = new C | ||
x match | ||
case x: B => x | ||
|
||
def test12 = | ||
class Foo | ||
class Bar | ||
val x: Foo | Bar = new Foo | ||
x.isInstanceOf[Foo] | ||
|
||
def main(args: Array[String]): Unit = | ||
test(1) | ||
val x: String = test("") // was: ClassCastException: java.lang.Integer cannot be cast to java.lang.String |