NI: improve lambdas completion – look at all postponed arguments during resolution lambdas by additional conditions
^KT-36819 Fixed ^KT-36069 Fixed
This commit is contained in:
+46
-54
@@ -153,75 +153,67 @@ class KotlinConstraintSystemCompleter(
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
||||||
|
|
||||||
return resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType(
|
if (postponedArguments.isEmpty())
|
||||||
variableForFixation,
|
|
||||||
postponedArguments,
|
|
||||||
diagnosticsHolder,
|
|
||||||
analyze
|
|
||||||
) || resolveLambdaWhichIsReturnArgument(postponedArguments, diagnosticsHolder, analyze, fixationFinder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* returns true -> analyzed
|
|
||||||
*/
|
|
||||||
private fun Context.resolveLambdaWhichIsReturnArgument(
|
|
||||||
postponedArguments: List<PostponedResolvedAtom>,
|
|
||||||
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)
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
val expectedTypeVariable =
|
val groupedPostponedArguments = postponedArguments.filterIsInstance<LambdaWithTypeVariableAsExpectedTypeAtom>()
|
||||||
atomExpectedType?.constructor?.takeIf { it in allTypeVariables } ?: return false
|
.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
|
* returns true -> analyzed
|
||||||
*/
|
*/
|
||||||
private fun Context.resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType(
|
private fun Context.resolveLambdaByCondition(
|
||||||
variableForFixation: VariableFixationFinder.VariableForFixation,
|
variableForFixation: VariableFixationFinder.VariableForFixation,
|
||||||
postponedArguments: List<PostponedResolvedAtom>,
|
postponedArguments: List<PostponedResolvedAtom>,
|
||||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||||
analyze: (PostponedResolvedAtom) -> Unit
|
analyze: (PostponedResolvedAtom) -> Unit,
|
||||||
|
shouldAnalyze: (PostponedResolvedAtom) -> Boolean
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val variable = variableForFixation.variable as? TypeConstructor ?: return false
|
val variable = variableForFixation.variable as? TypeConstructor ?: return false
|
||||||
val hasProperAtom = postponedArguments.any {
|
|
||||||
when (it) {
|
return postponedArguments.all { argument ->
|
||||||
is LambdaWithTypeVariableAsExpectedTypeAtom,
|
if (!shouldAnalyze(argument))
|
||||||
is PostponedCallableReferenceAtom -> it.expectedType?.constructor == variable
|
return@all false
|
||||||
else -> 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(
|
private fun Context.preparePostponedAtom(
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ fun testNoSmartCast3(s: String?) {
|
|||||||
fun testNoSmartCast4(s: String?) {
|
fun testNoSmartCast4(s: String?) {
|
||||||
id(
|
id(
|
||||||
if (s != null) ( {""} )
|
if (s != null) ( {""} )
|
||||||
else <!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>noSmartCast4<!>(null) <!TYPE_MISMATCH!>{ <!TYPE_MISMATCH!>""<!> }<!>
|
else noSmartCast4(null) { "" }
|
||||||
)
|
)
|
||||||
s<!UNSAFE_CALL!>.<!>length
|
s<!UNSAFE_CALL!>.<!>length
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// !LANGUAGE: +NewInference
|
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
|
||||||
// ISSUE: KT-36819
|
|
||||||
|
|
||||||
fun <K> select(vararg x: K) = x[0]
|
|
||||||
interface A
|
|
||||||
class B: A
|
|
||||||
class C: A
|
|
||||||
fun <T> id1(x: T): T = x
|
|
||||||
fun <R> id2(x: R): R = x
|
|
||||||
|
|
||||||
class Out<out R>(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<A>
|
|
||||||
}
|
|
||||||
+12
-5
@@ -1,5 +1,6 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_ANONYMOUS_PARAMETER
|
||||||
// ISSUE: KT-36819
|
// ISSUE: KT-36819
|
||||||
|
|
||||||
fun <K> select(vararg x: K) = x[0]
|
fun <K> select(vararg x: K) = x[0]
|
||||||
@@ -12,7 +13,13 @@ fun <R> id2(x: R): R = x
|
|||||||
class Out<out R>(x: R)
|
class Out<out R>(x: R)
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val x1 = select(id1 { B() }, id2 { <!TYPE_MISMATCH, TYPE_MISMATCH!>C()<!> })
|
val x1 = select(id1 { B() }, id2 { C() })
|
||||||
val x2 = select({ B() }, { C() }) // OK, CST = () -> A
|
val x2 = select({ B() }, { C() })
|
||||||
val x3 = select(id1(Out(B())), id2(Out(C()))) // OK, CST = Out<A>
|
val x3 = select(id1(Out(B())), id2(Out(C())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <R> fold(initial: R, operation: (R) -> Unit) {}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
fold({ x: Int -> x }) { acc -> }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
|
public fun </*0*/ R> fold(/*0*/ initial: R, /*1*/ operation: (R) -> kotlin.Unit): kotlin.Unit
|
||||||
|
public fun foo(): kotlin.Unit
|
||||||
public fun </*0*/ T> id1(/*0*/ x: T): T
|
public fun </*0*/ T> id1(/*0*/ x: T): T
|
||||||
public fun </*0*/ R> id2(/*0*/ x: R): R
|
public fun </*0*/ R> id2(/*0*/ x: R): R
|
||||||
public fun main(): kotlin.Unit
|
public fun main(): kotlin.Unit
|
||||||
|
|||||||
Reference in New Issue
Block a user