Skip to content

Commit

Permalink
KT-53465, KT-53677 Get rid of unnecessary checkcasts to array of reif…
Browse files Browse the repository at this point in the history
…ied type

(cherry picked from commit a75d5ba)
  • Loading branch information
strangepleasures authored and udalov committed Oct 28, 2022
1 parent 2587f3e commit 7a25213
Show file tree
Hide file tree
Showing 17 changed files with 213 additions and 1 deletion.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.backend.jvm.unboxInlineClass
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
Expand All @@ -36,6 +37,9 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.getArgument
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.isTypeVariableType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Handle
import org.jetbrains.org.objectweb.asm.Opcodes
Expand Down Expand Up @@ -88,6 +92,8 @@ private class TypeOperatorLowering(private val backendContext: JvmBackendContext
builder.irAs(argument, type)
argument.type.isInlineClassType() && argument.type.isSubtypeOfClass(type.erasedUpperBound.symbol) ->
argument
isCompatibleArrayType(argument.type, type) ->
argument
type.isNullable() || argument.isDefinitelyNotNull() ->
builder.irAs(argument, type)
else -> {
Expand Down Expand Up @@ -121,6 +127,22 @@ private class TypeOperatorLowering(private val backendContext: JvmBackendContext
}
}

private fun isCompatibleArrayType(actualType: IrType, expectedType: IrType): Boolean {
var actual = actualType
var expected = expectedType
while ((actual.isArray() || actual.isNullableArray()) && (expected.isArray() || expected.isNullableArray())) {
actual = actual.getArrayElementLowerType()
expected = expected.getArrayElementLowerType()
}
if (actual == actualType || expected == expectedType) return false
return actual.isSubtypeOfClass(expected.erasedUpperBound.symbol)
}

private fun IrType.getArrayElementLowerType(): IrType =
if (isBoxedArray && this is IrSimpleType && (arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE)
backendContext.irBuiltIns.anyNType
else getArrayElementType(backendContext.irBuiltIns)

// TODO extract null check elimination on IR somewhere?
private fun IrExpression.isDefinitelyNotNull(): Boolean =
when (this) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// TARGET_BACKEND: JVM

inline fun <reified T : CharSequence> f(x: Array<in String>) = x as Array<T>

fun box(): String = try {
f<String>(arrayOf<Any>(42))
"Fail"
} catch (e: Exception) {
"OK"
}
10 changes: 10 additions & 0 deletions compiler/testData/codegen/box/casts/arrayDowncatingInvariant.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// TARGET_BACKEND: JVM

inline fun <reified T : CharSequence> f(x: Array<Any>) = x as Array<T>

fun box(): String = try {
f<String>(arrayOf<Any>(42))
"Fail"
} catch (e: Exception) {
"OK"
}
10 changes: 10 additions & 0 deletions compiler/testData/codegen/box/casts/arrayDownctingCovariant.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// TARGET_BACKEND: JVM

inline fun <reified T : CharSequence> f(x: Array<out Any>) = x as Array<T>

fun box(): String = try {
f<String>(arrayOf<Int>(42))
"Fail"
} catch (e: Exception) {
"OK"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ abstract class Base {
private fun test(): String = "OK"

fun test(d: Derived): String = (d as Base).test()

fun test(d: Array<out Derived>) = (d as Array<out Base>)[0].test()
}

class Derived : Base()

fun box(): String = Derived().test(Derived())
fun box(): String {
Derived().test(arrayOf(Derived()))
return Derived().test(Derived())
}
29 changes: 29 additions & 0 deletions compiler/testData/codegen/box/casts/kt53677.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// WITH_STDLIB
// WITH_COROUTINES
// DONT_TARGET_EXACT_BACKEND: JVM
// DONT_TARGET_EXACT_BACKEND: JS

import kotlin.coroutines.*

public inline fun <reified T> myEmptyArray(): Array<T> = arrayOfNulls<T>(0) as Array<T>

inline fun <reified T> Array<out T>?.myOrEmpty(): Array<out T> = this ?: myEmptyArray<T>()

fun <T> runBlocking(c: suspend () -> T): T {
var res: T? = null
c.startCoroutine(Continuation(EmptyCoroutineContext) {
res = it.getOrThrow()
})
return res!!
}

suspend fun suspendHere(x: String) {}

suspend fun main() {
arrayOf("1").myOrEmpty().forEach { suspendHere(it) }
}

fun box(): String {
runBlocking(::main)
return "OK"
}
15 changes: 15 additions & 0 deletions compiler/testData/codegen/bytecodeText/checkcast/kt53465.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// TARGET_BACKEND: JVM_IR

public inline fun <reified T> myEmptyArray(): Array<T> = arrayOfNulls<T>(0) as Array<T>

inline fun <reified T> Array<out T>?.myOrEmpty(): Array<out T> = this ?: myEmptyArray<T>()

fun foo(a : Array<String>?) = a.myOrEmpty()

val a = arrayOf<Int>(1) as Array<Any>

val b = arrayOf<Int>(1) as Array<Int>

val c = arrayOf(arrayOf<Int>(1)) as Array<Array<Any>?>

// 0 CHECKCAST

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import com.android.tools.r8.*;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import kotlin.Pair;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.test.KtAssert;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7a25213

Please sign in to comment.