From cf75afba66178d9ab2b1ab2a3c0fdc806500fe24 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 3 Jul 2017 10:48:20 +0300 Subject: [PATCH] [NI] Fix type intersection for equal types --- .../regressions/intersectionOfEqualTypes.kt | 18 +++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++++ .../LightAnalysisModeTestGenerated.java | 6 +++++ .../kotlin/types/checker/IntersectionType.kt | 25 +++++++++++++++---- .../semantics/JsCodegenBoxTestGenerated.java | 6 +++++ 6 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt diff --git a/compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt b/compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt new file mode 100644 index 00000000000..220d3759335 --- /dev/null +++ b/compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt @@ -0,0 +1,18 @@ +// WITH_RUNTIME + +// FILE: test.kt + +fun foo() { + takeClass(run { + val outer: Sample? = null + if (outer != null) outer else null + }) +} + +fun takeClass(instanceClass: Sample<*>?) {} +class Sample + +fun box(): String { + foo() + return "OK" +} \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index af6a71ec609..cc2c2cf2153 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -16580,6 +16580,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("intersectionOfEqualTypes.kt") + public void testIntersectionOfEqualTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt"); + doTest(fileName); + } + @TestMetadata("kt10143.kt") public void testKt10143() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 66cb3556ba1..00462cbdee7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -16580,6 +16580,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("intersectionOfEqualTypes.kt") + public void testIntersectionOfEqualTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt"); + doTest(fileName); + } + @TestMetadata("kt10143.kt") public void testKt10143() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b989687e0e4..2dd44409a66 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16580,6 +16580,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("intersectionOfEqualTypes.kt") + public void testIntersectionOfEqualTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt"); + doTest(fileName); + } + @TestMetadata("kt10143.kt") public void testKt10143() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt index 8ea7032602b..b3d8ba97afc 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,22 +99,37 @@ object TypeIntersector { // nullability here is correct private fun intersectTypesWithoutIntersectionType(inputTypes: Set): SimpleType { + if (inputTypes.size == 1) return inputTypes.single() + // Any and Nothing should leave // Note that duplicates should be dropped because we have Set here. - val filteredSupertypes = inputTypes.filterNot { upper -> - inputTypes.any { upper != it && NewKotlinTypeChecker.isSubtypeOf(it, upper) } + val filteredSuperAndEqualTypes = ArrayList(inputTypes) + val iterator = filteredSuperAndEqualTypes.iterator() + while (iterator.hasNext()) { + val upper = iterator.next() + val strictSupertypeOrHasEqual = filteredSuperAndEqualTypes.any { lower -> + lower !== upper && (isStrictSupertype(lower, upper) || NewKotlinTypeChecker.equalTypes(lower, upper)) + } + + if (strictSupertypeOrHasEqual) iterator.remove() } - assert(filteredSupertypes.isNotEmpty()) { + assert(filteredSuperAndEqualTypes.isNotEmpty()) { "This collections cannot be empty! input types: ${inputTypes.joinToString()}" } - if (filteredSupertypes.size < 2) return filteredSupertypes.single() + if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single() val constructor = IntersectionTypeConstructor(inputTypes) return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType()) } + private fun isStrictSupertype(subtype: KotlinType, supertype: KotlinType): Boolean { + return with(NewKotlinTypeChecker) { + isSubtypeOf(subtype, supertype) && !isSubtypeOf(supertype, subtype) + } + } + /** * Let T is type parameter with upper bound Any?. resultNullability(String? & T) = UNKNOWN => String? & T */ diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 0250749457d..0faf8c8ce92 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -20234,6 +20234,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("intersectionOfEqualTypes.kt") + public void testIntersectionOfEqualTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt"); + doTest(fileName); + } + @TestMetadata("kt10143.kt") public void testKt10143() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt");