JS_IR: fix typecheck corner case
Consider `fun <E : I> foo(a: Any?) = a as? E`, where I is an interface. This check used to fail, because the `a == null` was missing, and the `isInterface` stdlib method crashes if the first argument is null. This change adds the null check. Also this change prettifies the instance check in case of type parameter left operand.
This commit is contained in:
committed by
Anton Bannykh
parent
9a971172c9
commit
d6fcde7316
@@ -41,7 +41,7 @@ private fun IrType.isClassWithNamePrefix(prefix: String, packageFqName: FqName):
|
||||
return parent.fqName == packageFqName
|
||||
}
|
||||
|
||||
private fun IrType.superTypes(): List<IrType> = classifierOrNull?.superTypes() ?: emptyList()
|
||||
fun IrType.superTypes(): List<IrType> = classifierOrNull?.superTypes() ?: emptyList()
|
||||
|
||||
fun IrType.isFunctionTypeOrSubtype(): Boolean = DFS.ifAny(listOf(this), IrType::superTypes, IrType::isFunction)
|
||||
fun IrType.isSuspendFunctionTypeOrSubtype(): Boolean = DFS.ifAny(listOf(this), IrType::superTypes, IrType::isSuspendFunction)
|
||||
|
||||
+10
-3
@@ -151,6 +151,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
// Note: native `instanceOf` is not used which is important because of null-behaviour
|
||||
private fun advancedCheckRequired(type: IrType) = type.isInterface() ||
|
||||
type.isTypeParameter() && type.superTypes().any { it.isInterface() } ||
|
||||
type.isArray() ||
|
||||
type.isPrimitiveArray() ||
|
||||
isTypeOfCheckingType(type)
|
||||
@@ -261,10 +262,16 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
// TODO either remove functions with reified type parameters or support this case
|
||||
// assert(!typeParameter.isReified) { "reified parameters have to be lowered before" }
|
||||
return typeParameter.superTypes.fold(litTrue) { r, t ->
|
||||
|
||||
return typeParameter.superTypes.fold<IrType, IrExpression?>(null) { r, t ->
|
||||
val check = generateTypeCheckNonNull(argument.copy(), t.makeNotNull())
|
||||
calculator.and(r, check)
|
||||
}
|
||||
|
||||
if (r == null) {
|
||||
check
|
||||
} else {
|
||||
calculator.andand(r, check)
|
||||
}
|
||||
} ?: litTrue
|
||||
}
|
||||
|
||||
// private fun generateCheckForChar(argument: IrExpression) =
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
interface I
|
||||
|
||||
fun <E: I> foo(a: Any?): E? = a as? E
|
||||
|
||||
fun box() = foo<I>(null) ?: "OK"
|
||||
+5
@@ -2821,6 +2821,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/casts/notIs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt")
|
||||
public void testNullableSafeCastToTypeParameterWithInterfaceUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsAny.kt")
|
||||
public void testUnitAsAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/unitAsAny.kt");
|
||||
|
||||
+5
@@ -2821,6 +2821,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/casts/notIs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt")
|
||||
public void testNullableSafeCastToTypeParameterWithInterfaceUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsAny.kt")
|
||||
public void testUnitAsAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/unitAsAny.kt");
|
||||
|
||||
+5
@@ -2801,6 +2801,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/casts/notIs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt")
|
||||
public void testNullableSafeCastToTypeParameterWithInterfaceUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsAny.kt")
|
||||
public void testUnitAsAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/unitAsAny.kt");
|
||||
|
||||
+5
@@ -2801,6 +2801,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/casts/notIs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt")
|
||||
public void testNullableSafeCastToTypeParameterWithInterfaceUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsAny.kt")
|
||||
public void testUnitAsAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/unitAsAny.kt");
|
||||
|
||||
Generated
+5
@@ -2246,6 +2246,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/casts/notIs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt")
|
||||
public void testNullableSafeCastToTypeParameterWithInterfaceUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsAny.kt")
|
||||
public void testUnitAsAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/unitAsAny.kt");
|
||||
|
||||
+5
@@ -2246,6 +2246,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/casts/notIs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt")
|
||||
public void testNullableSafeCastToTypeParameterWithInterfaceUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/nullableSafeCastToTypeParameterWithInterfaceUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unitAsAny.kt")
|
||||
public void testUnitAsAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/unitAsAny.kt");
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class KotlinpTestGenerated extends AbstractKotlinpTest {
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTestData() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("libraries/tools/kotlinp/testData"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("libraries/tools/kotlinp/testData"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("Annotations.kt")
|
||||
|
||||
Reference in New Issue
Block a user