Skip to content

Commit 37006e3

Browse files
Merge pull request #8713 from dotty-staging/cast-elision
Better cast elision, fix an issue with tailrec
2 parents 4356d70 + 82e7d20 commit 37006e3

File tree

3 files changed

+28
-15
lines changed

3 files changed

+28
-15
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,8 @@ object TypeTestsCasts {
240240

241241
def transformAsInstanceOf(testType: Type): Tree = {
242242
def testCls = testType.widen.classSymbol
243-
if (expr.tpe <:< testType)
244-
Typed(expr, tree.args.head)
243+
if (erasure(expr.tpe) <:< testType)
244+
Typed(expr, tree.args.head) // Replace cast by type ascription (which does not generate any bytecode)
245245
else if (testCls eq defn.BoxedUnitClass)
246246
// as a special case, casting to Unit always successfully returns Unit
247247
Block(expr :: Nil, Literal(Constant(()))).withSpan(expr.span)

compiler/test/dotty/tools/backend/jvm/ArrayApplyOptTest.scala

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,53 +51,53 @@ class ArrayApplyOptTest extends DottyBytecodeTest {
5151
@Test def testArrayApplyBoolean = {
5252
val init = List(Op(DUP), Op(ICONST_0), Op(ICONST_1), Op(BASTORE), Op(DUP), Op(ICONST_1), Op(ICONST_0), Op(BASTORE))
5353
test("Array(true, false)", newArray2Opcodes(T_BOOLEAN, init))
54-
test("IArray(true, false)", newArray2Opcodes(T_BOOLEAN, init :+ TypeOp(CHECKCAST, "[Z")))
54+
test("IArray(true, false)", newArray2Opcodes(T_BOOLEAN, init))
5555
}
5656

5757
@Test def testArrayApplyByte = {
5858
val init = List(Op(DUP), Op(ICONST_0), Op(ICONST_1), Op(BASTORE), Op(DUP), Op(ICONST_1), Op(ICONST_2), Op(BASTORE))
59-
test("Array[Byte](1, 2)", newArray2Opcodes(T_BYTE, init))
60-
test("IArray[Byte](1, 2)", newArray2Opcodes(T_BYTE, init :+ TypeOp(CHECKCAST, "[B")))
59+
test("Array(1: Byte, 2: Byte)", newArray2Opcodes(T_BYTE, init))
60+
test("IArray(1: Byte, 2: Byte)", newArray2Opcodes(T_BYTE, init))
6161
}
6262

6363
@Test def testArrayApplyShort = {
6464
val init = List(Op(DUP), Op(ICONST_0), Op(ICONST_1), Op(SASTORE), Op(DUP), Op(ICONST_1), Op(ICONST_2), Op(SASTORE))
65-
test("Array[Short](1, 2)", newArray2Opcodes(T_SHORT, init))
66-
test("IArray[Short](1, 2)", newArray2Opcodes(T_SHORT, init :+ TypeOp(CHECKCAST, "[S")))
65+
test("Array(1: Short, 2: Short)", newArray2Opcodes(T_SHORT, init))
66+
test("IArray(1: Short, 2: Short)", newArray2Opcodes(T_SHORT, init))
6767
}
6868

6969
@Test def testArrayApplyInt = {
7070
val init = List(Op(DUP), Op(ICONST_0), Op(ICONST_1), Op(IASTORE), Op(DUP), Op(ICONST_1), Op(ICONST_2), Op(IASTORE))
7171
test("Array(1, 2)", newArray2Opcodes(T_INT, init))
72-
test("IArray(1, 2)", newArray2Opcodes(T_INT, init :+ TypeOp(CHECKCAST, "[I")))
72+
test("IArray(1, 2)", newArray2Opcodes(T_INT, init))
7373

74-
val init2 = List(Op(DUP), Op(ICONST_0), Field(GETSTATIC, "Foo$", "MODULE$", "LFoo$;"), Invoke(INVOKEVIRTUAL, "Foo$", "t", "()I", false), Op(IASTORE), Op(DUP), Op(ICONST_1), Field(GETSTATIC, "Foo$", "MODULE$", "LFoo$;"), Invoke(INVOKEVIRTUAL, "Foo$", "t", "()I", false), Op(IASTORE))
75-
test("""Array[T](t, t)""", newArray2Opcodes(T_INT, init2))
76-
test("""IArray[T](t, t)""", newArray2Opcodes(T_INT, init2 :+ TypeOp(CHECKCAST, "[I")))
74+
val init2 = List(Op(DUP), Op(ICONST_0), Field(GETSTATIC, "Foo$", "MODULE$", "LFoo$;"), Invoke(INVOKEVIRTUAL, "Foo$", "t", "()I", false), Op(IASTORE), Op(DUP), Op(ICONST_1), Field(GETSTATIC, "Foo$", "MODULE$", "LFoo$;"), Invoke(INVOKEVIRTUAL, "Foo$", "t", "()I", false), Op(IASTORE), TypeOp(CHECKCAST, "[I"))
75+
test("""Array[T](t, t): Array[T]""", newArray2Opcodes(T_INT, init2))
76+
test("""IArray[T](t, t): IArray[T]""", newArray2Opcodes(T_INT, init2))
7777
}
7878

7979
@Test def testArrayApplyLong = {
8080
val init = List(Op(DUP), Op(ICONST_0), Ldc(LDC, 2), Op(LASTORE), Op(DUP), Op(ICONST_1), Ldc(LDC, 3), Op(LASTORE))
8181
test("Array(2L, 3L)", newArray2Opcodes(T_LONG, init))
82-
test("IArray(2L, 3L)", newArray2Opcodes(T_LONG, init :+ TypeOp(CHECKCAST, "[J")))
82+
test("IArray(2L, 3L)", newArray2Opcodes(T_LONG, init))
8383
}
8484

8585
@Test def testArrayApplyFloat = {
8686
val init = List(Op(DUP), Op(ICONST_0), Ldc(LDC, 2.1f), Op(FASTORE), Op(DUP), Op(ICONST_1), Ldc(LDC, 3.1f), Op(FASTORE))
8787
test("Array(2.1f, 3.1f)", newArray2Opcodes(T_FLOAT, init))
88-
test("IArray(2.1f, 3.1f)", newArray2Opcodes(T_FLOAT, init :+ TypeOp(CHECKCAST, "[F")))
88+
test("IArray(2.1f, 3.1f)", newArray2Opcodes(T_FLOAT, init))
8989
}
9090

9191
@Test def testArrayApplyDouble = {
9292
val init = List(Op(DUP), Op(ICONST_0), Ldc(LDC, 2.2d), Op(DASTORE), Op(DUP), Op(ICONST_1), Ldc(LDC, 3.2d), Op(DASTORE))
9393
test("Array(2.2d, 3.2d)", newArray2Opcodes(T_DOUBLE, init))
94-
test("IArray(2.2d, 3.2d)", newArray2Opcodes(T_DOUBLE, init :+ TypeOp(CHECKCAST, "[D")))
94+
test("IArray(2.2d, 3.2d)", newArray2Opcodes(T_DOUBLE, init))
9595
}
9696

9797
@Test def testArrayApplyChar = {
9898
val init = List(Op(DUP), Op(ICONST_0), IntOp(BIPUSH, 120), Op(CASTORE), Op(DUP), Op(ICONST_1), IntOp(BIPUSH, 121), Op(CASTORE))
9999
test("Array('x', 'y')", newArray2Opcodes(T_CHAR, init))
100-
test("IArray('x', 'y')", newArray2Opcodes(T_CHAR, init :+ TypeOp(CHECKCAST, "[C")))
100+
test("IArray('x', 'y')", newArray2Opcodes(T_CHAR, init))
101101
}
102102

103103
@Test def testArrayApplyUnit = {

tests/pos/i8712.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import scala.annotation.tailrec
2+
3+
sealed trait Foo[+A]
4+
case class Bar[A](f: Foo[A]) extends Foo[A]
5+
case class Done[A](a: A) extends Foo[A]
6+
7+
object Test {
8+
@tailrec
9+
def runT[A](c: Foo[A]): A = c match {
10+
case Bar(f) => runT(f)
11+
case Done(a) => a
12+
}
13+
}

0 commit comments

Comments
 (0)