From d18a14b717194a4afeacf97754738747bf0d71bf Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Tue, 22 Aug 2017 15:25:11 +0300 Subject: [PATCH] [NI] Eliminate special intersection type from result type --- .../model/NewConstraintSystemImpl.kt | 18 +++++++++-- .../approximateIntersectionType.kt | 30 +++++++++++++++++++ .../regressions/intersectionAsLastLambda.kt | 23 ++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 12 ++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 ++++++++ .../LightAnalysisModeTestGenerated.java | 12 ++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 24 +++++++++++++++ 7 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/box/regressions/approximateIntersectionType.kt create mode 100644 compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index a6debcb0d93..53a58d44b8c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -25,10 +25,14 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstituto import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.tower.isSuccess +import org.jetbrains.kotlin.types.IntersectionTypeConstructor import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.contains +import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addToStdlib.safeAs class NewConstraintSystemImpl( private val constraintInjector: ConstraintInjector, @@ -201,7 +205,8 @@ class NewConstraintSystemImpl( override fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) { checkState(State.BUILDING, State.COMPLETION) - constraintInjector.addInitialEqualityConstraint(this, variable.defaultType, resultType, FixVariableConstraintPosition(variable)) + val actualResultType = eliminateSpecialIntersectionType(resultType) ?: resultType + constraintInjector.addInitialEqualityConstraint(this, variable.defaultType, actualResultType, FixVariableConstraintPosition(variable)) notFixedTypeVariables.remove(variable.freshTypeConstructor) for (variableWithConstraint in notFixedTypeVariables.values) { @@ -210,7 +215,16 @@ class NewConstraintSystemImpl( } } - storage.fixedTypeVariables[variable.freshTypeConstructor] = resultType + storage.fixedTypeVariables[variable.freshTypeConstructor] = actualResultType + } + + private fun eliminateSpecialIntersectionType(type: UnwrappedType): UnwrappedType? { + val constructor = type.constructor.safeAs() ?: return null + + if (constructor.supertypes.size != 2) return null + val actualType = constructor.supertypes.singleOrNull { it != type.builtIns.anyType } + + return actualType?.unwrap() } // KotlinConstraintSystemCompleter.Context, PostponedArgumentsAnalyzer.Context diff --git a/compiler/testData/codegen/box/regressions/approximateIntersectionType.kt b/compiler/testData/codegen/box/regressions/approximateIntersectionType.kt new file mode 100644 index 00000000000..0b7b38cab3c --- /dev/null +++ b/compiler/testData/codegen/box/regressions/approximateIntersectionType.kt @@ -0,0 +1,30 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JS, NATIVE + +// FILE: First.java + +import java.util.List; +import java.util.Iterator; + +public class First { + public static List from(List var0) { + return null; + } +} + +// FILE: second.kt + +fun List.listFromJava() = First.from(this) +fun List.listFromKotlin() = fromKotlin(this) + +fun fromKotlin(var0: List): List = var0 + +fun test(a: List) { + val b: List? = a.listFromJava() + val c: List = a.listFromKotlin() +} + +fun box(): String { + test(listOf(1)) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt b/compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt new file mode 100644 index 00000000000..e0667b4f106 --- /dev/null +++ b/compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt @@ -0,0 +1,23 @@ +// IGNORE_BACKEND: JS, NATIVE + +// FILE: First.java + +public class First { + public static First first(K key) { + return null; + } +} + +// FILE: second.kt + +class Inv(val key: T) + +fun lastLambda(x: T, block: (T) -> R): R = block(x) + +fun myTest(m: Inv) { + lastLambda(m) { First.first(it.key) } +} + +fun box(): String { + 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 ee5ff11081f..48c82a48416 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 KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("approximateIntersectionType.kt") + public void testApproximateIntersectionType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateIntersectionType.kt"); + doTest(fileName); + } + @TestMetadata("arrayLengthNPE.kt") public void testArrayLengthNPE() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt"); @@ -16652,6 +16658,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("intersectionAsLastLambda.kt") + public void testIntersectionAsLastLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt"); + doTest(fileName); + } + @TestMetadata("intersectionOfEqualTypes.kt") public void testIntersectionOfEqualTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 31b22549de4..14fe12d94f8 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 { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("approximateIntersectionType.kt") + public void testApproximateIntersectionType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateIntersectionType.kt"); + doTest(fileName); + } + @TestMetadata("arrayLengthNPE.kt") public void testArrayLengthNPE() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt"); @@ -16652,6 +16658,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("intersectionAsLastLambda.kt") + public void testIntersectionAsLastLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt"); + doTest(fileName); + } + @TestMetadata("intersectionOfEqualTypes.kt") public void testIntersectionOfEqualTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6f018a5259e..0157c49c079 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 KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("approximateIntersectionType.kt") + public void testApproximateIntersectionType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateIntersectionType.kt"); + doTest(fileName); + } + @TestMetadata("arrayLengthNPE.kt") public void testArrayLengthNPE() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt"); @@ -16652,6 +16658,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("intersectionAsLastLambda.kt") + public void testIntersectionAsLastLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt"); + doTest(fileName); + } + @TestMetadata("intersectionOfEqualTypes.kt") public void testIntersectionOfEqualTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt"); 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 4ce24ae6fac..3aab74dfe83 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 @@ -20222,6 +20222,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("approximateIntersectionType.kt") + public void testApproximateIntersectionType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateIntersectionType.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + @TestMetadata("arrayLengthNPE.kt") public void testArrayLengthNPE() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt"); @@ -20306,6 +20318,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("intersectionAsLastLambda.kt") + public void testIntersectionAsLastLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionAsLastLambda.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + @TestMetadata("intersectionOfEqualTypes.kt") public void testIntersectionOfEqualTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/intersectionOfEqualTypes.kt");