From f8d72f5dd92ed43a1937a8f136dcef9ee0ced4f3 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Tue, 31 Mar 2020 13:06:44 +0300 Subject: [PATCH] =?UTF-8?q?NI:=20improve=20lambdas=20completion=20?= =?UTF-8?q?=E2=80=93=20look=20at=20all=20postponed=20arguments=20during=20?= =?UTF-8?q?resolution=20lambdas=20by=20additional=20conditions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ^KT-36819 Fixed ^KT-36069 Fixed --- .../KotlinConstraintSystemCompleter.kt | 100 ++++++++---------- .../lambdaWithVariableAndNothing.kt | 2 +- .../tests/inference/kt36819.fir.kt | 18 ---- .../diagnostics/tests/inference/kt36819.kt | 17 ++- .../diagnostics/tests/inference/kt36819.txt | 2 + 5 files changed, 61 insertions(+), 78 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/inference/kt36819.fir.kt diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt index c944224e967..799aab5cda3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt @@ -153,75 +153,67 @@ class KotlinConstraintSystemCompleter( ): Boolean { val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) - return resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType( - variableForFixation, - postponedArguments, - diagnosticsHolder, - analyze - ) || resolveLambdaWhichIsReturnArgument(postponedArguments, diagnosticsHolder, analyze, fixationFinder) - } - - /* - * returns true -> analyzed - */ - private fun Context.resolveLambdaWhichIsReturnArgument( - postponedArguments: List, - diagnosticsHolder: KotlinDiagnosticsHolder, - analyze: (PostponedResolvedAtom) -> Unit, - fixationFinder: VariableFixationFinder - ): Boolean { - val isReturnArgumentOfAnotherLambda = postponedArguments.any { - it is LambdaWithTypeVariableAsExpectedTypeAtom && it.isReturnArgumentOfAnotherLambda - } - val postponedAtom = postponedArguments.firstOrNull() ?: return false - val atomExpectedType = postponedAtom.expectedType - - val shouldAnalyzeByPresenceLambdaAsReturnArgument = - isReturnArgumentOfAnotherLambda && atomExpectedType != null && - with(fixationFinder) { variableHasTrivialOrNonProperConstraints(atomExpectedType.constructor) } - - if (!shouldAnalyzeByPresenceLambdaAsReturnArgument) + if (postponedArguments.isEmpty()) return false - val expectedTypeVariable = - atomExpectedType?.constructor?.takeIf { it in allTypeVariables } ?: return false + val groupedPostponedArguments = postponedArguments.filterIsInstance() + .ifEmpty { postponedArguments.filter { it !is LambdaWithTypeVariableAsExpectedTypeAtom } } - analyze(preparePostponedAtom(expectedTypeVariable, postponedAtom, expectedTypeVariable.builtIns, diagnosticsHolder) ?: return false) + if (groupedPostponedArguments.isEmpty()) + return false - return true + fun shouldAnalyzeLambdaWithTypeVariableAsExpectedType(argument: PostponedResolvedAtom): Boolean { + val hasProperAtom = when (argument) { + is LambdaWithTypeVariableAsExpectedTypeAtom, is PostponedCallableReferenceAtom -> + argument.expectedType?.constructor == variableForFixation.variable + else -> false + } + + return hasProperAtom || !variableForFixation.hasProperConstraint || variableForFixation.hasOnlyTrivialProperConstraint + } + + fun shouldAnalyzeLambdaWhichIsReturnArgument(argument: PostponedResolvedAtom): Boolean { + val isReturnArgumentOfAnotherLambda = + argument is LambdaWithTypeVariableAsExpectedTypeAtom && argument.isReturnArgumentOfAnotherLambda + val atomExpectedType = argument.expectedType + + return isReturnArgumentOfAnotherLambda && atomExpectedType != null && + with(fixationFinder) { variableHasTrivialOrNonProperConstraints(atomExpectedType.constructor) } + } + + return resolveLambdaByCondition( + variableForFixation, groupedPostponedArguments, diagnosticsHolder, analyze, ::shouldAnalyzeLambdaWithTypeVariableAsExpectedType + ) || resolveLambdaByCondition( + variableForFixation, groupedPostponedArguments, diagnosticsHolder, analyze, ::shouldAnalyzeLambdaWhichIsReturnArgument + ) } /* * returns true -> analyzed */ - private fun Context.resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType( + private fun Context.resolveLambdaByCondition( variableForFixation: VariableFixationFinder.VariableForFixation, postponedArguments: List, diagnosticsHolder: KotlinDiagnosticsHolder, - analyze: (PostponedResolvedAtom) -> Unit + analyze: (PostponedResolvedAtom) -> Unit, + shouldAnalyze: (PostponedResolvedAtom) -> Boolean ): Boolean { val variable = variableForFixation.variable as? TypeConstructor ?: return false - val hasProperAtom = postponedArguments.any { - when (it) { - is LambdaWithTypeVariableAsExpectedTypeAtom, - is PostponedCallableReferenceAtom -> it.expectedType?.constructor == variable - else -> false - } + + return postponedArguments.all { argument -> + if (!shouldAnalyze(argument)) + return@all false + + val expectedTypeVariable = argument.expectedType?.constructor?.takeIf { it in allTypeVariables } ?: variable + + val preparedAtom = + preparePostponedAtom(expectedTypeVariable, argument, expectedTypeVariable.builtIns, diagnosticsHolder) + ?: return@all false + + analyze(preparedAtom) + + true } - - val postponedAtom = postponedArguments.firstOrNull() ?: return false - val expectedTypeAtom = postponedAtom.expectedType - val expectedTypeVariable = - expectedTypeAtom?.constructor?.takeIf { it in allTypeVariables } ?: variable - - val shouldAnalyze = hasProperAtom || !variableForFixation.hasProperConstraint || variableForFixation.hasOnlyTrivialProperConstraint - - if (!shouldAnalyze) - return false - - analyze(preparePostponedAtom(expectedTypeVariable, postponedAtom, variable.builtIns, diagnosticsHolder) ?: return false) - - return true } private fun Context.preparePostponedAtom( diff --git a/compiler/testData/diagnostics/tests/inference/completion/lambdaWithVariableAndNothing.kt b/compiler/testData/diagnostics/tests/inference/completion/lambdaWithVariableAndNothing.kt index 71f897e9e54..7fb87cda83c 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/lambdaWithVariableAndNothing.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/lambdaWithVariableAndNothing.kt @@ -46,7 +46,7 @@ fun testNoSmartCast3(s: String?) { fun testNoSmartCast4(s: String?) { id( if (s != null) ( {""} ) - else noSmartCast4(null) { "" } + else noSmartCast4(null) { "" } ) s.length } diff --git a/compiler/testData/diagnostics/tests/inference/kt36819.fir.kt b/compiler/testData/diagnostics/tests/inference/kt36819.fir.kt deleted file mode 100644 index 3967aae18fb..00000000000 --- a/compiler/testData/diagnostics/tests/inference/kt36819.fir.kt +++ /dev/null @@ -1,18 +0,0 @@ -// !LANGUAGE: +NewInference -// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -// ISSUE: KT-36819 - -fun select(vararg x: K) = x[0] -interface A -class B: A -class C: A -fun id1(x: T): T = x -fun id2(x: R): R = x - -class Out(x: R) - -fun main() { - val x1 = select(id1 { B() }, id2 { C() }) - val x2 = select({ B() }, { C() }) // OK, CST = () -> A - val x3 = select(id1(Out(B())), id2(Out(C()))) // OK, CST = Out -} diff --git a/compiler/testData/diagnostics/tests/inference/kt36819.kt b/compiler/testData/diagnostics/tests/inference/kt36819.kt index 7157864aecb..9922c6caa1e 100644 --- a/compiler/testData/diagnostics/tests/inference/kt36819.kt +++ b/compiler/testData/diagnostics/tests/inference/kt36819.kt @@ -1,5 +1,6 @@ +// FIR_IDENTICAL // !LANGUAGE: +NewInference -// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_ANONYMOUS_PARAMETER // ISSUE: KT-36819 fun select(vararg x: K) = x[0] @@ -12,7 +13,13 @@ fun id2(x: R): R = x class Out(x: R) fun main() { - val x1 = select(id1 { B() }, id2 { C() }) - val x2 = select({ B() }, { C() }) // OK, CST = () -> A - val x3 = select(id1(Out(B())), id2(Out(C()))) // OK, CST = Out -} \ No newline at end of file + val x1 = select(id1 { B() }, id2 { C() }) + val x2 = select({ B() }, { C() }) + val x3 = select(id1(Out(B())), id2(Out(C()))) +} + +fun fold(initial: R, operation: (R) -> Unit) {} + +fun foo() { + fold({ x: Int -> x }) { acc -> } +} diff --git a/compiler/testData/diagnostics/tests/inference/kt36819.txt b/compiler/testData/diagnostics/tests/inference/kt36819.txt index b323db87317..6cf6233625e 100644 --- a/compiler/testData/diagnostics/tests/inference/kt36819.txt +++ b/compiler/testData/diagnostics/tests/inference/kt36819.txt @@ -1,5 +1,7 @@ package +public fun fold(/*0*/ initial: R, /*1*/ operation: (R) -> kotlin.Unit): kotlin.Unit +public fun foo(): kotlin.Unit public fun id1(/*0*/ x: T): T public fun id2(/*0*/ x: R): R public fun main(): kotlin.Unit