From bb23556eadf847a390d0f08f2f922d56c303102d Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Tue, 14 Jul 2020 01:26:06 +0300 Subject: [PATCH] Don't perform `Unit`-conversion for functional types with type variables #KT-40269 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 10 ++++++++++ .../calls/components/UnitTypeConversions.kt | 19 ++++++++++++------- ...noUnitConversionForGenericTypeFromArrow.kt | 12 ++++++++++++ ...oUnitConversionForGenericTypeFromArrow.txt | 12 ++++++++++++ ...versionOnReturningGenericFunctionalType.kt | 10 ++++++++++ ...ersionOnReturningGenericFunctionalType.txt | 6 ++++++ .../checkers/DiagnosticsTestGenerated.java | 10 ++++++++++ .../DiagnosticsUsingJavacTestGenerated.java | 10 ++++++++++ 8 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.kt create mode 100644 compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.txt create mode 100644 compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.kt create mode 100644 compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.txt diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index bf709b714f5..9640fad1679 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -24674,6 +24674,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/unitConversion/chainedUnitSuspendConversion.kt"); } + @TestMetadata("noUnitConversionForGenericTypeFromArrow.kt") + public void testNoUnitConversionForGenericTypeFromArrow() throws Exception { + runTest("compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.kt"); + } + + @TestMetadata("noUnitConversionOnReturningGenericFunctionalType.kt") + public void testNoUnitConversionOnReturningGenericFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.kt"); + } + @TestMetadata("unitConversionCompatibility.kt") public void testUnitConversionCompatibility() throws Exception { runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt index ceeed15e6a3..0becae26121 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.components import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.descriptors.ParameterDescriptor -import org.jetbrains.kotlin.resolve.calls.inference.model.LowerPriorityToPreserveCompatibility +import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument @@ -28,8 +28,8 @@ object UnitTypeConversions : ParameterTypeConversion { if (argument !is SimpleKotlinCallArgument) return true val receiver = argument.receiver - if (receiver.receiverValue.type.hasUnitOrSubtypeReturnType()) return true - if (receiver.typesFromSmartCasts.any { it.hasUnitOrSubtypeReturnType() }) return true + if (receiver.receiverValue.type.hasUnitOrSubtypeReturnType(candidate.csBuilder)) return true + if (receiver.typesFromSmartCasts.any { it.hasUnitOrSubtypeReturnType(candidate.csBuilder) }) return true if ( !expectedParameterType.isBuiltinFunctionalType || @@ -39,10 +39,15 @@ object UnitTypeConversions : ParameterTypeConversion { return false } - private fun KotlinType.hasUnitOrSubtypeReturnType(): Boolean = - isFunctionOrKFunctionTypeWithAnySuspendability && arguments.last().type.isUnitOrSubtype() + private fun KotlinType.hasUnitOrSubtypeReturnType(c: ConstraintSystemOperation): Boolean = + isFunctionOrKFunctionTypeWithAnySuspendability && arguments.last().type.isUnitOrSubtypeOrVariable(c) + + private fun KotlinType.isUnitOrSubtypeOrVariable(c: ConstraintSystemOperation): Boolean = + isUnitOrSubtype() || c.isTypeVariable(this) + + private fun KotlinType.isUnitOrSubtype(): Boolean = + isUnit() || isDynamic() || isNothing() - private fun KotlinType.isUnitOrSubtype(): Boolean = isUnit() || isDynamic() || isNothing() override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean = argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionType @@ -53,7 +58,7 @@ object UnitTypeConversions : ParameterTypeConversion { var isFunctionTypeOrSubtype = false val hasReturnTypeInSubtypes = argument.receiver.stableType.isFunctionTypeOrSubtype { isFunctionTypeOrSubtype = true - it.getReturnTypeFromFunctionType().isUnitOrSubtype() + it.getReturnTypeFromFunctionType().isUnitOrSubtype() // there is no need to check for variable as it was done earlier } if (!isFunctionTypeOrSubtype) return false diff --git a/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.kt b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.kt new file mode 100644 index 00000000000..0f5c72758cb --- /dev/null +++ b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.kt @@ -0,0 +1,12 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class Either + +infix fun ((A) -> B).andThen(g: (B) -> C): (A) -> C = TODO() + +fun unsafeRunAsync(cb: (Either) -> Unit) {} + +fun runAsync(cb: (Either) -> Unit) { + unsafeRunAsync(cb.andThen { }) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.txt b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.txt new file mode 100644 index 00000000000..80543186aac --- /dev/null +++ b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.txt @@ -0,0 +1,12 @@ +package + +public fun runAsync(/*0*/ cb: (Either) -> kotlin.Unit): kotlin.Unit +public fun unsafeRunAsync(/*0*/ cb: (Either) -> kotlin.Unit): kotlin.Unit +public infix fun ((A) -> B).andThen(/*0*/ g: (B) -> C): (A) -> C + +public final class Either { + public constructor Either() + 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/unitConversion/noUnitConversionOnReturningGenericFunctionalType.kt b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.kt new file mode 100644 index 00000000000..7be24ab4c6b --- /dev/null +++ b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.kt @@ -0,0 +1,10 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun foo(f: () -> T) {} +fun bar(g: () -> Unit) {} +fun baz(): () -> K = TODO() + +fun test() { + foo { bar(baz()) } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.txt b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.txt new file mode 100644 index 00000000000..bed9c2f5107 --- /dev/null +++ b/compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.txt @@ -0,0 +1,6 @@ +package + +public fun bar(/*0*/ g: () -> kotlin.Unit): kotlin.Unit +public fun baz(): () -> K +public fun foo(/*0*/ f: () -> T): kotlin.Unit +public fun test(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index fb559b1573a..9f26dc4b9c5 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -24756,6 +24756,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/unitConversion/chainedUnitSuspendConversion.kt"); } + @TestMetadata("noUnitConversionForGenericTypeFromArrow.kt") + public void testNoUnitConversionForGenericTypeFromArrow() throws Exception { + runTest("compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.kt"); + } + + @TestMetadata("noUnitConversionOnReturningGenericFunctionalType.kt") + public void testNoUnitConversionOnReturningGenericFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.kt"); + } + @TestMetadata("unitConversionCompatibility.kt") public void testUnitConversionCompatibility() throws Exception { runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 883344af4ef..462af9f6f85 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -24676,6 +24676,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/unitConversion/chainedUnitSuspendConversion.kt"); } + @TestMetadata("noUnitConversionForGenericTypeFromArrow.kt") + public void testNoUnitConversionForGenericTypeFromArrow() throws Exception { + runTest("compiler/testData/diagnostics/tests/unitConversion/noUnitConversionForGenericTypeFromArrow.kt"); + } + + @TestMetadata("noUnitConversionOnReturningGenericFunctionalType.kt") + public void testNoUnitConversionOnReturningGenericFunctionalType() throws Exception { + runTest("compiler/testData/diagnostics/tests/unitConversion/noUnitConversionOnReturningGenericFunctionalType.kt"); + } + @TestMetadata("unitConversionCompatibility.kt") public void testUnitConversionCompatibility() throws Exception { runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt");