Properly check expression nullability on attempt to apply == optimizations
#Fix KT-19767
This commit is contained in:
@@ -2926,11 +2926,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return genCmpWithZero(left, opToken, pregeneratedLeft);
|
||||
}
|
||||
|
||||
if (pregeneratedLeft == null && left instanceof KtSafeQualifiedExpression && isPrimitive(rightType)) {
|
||||
if (pregeneratedLeft == null && left instanceof KtSafeQualifiedExpression &&
|
||||
isSelectorPureNonNullType((KtSafeQualifiedExpression) left) && isPrimitive(rightType)) {
|
||||
return genCmpSafeCallToPrimitive((KtSafeQualifiedExpression) left, right, rightType, opToken);
|
||||
}
|
||||
|
||||
if (isPrimitive(leftType) && right instanceof KtSafeQualifiedExpression) {
|
||||
if (isPrimitive(leftType) && right instanceof KtSafeQualifiedExpression &&
|
||||
isSelectorPureNonNullType(((KtSafeQualifiedExpression) right))) {
|
||||
return genCmpPrimitiveToSafeCall(left, leftType, (KtSafeQualifiedExpression) right, opToken, pregeneratedLeft);
|
||||
}
|
||||
|
||||
@@ -2979,6 +2981,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return genEqualsForExpressionsPreferIEEE754Arithmetic(left, right, opToken, leftType, rightType, pregeneratedLeft);
|
||||
}
|
||||
|
||||
private boolean isSelectorPureNonNullType(@NotNull KtSafeQualifiedExpression safeExpression) {
|
||||
KtExpression expression = safeExpression.getSelectorExpression();
|
||||
if (expression == null) return false;
|
||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
|
||||
if (resolvedCall == null) return false;
|
||||
KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||
return returnType != null && !TypeUtils.isNullableType(returnType);
|
||||
}
|
||||
|
||||
private StackValue genCmpPrimitiveToSafeCall(
|
||||
@NotNull KtExpression left,
|
||||
@NotNull Type leftType,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
fun foo(p: Int?): Boolean {
|
||||
return M<Int>(p)?.nulled() == 1
|
||||
}
|
||||
|
||||
fun foo2(p: Int?): Boolean {
|
||||
return 1 == M<Int>(p)?.nulled()
|
||||
}
|
||||
|
||||
class M<T: Any>(val z: T?) {
|
||||
fun nulled(): T? = z
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
if (foo(null)) return "fail 1"
|
||||
if (!foo(1)) return "fail 2"
|
||||
|
||||
if (foo2(null)) return "fail 1"
|
||||
if (!foo2(1)) return "fail 2"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//WITH_RUNTIME
|
||||
|
||||
fun box(): String {
|
||||
val map: Map<String, Boolean>? = mapOf()
|
||||
return if (map?.get("") == true) "fail" else "OK"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
// FILE: M.java
|
||||
|
||||
public class M {
|
||||
private final Integer value;
|
||||
|
||||
public M(Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Integer nulled() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FILE: Kotlin.kt
|
||||
fun foo(p: Int?): Boolean {
|
||||
return M(p)?.nulled() == 1
|
||||
}
|
||||
|
||||
fun foo2(p: Int?): Boolean {
|
||||
return 1 == M(p)?.nulled()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (foo(null)) return "fail 1"
|
||||
if (!foo(1)) return "fail 2"
|
||||
|
||||
if (foo2(null)) return "fail 1"
|
||||
if (!foo2(1)) return "fail 2"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
fun foo(p: Int?): Boolean {
|
||||
return M<Int>(p)?.chain()?.nulled() == 1
|
||||
}
|
||||
|
||||
fun foo2(p: Int?): Boolean {
|
||||
return 1 == M<Int>(p)?.chain()?.nulled()
|
||||
}
|
||||
|
||||
class M<T: Any>(val z: T?) {
|
||||
fun nulled(): T? = z
|
||||
|
||||
fun chain(): M<T>? = this
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
if (foo(null)) return "fail 1"
|
||||
if (!foo(1)) return "fail 2"
|
||||
|
||||
if (foo2(null)) return "fail 1"
|
||||
if (!foo2(1)) return "fail 2"
|
||||
return "OK"
|
||||
}
|
||||
+24
@@ -956,6 +956,30 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767.kt")
|
||||
public void testKt19767() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_2.kt")
|
||||
public void testKt19767_2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_3.kt")
|
||||
public void testKt19767_3() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_chain.kt")
|
||||
public void testKt19767_chain() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_chain.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt5493.kt")
|
||||
public void testKt5493() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt5493.kt");
|
||||
|
||||
@@ -956,6 +956,30 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767.kt")
|
||||
public void testKt19767() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_2.kt")
|
||||
public void testKt19767_2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_3.kt")
|
||||
public void testKt19767_3() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_chain.kt")
|
||||
public void testKt19767_chain() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_chain.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt5493.kt")
|
||||
public void testKt5493() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt5493.kt");
|
||||
|
||||
@@ -956,6 +956,30 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767.kt")
|
||||
public void testKt19767() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_2.kt")
|
||||
public void testKt19767_2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_3.kt")
|
||||
public void testKt19767_3() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_chain.kt")
|
||||
public void testKt19767_chain() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_chain.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt5493.kt")
|
||||
public void testKt5493() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt5493.kt");
|
||||
|
||||
+24
@@ -1154,6 +1154,30 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767.kt")
|
||||
public void testKt19767() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_2.kt")
|
||||
public void testKt19767_2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_3.kt")
|
||||
public void testKt19767_3() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19767_chain.kt")
|
||||
public void testKt19767_chain() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt19767_chain.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt5493.kt")
|
||||
public void testKt5493() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/boxingOptimization/kt5493.kt");
|
||||
|
||||
Reference in New Issue
Block a user