From 5e9aa38950c936340491f678f897717f7f49faff Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 2 Nov 2015 19:14:20 +0300 Subject: [PATCH] More precise type handling for equality #KT-2311 Fixed --- .../smartcasts/DelegatingDataFlowInfo.java | 11 +++++++ .../tests/smartCasts/typeDegradation.kt | 17 ++++++++++ .../tests/smartCasts/typeDegradation.txt | 32 +++++++++++++++++++ .../tests/smartCasts/typeInComparison.kt | 8 +++++ .../tests/smartCasts/typeInComparison.txt | 3 ++ .../checkers/DiagnosticsTestGenerated.java | 12 +++++++ 6 files changed, 83 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/smartCasts/typeDegradation.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/typeDegradation.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/typeInComparison.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/typeInComparison.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java index 3044c9b48cd..e642cbddfb2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.java @@ -19,8 +19,10 @@ package org.jetbrains.kotlin.resolve.calls.smartcasts; import com.google.common.collect.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeUtils; +import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import java.util.HashSet; import java.util.LinkedHashSet; @@ -216,6 +218,15 @@ import static org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability.NOT_NULL SetMultimap newTypeInfo = newTypeInfo(); newTypeInfo.putAll(a, collectTypesFromMeAndParents(b)); newTypeInfo.putAll(b, collectTypesFromMeAndParents(a)); + if (!a.getType().equals(b.getType())) { + // To avoid smart casts to Nothing or Nothing? and recording base types of own type + if (!KotlinBuiltIns.isNothingOrNullableNothing(b.getType()) && !TypeUtilsKt.isSubtypeOf(a.getType(), b.getType())) { + newTypeInfo.put(a, b.getType()); + } + if (!KotlinBuiltIns.isNothingOrNullableNothing(a.getType()) && !TypeUtilsKt.isSubtypeOf(b.getType(), a.getType())) { + newTypeInfo.put(b, a.getType()); + } + } changed |= !newTypeInfo.isEmpty(); return !changed diff --git a/compiler/testData/diagnostics/tests/smartCasts/typeDegradation.kt b/compiler/testData/diagnostics/tests/smartCasts/typeDegradation.kt new file mode 100644 index 00000000000..8431470f568 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/typeDegradation.kt @@ -0,0 +1,17 @@ +open class VeryBase + +open class Base : VeryBase() + +class Derived : Base() { + fun original(): VeryBase = this +} + +class Another : Base() + +fun foo(d: Derived, a: Another?): Base? { + // d is compared with d.original(): VeryBase but should retain its own type + if (d.original() != d) return null + // ad should be of type Base, not VeryBase + val ad = a ?: d + return ad +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/typeDegradation.txt b/compiler/testData/diagnostics/tests/smartCasts/typeDegradation.txt new file mode 100644 index 00000000000..55b519f9a7d --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/typeDegradation.txt @@ -0,0 +1,32 @@ +package + +public fun foo(/*0*/ d: Derived, /*1*/ a: Another?): Base? + +public final class Another : Base { + public constructor Another() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class Base : VeryBase { + public constructor Base() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Derived : Base { + public constructor Derived() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun original(): VeryBase + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class VeryBase { + public constructor VeryBase() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/typeInComparison.kt b/compiler/testData/diagnostics/tests/smartCasts/typeInComparison.kt new file mode 100644 index 00000000000..c3ed05c0a59 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/typeInComparison.kt @@ -0,0 +1,8 @@ +fun foo(): Int { + val x: Any? = null + val y = 2 + if (x == y) { + return x + y + } + return y +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/typeInComparison.txt b/compiler/testData/diagnostics/tests/smartCasts/typeInComparison.txt new file mode 100644 index 00000000000..b02182627c0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/typeInComparison.txt @@ -0,0 +1,3 @@ +package + +public fun foo(): kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 19bb652634a..a71b1809d96 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -14643,6 +14643,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("typeDegradation.kt") + public void testTypeDegradation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/typeDegradation.kt"); + doTest(fileName); + } + + @TestMetadata("typeInComparison.kt") + public void testTypeInComparison() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/typeInComparison.kt"); + doTest(fileName); + } + @TestMetadata("varChangedInInitializer.kt") public void testVarChangedInInitializer() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/varChangedInInitializer.kt");