From 4083111dab532807f755e1ac4cffcb501364d7f1 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 20 Jul 2020 10:36:37 +0300 Subject: [PATCH] Fix SAM conversion when lambda is the last expression of another lambda #KT-39691 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 5 ++++ .../calls/components/SamTypeConversions.kt | 17 ++++++++++++ .../conversionOnLambdaAsLastExpression.kt | 20 ++++++++++++++ .../conversionOnLambdaAsLastExpression.txt | 27 +++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 5 ++++ .../DiagnosticsUsingJavacTestGenerated.java | 5 ++++ 6 files changed, 79 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.kt create mode 100644 compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.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 8f8ebd99252..cd9326ab3ee 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 @@ -19776,6 +19776,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/samConversions/checkSamConversionsAreDisabledByDefault.kt"); } + @TestMetadata("conversionOnLambdaAsLastExpression.kt") + public void testConversionOnLambdaAsLastExpression() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.kt"); + } + @TestMetadata("DisabledForKTSimple.kt") public void testDisabledForKTSimple() throws Exception { runTest("compiler/testData/diagnostics/tests/samConversions/DisabledForKTSimple.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt index 2f8a441c1c8..14edf5d9fe1 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt @@ -45,12 +45,29 @@ object SamTypeConversions : ParameterTypeConversion { override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean { return when (argument) { + is SubKotlinCallArgument -> { + val stableType = argument.receiver.stableType + hasNonAnalyzedLambdaAsReturnType(argument.callResult.subResolvedAtoms, stableType) + } is SimpleKotlinCallArgument -> argument.receiver.stableType.isFunctionType is LambdaKotlinCallArgument, is CallableReferenceKotlinCallArgument -> true else -> false } } + private fun hasNonAnalyzedLambdaAsReturnType(subResolvedAtoms: List?, type: UnwrappedType): Boolean { + subResolvedAtoms?.forEach { + if (it is LambdaWithTypeVariableAsExpectedTypeAtom) { + if (it.expectedType.constructor == type.constructor) return true + } + + val hasNonAnalyzedLambda = hasNonAnalyzedLambdaAsReturnType(it.subResolvedAtoms, type) + if (hasNonAnalyzedLambda) return true + } + + return false + } + override fun conversionIsNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean { return argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionTypeOrSubtype } diff --git a/compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.kt b/compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.kt new file mode 100644 index 00000000000..0c48f1c94fd --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.kt @@ -0,0 +1,20 @@ +// FIR_IDENTICAL + +// FILE: C.java + +public interface C { void on(String s); } + +// FILE: A.java + +public class A { void add(C c) {} } + +// FILE: test.kt + +class B : A() { + fun test(x: Any?) { + add(foo { { _ : String -> Unit } }) + add(x?.let { { _ : String -> Unit } }) + } +} + +fun foo(f: () -> T): T = f() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.txt b/compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.txt new file mode 100644 index 00000000000..72042fa454f --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.txt @@ -0,0 +1,27 @@ +package + +public fun foo(/*0*/ f: () -> T): T + +public open class A { + public constructor A() + public/*package*/ open fun add(/*0*/ c: C!): kotlin.Unit + 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 B : A { + public constructor B() + public/*package*/ open override /*1*/ /*fake_override*/ fun add(/*0*/ c: C!): kotlin.Unit + 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 test(/*0*/ x: kotlin.Any?): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface C { + 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 abstract fun on(/*0*/ s: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index c4dc540662d..67c23e42dbf 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -19788,6 +19788,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/samConversions/checkSamConversionsAreDisabledByDefault.kt"); } + @TestMetadata("conversionOnLambdaAsLastExpression.kt") + public void testConversionOnLambdaAsLastExpression() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.kt"); + } + @TestMetadata("DisabledForKTSimple.kt") public void testDisabledForKTSimple() throws Exception { runTest("compiler/testData/diagnostics/tests/samConversions/DisabledForKTSimple.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 6929ea7c3b8..8b6153ac6dc 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -19778,6 +19778,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/samConversions/checkSamConversionsAreDisabledByDefault.kt"); } + @TestMetadata("conversionOnLambdaAsLastExpression.kt") + public void testConversionOnLambdaAsLastExpression() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/conversionOnLambdaAsLastExpression.kt"); + } + @TestMetadata("DisabledForKTSimple.kt") public void testDisabledForKTSimple() throws Exception { runTest("compiler/testData/diagnostics/tests/samConversions/DisabledForKTSimple.kt");