From caf02806d59afa32c38ef61a7f8683ad5a71aba0 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 26 Dec 2019 17:23:14 +0300 Subject: [PATCH] NI: Fix resolution ambiguity for references returned from lambda ^KT-32267 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 15 +++++ .../tower/KotlinResolutionCallbacksImpl.kt | 11 ++++ .../resolve/calls/tower/PSICallResolver.kt | 2 +- .../ControlStructureTypingVisitor.java | 2 +- .../expressions/ExpressionTypingServices.java | 56 +++++++++++++------ .../tests/callableReference/kt32267.fir.kt | 39 +++++++++++++ .../tests/callableReference/kt32267.kt | 39 +++++++++++++ .../callableReference/lambdaResult.fir.kt | 43 ++++++++++++++ .../tests/callableReference/lambdaResult.kt | 43 ++++++++++++++ .../coercionToUnitReference.fir.kt | 14 +++++ .../coercionToUnit/coercionToUnitReference.kt | 14 +++++ .../checkers/DiagnosticsTestGenerated.java | 15 +++++ .../DiagnosticsUsingJavacTestGenerated.java | 15 +++++ 13 files changed, 290 insertions(+), 18 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/callableReference/kt32267.fir.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/kt32267.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/lambdaResult.fir.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/lambdaResult.kt create mode 100644 compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.kt diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index a83e4b73972..49267b47292 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -1849,11 +1849,21 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/callableReference/kt32256.kt"); } + @TestMetadata("kt32267.kt") + public void testKt32267() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/kt32267.kt"); + } + @TestMetadata("kt7430_wrongClassOnLHS.kt") public void testKt7430_wrongClassOnLHS() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/kt7430_wrongClassOnLHS.kt"); } + @TestMetadata("lambdaResult.kt") + public void testLambdaResult() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/lambdaResult.kt"); + } + @TestMetadata("memberExtensionsImportedFromObjectsUnsupported.kt") public void testMemberExtensionsImportedFromObjectsUnsupported() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/memberExtensionsImportedFromObjectsUnsupported.kt"); @@ -10223,6 +10233,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitForLastLambdaInLambda.kt"); } + @TestMetadata("coercionToUnitReference.kt") + public void testCoercionToUnitReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.kt"); + } + @TestMetadata("coercionWithExpectedType.kt") public void testCoercionWithExpectedType() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionWithExpectedType.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt index a27c4cdc704..bf1725adc5a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtCallableReferenceExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtReturnExpression @@ -116,6 +117,16 @@ class KotlinResolutionCallbacksImpl( return it } + val deparenthesizedExpression = KtPsiUtil.deparenthesize(ktExpression) ?: ktExpression + if (deparenthesizedExpression is KtCallableReferenceExpression) { + return psiCallResolver.createCallableReferenceKotlinCallArgument( + newContext, deparenthesizedExpression, DataFlowInfo.EMPTY, + CallMaker.makeExternalValueArgument(deparenthesizedExpression), + argumentName = null, + outerCallContext + ) + } + return createSimplePSICallArgument( trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor, CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 801e3d1097e..b7dd8f595c6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -702,7 +702,7 @@ class PSICallResolver( return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: createParseErrorElement() } - private fun createCallableReferenceKotlinCallArgument( + fun createCallableReferenceKotlinCallArgument( context: BasicCallResolutionContext, ktExpression: KtCallableReferenceExpression, startDataFlowInfo: DataFlowInfo, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index 03ba45f3347..86dfae0c942 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -895,7 +895,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (returnedExpression != null) { if (newInferenceLambdaInfo != null) { LambdaContextInfo contextInfo; - if (returnedExpression instanceof KtLambdaExpression) { + if (returnedExpression instanceof KtLambdaExpression || returnedExpression instanceof KtCallableReferenceExpression) { contextInfo = new LambdaContextInfo( new KotlinTypeInfo(DONT_CARE, context.dataFlowInfo), null, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java index 059615f0268..59b2e7c575f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.types.expressions; -import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -317,10 +316,24 @@ public class ExpressionTypingServices { @NotNull CoercionStrategy coercionStrategyForLastExpression, @NotNull ExpressionTypingInternals blockLevelVisitor ) { + boolean isUnitExpectedType = context.expectedType != NO_EXPECTED_TYPE && + ( + context.expectedType == UNIT_EXPECTED_TYPE || + //the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)' + ( + coercionStrategyForLastExpression == COERCION_TO_UNIT && + KotlinBuiltIns.isUnit(context.expectedType) + ) + ); + + if (!isUnitExpectedType && statementExpression instanceof KtCallableReferenceExpression) { + KotlinTypeInfo typeInfo = createDontCareTypeInfoForNILambda(statementExpression, context); + if (typeInfo != null) return typeInfo; + } + if (context.expectedType != NO_EXPECTED_TYPE) { KotlinType expectedType; - if (context.expectedType == UNIT_EXPECTED_TYPE ||//the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)' - (coercionStrategyForLastExpression == COERCION_TO_UNIT && KotlinBuiltIns.isUnit(context.expectedType))) { + if (isUnitExpectedType) { expectedType = UNIT_EXPECTED_TYPE; } else { @@ -329,20 +342,12 @@ public class ExpressionTypingServices { return blockLevelVisitor.getTypeInfo(statementExpression, context.replaceExpectedType(expectedType), true); } - if (context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) && - statementExpression instanceof KtLambdaExpression) { - PsiElement parent = PsiUtilsKt.getNonStrictParentOfType(statementExpression, KtFunctionLiteral.class); - if (parent != null) { - KtFunctionLiteral functionLiteral = (KtFunctionLiteral) parent; - KotlinResolutionCallbacksImpl.LambdaInfo info = - context.trace.getBindingContext().get(BindingContext.NEW_INFERENCE_LAMBDA_INFO, functionLiteral); - if (info != null) { - info.getLastExpressionInfo().setLexicalScope(context.scope); - info.getLastExpressionInfo().setTrace(context.trace); - return new KotlinTypeInfo(DONT_CARE, context.dataFlowInfo); - } - } + + if (statementExpression instanceof KtLambdaExpression) { + KotlinTypeInfo typeInfo = createDontCareTypeInfoForNILambda(statementExpression, context); + if (typeInfo != null) return typeInfo; } + KotlinTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true); if (coercionStrategyForLastExpression == COERCION_TO_UNIT) { boolean mightBeUnit = false; @@ -369,6 +374,25 @@ public class ExpressionTypingServices { return result; } + @Nullable + private static KotlinTypeInfo createDontCareTypeInfoForNILambda( + @NotNull KtExpression statementExpression, + @NotNull ExpressionTypingContext context + ) { + if (!context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference)) return null; + KtFunctionLiteral functionLiteral = PsiUtilsKt.getNonStrictParentOfType(statementExpression, KtFunctionLiteral.class); + if (functionLiteral != null) { + KotlinResolutionCallbacksImpl.LambdaInfo info = + context.trace.getBindingContext().get(BindingContext.NEW_INFERENCE_LAMBDA_INFO, functionLiteral); + if (info != null) { + info.getLastExpressionInfo().setLexicalScope(context.scope); + info.getLastExpressionInfo().setTrace(context.trace); + return new KotlinTypeInfo(DONT_CARE, context.dataFlowInfo); + } + } + return null; + } + private static class EffectsFilteringTrace extends AbstractFilteringTrace { public EffectsFilteringTrace(BindingTrace parentTrace) { super(parentTrace, "Effects filtering trace"); diff --git a/compiler/testData/diagnostics/tests/callableReference/kt32267.fir.kt b/compiler/testData/diagnostics/tests/callableReference/kt32267.fir.kt new file mode 100644 index 00000000000..82a69b84a5d --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/kt32267.fir.kt @@ -0,0 +1,39 @@ +// SKIP_TXT +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !LANGUAGE: +NewInference + +fun main() { + Configuration().commands { + Command1 { someService::execute } // Overload resolution ambiguity. All these functions match. + Command2 { someService::execute } // Overload resolution ambiguity. All these functions match. + Command1 { { someService.execute(it) } } // fine + Command2 { { someService.execute(it) } } // fine + } +} +interface Command +interface CommandFactory +class Command1 : Command { + companion object : CommandFactory +} +class Command2 : Command { + companion object : CommandFactory +} +class Configuration { + val commands = Commands() + inline fun commands(configure: Commands.() -> Unit) { + commands.configure() + } + class Commands { + operator fun CommandFactory.invoke( + handler: Transaction.() -> ((command: TCommand) -> Unit) + ) { + } + } +} +interface Transaction { + val someService: SomeService +} +interface SomeService { + fun execute(command: Command1) + fun execute(command: Command2) +} diff --git a/compiler/testData/diagnostics/tests/callableReference/kt32267.kt b/compiler/testData/diagnostics/tests/callableReference/kt32267.kt new file mode 100644 index 00000000000..a885e6375cf --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/kt32267.kt @@ -0,0 +1,39 @@ +// SKIP_TXT +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !LANGUAGE: +NewInference + +fun main() { + Configuration().commands { + Command1 { someService::execute } // Overload resolution ambiguity. All these functions match. + Command2 { someService::execute } // Overload resolution ambiguity. All these functions match. + Command1 { { someService.execute(it) } } // fine + Command2 { { someService.execute(it) } } // fine + } +} +interface Command +interface CommandFactory +class Command1 : Command { + companion object : CommandFactory +} +class Command2 : Command { + companion object : CommandFactory +} +class Configuration { + val commands = Commands() + inline fun commands(configure: Commands.() -> Unit) { + commands.configure() + } + class Commands { + operator fun CommandFactory.invoke( + handler: Transaction.() -> ((command: TCommand) -> Unit) + ) { + } + } +} +interface Transaction { + val someService: SomeService +} +interface SomeService { + fun execute(command: Command1) + fun execute(command: Command2) +} diff --git a/compiler/testData/diagnostics/tests/callableReference/lambdaResult.fir.kt b/compiler/testData/diagnostics/tests/callableReference/lambdaResult.fir.kt new file mode 100644 index 00000000000..92f1ec9ba32 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/lambdaResult.fir.kt @@ -0,0 +1,43 @@ +// SKIP_TXT +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !LANGUAGE: +NewInference + +interface Inv + +fun Inv.foo( + handler: () -> ((command: E) -> Unit) +) {} + +fun bar(x: Int) {} +fun bar(x: String) {} + +fun bar1(arg: Int) {} +fun foo1(f: () -> (Int) -> Unit) = "" + +fun main(x: Inv) { + x.foo { + if (x.hashCode() == 0) return@foo ::bar + + ::bar + } + + x.foo { + if (x.hashCode() == 0) return@foo ::bar + + ::bar + } + + foo1 { + ::bar1 + } + + foo1 { + return@foo1 ::bar1 + } + + foo1 { + if (x.hashCode() == 0) return@foo1 ::bar + + ::bar + } +} diff --git a/compiler/testData/diagnostics/tests/callableReference/lambdaResult.kt b/compiler/testData/diagnostics/tests/callableReference/lambdaResult.kt new file mode 100644 index 00000000000..1391ebe2b86 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/lambdaResult.kt @@ -0,0 +1,43 @@ +// SKIP_TXT +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !LANGUAGE: +NewInference + +interface Inv + +fun Inv.foo( + handler: () -> ((command: E) -> Unit) +) {} + +fun bar(x: Int) {} +fun bar(x: String) {} + +fun bar1(arg: Int) {} +fun foo1(f: () -> (Int) -> Unit) = "" + +fun main(x: Inv) { + x.foo { + if (x.hashCode() == 0) return@foo ::bar + + ::bar + } + + x.foo { + if (x.hashCode() == 0) return@foo ::bar + + ::bar + } + + foo1 { + ::bar1 + } + + foo1 { + return@foo1 ::bar1 + } + + foo1 { + if (x.hashCode() == 0) return@foo1 ::bar + + ::bar + } +} diff --git a/compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.fir.kt b/compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.fir.kt new file mode 100644 index 00000000000..1c0978422ce --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.fir.kt @@ -0,0 +1,14 @@ +// SKIP_TXT +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !LANGUAGE: +NewInference + +fun foo(f: () -> Unit) {} +fun bar(): Int = 42 +fun test() { + foo { + ::bar // should be fine + } + foo { + { "something" } // should be fine + } +} diff --git a/compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.kt b/compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.kt new file mode 100644 index 00000000000..86d1d2ecf3f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.kt @@ -0,0 +1,14 @@ +// SKIP_TXT +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !LANGUAGE: +NewInference + +fun foo(f: () -> Unit) {} +fun bar(): Int = 42 +fun test() { + foo { + ::bar // should be fine + } + foo { + { "something" } // should be fine + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index e7a4a176d57..d2b9cc9d473 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -1856,11 +1856,21 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/callableReference/kt32256.kt"); } + @TestMetadata("kt32267.kt") + public void testKt32267() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/kt32267.kt"); + } + @TestMetadata("kt7430_wrongClassOnLHS.kt") public void testKt7430_wrongClassOnLHS() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/kt7430_wrongClassOnLHS.kt"); } + @TestMetadata("lambdaResult.kt") + public void testLambdaResult() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/lambdaResult.kt"); + } + @TestMetadata("memberExtensionsImportedFromObjectsUnsupported.kt") public void testMemberExtensionsImportedFromObjectsUnsupported() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/memberExtensionsImportedFromObjectsUnsupported.kt"); @@ -10230,6 +10240,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitForLastLambdaInLambda.kt"); } + @TestMetadata("coercionToUnitReference.kt") + public void testCoercionToUnitReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.kt"); + } + @TestMetadata("coercionWithExpectedType.kt") public void testCoercionWithExpectedType() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionWithExpectedType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 846d7d5e5ed..25f94c0e443 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -1851,11 +1851,21 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/callableReference/kt32256.kt"); } + @TestMetadata("kt32267.kt") + public void testKt32267() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/kt32267.kt"); + } + @TestMetadata("kt7430_wrongClassOnLHS.kt") public void testKt7430_wrongClassOnLHS() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/kt7430_wrongClassOnLHS.kt"); } + @TestMetadata("lambdaResult.kt") + public void testLambdaResult() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/lambdaResult.kt"); + } + @TestMetadata("memberExtensionsImportedFromObjectsUnsupported.kt") public void testMemberExtensionsImportedFromObjectsUnsupported() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/memberExtensionsImportedFromObjectsUnsupported.kt"); @@ -10225,6 +10235,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitForLastLambdaInLambda.kt"); } + @TestMetadata("coercionToUnitReference.kt") + public void testCoercionToUnitReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionToUnitReference.kt"); + } + @TestMetadata("coercionWithExpectedType.kt") public void testCoercionWithExpectedType() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionWithExpectedType.kt");