[K/N] Rework is checks and as casts codegeneration

^KT-58707
^KT-59022
This commit is contained in:
Pavel Kunyavskiy
2023-06-01 10:06:01 +02:00
committed by Space Team
parent b2212b9275
commit f2520a9cb7
21 changed files with 316 additions and 90 deletions
@@ -4961,6 +4961,18 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/casts/kt55005.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -4961,6 +4961,18 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/casts/kt55005.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
-2
View File
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: NATIVE
abstract class A {
abstract val x: Any
+7
View File
@@ -0,0 +1,7 @@
interface A {}
fun <E> getA() = (object : A {}) as A
fun box() : String {
return if (getA<Int>() is A) "OK" else "FAIL"
}
+20
View File
@@ -0,0 +1,20 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
@file:Suppress("INCOMPATIBLE_TYPES", "UNCHECKED_CAST")
fun <T> unchecked(x: Any?) = x as T
fun box() : String{
if (unchecked<String>(null) is Any) return "FAIL 1"
if (unchecked<String>(null) is IntArray) return "FAIL 2"
try {
unchecked<String>(null) as Any
return "FAIL 3"
} catch (e: NullPointerException) {
}
try {
unchecked<String>(null) as IntArray
return "FAIL 4"
} catch (e: NullPointerException) {
}
return "OK"
}
@@ -4757,6 +4757,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -4961,6 +4961,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/casts/kt55005.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -4961,6 +4961,18 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/casts/kt55005.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -4146,6 +4146,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");
@@ -3473,6 +3473,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -3533,6 +3533,18 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -3533,6 +3533,18 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -3533,6 +3533,18 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -1185,7 +1185,7 @@ internal class CodeGeneratorVisitor(
genCatchBlock()
return // Remaining catch clauses are unreachable.
} else {
val isInstance = genInstanceOf(exception, catch.catchParameter.type.getClass()!!)
val isInstance = genInstanceOfImpl(exception, catch.catchParameter.type.getClass()!!)
val body = functionGenerationContext.basicBlock("catch", catch.startLocation)
val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation)
functionGenerationContext.condBr(isInstance, body, nextCheck)
@@ -1519,73 +1519,123 @@ internal class CodeGeneratorVisitor(
val dstClass = value.typeOperand.getClass()
?: error("No class for ${value.typeOperand.render()} from \n${functionGenerationContext.irFunction?.render()}")
val srcArg = evaluateExpression(value.argument, resultSlot)
assert(srcArg.type == codegen.kObjHeaderPtr)
with(functionGenerationContext) {
ifThen(not(genInstanceOf(srcArg, dstClass))) {
if (dstClass.defaultType.isObjCObjectType()) {
val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString()
callDirect(
context.ir.symbols.throwTypeCastException.owner,
listOf(srcArg, codegen.staticData.kotlinStringLiteral(dstFullClassName).llvm),
Lifetime.GLOBAL,
null
)
} else {
val dstTypeInfo = functionGenerationContext.bitcast(llvm.int8PtrType, codegen.typeInfoValue(dstClass))
callDirect(
context.ir.symbols.throwClassCastException.owner,
listOf(srcArg, dstTypeInfo),
Lifetime.GLOBAL,
null
)
return genInstanceOf(
value,
dstClass,
resultSlot,
onSuperClassCast = {
it.takeIf { value.typeOperand.isNullable() }
},
onNull = {
if (value.typeOperand.isNullable()) {
codegen.kNullObjHeaderPtr
} else {
callDirect(
context.ir.symbols.throwNullPointerException.owner,
listOf(),
Lifetime.GLOBAL,
null
)
}
},
onCheck = { argument, checkResult ->
with(functionGenerationContext) {
if (checkResult != kTrue) {
ifThen(not(checkResult)) {
if (dstClass.defaultType.isObjCObjectType()) {
val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString()
callDirect(
context.ir.symbols.throwTypeCastException.owner,
listOf(argument, codegen.staticData.kotlinStringLiteral(dstFullClassName).llvm),
Lifetime.GLOBAL,
null
)
} else {
val dstTypeInfo = functionGenerationContext.bitcast(llvm.int8PtrType, codegen.typeInfoValue(dstClass))
callDirect(
context.ir.symbols.throwClassCastException.owner,
listOf(argument, dstTypeInfo),
Lifetime.GLOBAL,
null
)
}
}
}
argument
}
}
}
}
return srcArg
)
}
//-------------------------------------------------------------------------//
private fun evaluateInstanceOf(value: IrTypeOperatorCall): LLVMValueRef {
context.log{"evaluateInstanceOf : ${ir2string(value)}"}
val type = value.typeOperand
val srcArg = evaluateExpression(value.argument) // Evaluate src expression.
val bbExit = functionGenerationContext.basicBlock("instance_of_exit", value.startLocation)
val bbInstanceOf = functionGenerationContext.basicBlock("instance_of_notnull", value.startLocation)
val bbNull = functionGenerationContext.basicBlock("instance_of_null", value.startLocation)
val condition = functionGenerationContext.icmpEq(srcArg, codegen.kNullObjHeaderPtr)
functionGenerationContext.condBr(condition, bbNull, bbInstanceOf)
functionGenerationContext.positionAtEnd(bbNull)
val resultNull = if (type.isNullable()) kTrue else kFalse
functionGenerationContext.br(bbExit)
functionGenerationContext.positionAtEnd(bbInstanceOf)
val typeOperandClass = value.typeOperand.getClass()
val resultInstanceOf = if (typeOperandClass != null) {
genInstanceOf(srcArg, typeOperandClass)
} else {
// E.g. when generating type operation with reified type parameter in the original body of inline function.
kTrue
// TODO: this code should be unreachable, recheck.
}
functionGenerationContext.br(bbExit)
val bbInstanceOfResult = functionGenerationContext.currentBlock
functionGenerationContext.positionAtEnd(bbExit)
val result = functionGenerationContext.phi(llvm.int1Type)
functionGenerationContext.addPhiIncoming(result, bbNull to resultNull, bbInstanceOfResult to resultInstanceOf)
return result
return genInstanceOf(
value,
type.getClass() ?: context.ir.symbols.any.owner,
resultSlot = null,
onSuperClassCast = { arg ->
if (type.isNullable())
kTrue
else
functionGenerationContext.icmpNe(arg, codegen.kNullObjHeaderPtr)
},
onNull = { if (type.isNullable()) kTrue else kFalse },
onCheck = { _, checkResult -> checkResult }
)
}
//-------------------------------------------------------------------------//
private fun genInstanceOf(obj: LLVMValueRef, dstClass: IrClass) = with(functionGenerationContext) {
private inline fun genInstanceOf(
value: IrTypeOperatorCall,
dstClass: IrClass,
resultSlot: LLVMValueRef?,
onSuperClassCast: (LLVMValueRef) -> LLVMValueRef?,
onNull: () -> LLVMValueRef,
onCheck: (argument: LLVMValueRef, checkResult: LLVMValueRef) -> LLVMValueRef,
) : LLVMValueRef {
val srcArg = evaluateExpression(value.argument, resultSlot)
require(srcArg.type == codegen.kObjHeaderPtr)
val isSuperClassCast = value.argument.type.isSubtypeOfClass(dstClass.symbol)
if (isSuperClassCast) {
onSuperClassCast(srcArg)?.let { return it }
}
return with(functionGenerationContext) {
val bbInstanceOf = basicBlock("instance_of_notnull", value.startLocation)
val bbNull = basicBlock("instance_of_null", value.startLocation)
val condition = icmpEq(srcArg, codegen.kNullObjHeaderPtr)
condBr(condition, bbNull, bbInstanceOf)
positionAtEnd(bbNull)
val resultNull = onNull()
val resultNullBB = currentBlock.takeIf { !isAfterTerminator() }
positionAtEnd(bbInstanceOf)
val resultInstanceOf = onCheck(srcArg, if (isSuperClassCast) kTrue else genInstanceOfImpl(srcArg, dstClass))
val resultInstanceOfBB = currentBlock.also { require(!isAfterTerminator()) }
if (resultNullBB == null) {
resultInstanceOf
} else {
val bbExit = basicBlock("instance_of_exit", value.startLocation)
positionAtEnd(bbExit)
appendingTo(resultInstanceOfBB) { br(bbExit) }
appendingTo(resultNullBB) { br(bbExit) }
val result = phi(value.type.toLLVMType(llvm))
addPhiIncoming(result, resultNullBB to resultNull, resultInstanceOfBB to resultInstanceOf)
result
}
}
}
private fun genInstanceOfImpl(obj: LLVMValueRef, dstClass: IrClass) = with(functionGenerationContext) {
if (dstClass.defaultType.isObjCObjectType()) {
genInstanceOfObjC(obj, dstClass)
} else with(VirtualTablesLookup) {
@@ -272,7 +272,9 @@ private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
// But let's keep it simple here for now; JVM backend doesn't do this anyway.
if (!type.isNullableAny()) {
+returnIfBadType(irGet(valueParameters[i]), type,
// Here, we can't trust value parameter type until we check it, because of @UnsafeVariance
// So we add implicit cast to avoid type check optimization
+returnIfBadType(irImplicitCast(irGet(valueParameters[i]), context.irBuiltIns.anyNType), type,
if (typeSafeBarrierDescription == SpecialGenericSignatures.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
irGet(valueParameters[2])
else irConst(typeSafeBarrierDescription.defaultValue)
@@ -55,37 +55,10 @@ internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLow
private fun lowerCast(expression: IrTypeOperatorCall): IrExpression {
builder.at(expression)
val typeOperand = expression.typeOperand.erasure()
// assert (!TypeUtils.hasNullableSuperType(typeOperand)) // So that `isNullable()` <=> `isMarkedNullable`.
// TODO: consider the case when expression type is wrong e.g. due to generics-related unchecked casts.
return when {
expression.argument.type.isSubtypeOf(typeOperand, context.typeSystem) -> expression.argument
expression.argument.type.isNullable() -> {
with(builder) {
irLetS(expression.argument) { argument ->
irIfThenElse(
type = expression.type,
condition = irEqeqeq(irGet(argument.owner), irNull()),
thenPart = if (typeOperand.isNullable())
irNull()
else
irCall(this@TypeOperatorLowering.context.ir.symbols.throwNullPointerException.owner),
elsePart = irAs(irGet(argument.owner), typeOperand.makeNotNull())
)
}
}
}
typeOperand.isMarkedNullable() -> builder.irAs(expression.argument, typeOperand.makeNotNull())
typeOperand == expression.typeOperand -> expression
else -> builder.irAs(expression.argument, typeOperand)
return if (typeOperand == expression.typeOperand) {
expression
} else {
builder.irAs(expression.argument, typeOperand)
}
}
@@ -3646,6 +3646,18 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -3724,6 +3724,18 @@ public class FirNativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenB
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -3608,6 +3608,18 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -3647,6 +3647,18 @@ public class NativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenBoxT
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@Test
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@Test
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -3111,6 +3111,16 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/casts/kt54802.kt");
}
@TestMetadata("kt58707.kt")
public void testKt58707() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt58707.kt");
}
@TestMetadata("kt59022.kt")
public void testKt59022() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt59022.kt");
}
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");