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 42b324e8bf8..48762dee97a 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -10106,6 +10106,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/kt35702.kt"); } + @TestMetadata("kt36044.kt") + public void testKt36044() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt36044.kt"); + } + @TestMetadata("kt36819.kt") public void testKt36819() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/kt36819.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index 17d8ebde48f..2901f4b0454 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -150,7 +150,10 @@ class PostponedArgumentsAnalyzer( val subResolvedKtPrimitives = allReturnArguments.map { resolveKtPrimitive( c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, ReceiverInfo.notReceiver, convertedType = null - ) + ).apply { + if (this is LambdaWithTypeVariableAsExpectedTypeAtom) + isReturnArgumentOfAnotherLambda = true + } } if (!returnArgumentsInfo.returnArgumentsExist) { 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 46601ad60bb..d252c869517 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 @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.resolve.calls.inference.components +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder +import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.types.* @@ -103,12 +105,12 @@ class KotlinConstraintSystemCompleter( if ( completionMode == ConstraintSystemCompletionMode.FULL && - resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType( - c, + c.resolveLambdaByAdditionalConditions( variableForFixation, topLevelAtoms, diagnosticsHolder, - analyze + analyze, + variableFixationFinder ) ) { continue @@ -141,15 +143,67 @@ class KotlinConstraintSystemCompleter( /* * returns true -> analyzed */ - private fun resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType( - c: Context, + private fun Context.resolveLambdaByAdditionalConditions( variableForFixation: VariableFixationFinder.VariableForFixation, topLevelAtoms: List, diagnosticsHolder: KotlinDiagnosticsHolder, + analyze: (PostponedResolvedAtom) -> Unit, + fixationFinder: VariableFixationFinder + ): 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 { + if (this !is NewConstraintSystem) return false + + 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 + + val expectedTypeVariable = + atomExpectedType?.constructor?.takeIf { it in this.getBuilder().currentStorage().allTypeVariables } ?: return false + + analyze(preparePostponedAtom(expectedTypeVariable, postponedAtom, expectedTypeVariable.builtIns, diagnosticsHolder) ?: return false) + + return true + } + + /* + * returns true -> analyzed + */ + private fun Context.resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType( + variableForFixation: VariableFixationFinder.VariableForFixation, + postponedArguments: List, + diagnosticsHolder: KotlinDiagnosticsHolder, analyze: (PostponedResolvedAtom) -> Unit ): Boolean { - val variable = variableForFixation.variable as TypeConstructor - val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) + if (this !is NewConstraintSystem) return false + + val variable = variableForFixation.variable as? TypeConstructor ?: return false val hasProperAtom = postponedArguments.any { when (it) { is LambdaWithTypeVariableAsExpectedTypeAtom, @@ -158,21 +212,33 @@ class KotlinConstraintSystemCompleter( } } - if ( - !hasProperAtom && - variableForFixation.hasProperConstraint && - !variableForFixation.hasOnlyTrivialProperConstraint - ) return false - val postponedAtom = postponedArguments.firstOrNull() ?: return false + val expectedTypeAtom = postponedAtom.expectedType + val expectedTypeVariable = + expectedTypeAtom?.constructor?.takeIf { it in this.getBuilder().currentStorage().allTypeVariables } ?: variable - val builtIns = (variable as TypeVariableTypeConstructor).builtIns - val csBuilder = (c as NewConstraintSystemImpl).getBuilder() + val shouldAnalyzeByEqualityExpectedTypeToVariable = + hasProperAtom || !variableForFixation.hasProperConstraint || variableForFixation.hasOnlyTrivialProperConstraint - val expectedTypeVariable = postponedAtom.expectedType?.constructor?.takeIf { it in c.allTypeVariables } ?: variable - val atomToAnalyze = when (postponedAtom) { + if (!shouldAnalyzeByEqualityExpectedTypeToVariable) + return false + + analyze(preparePostponedAtom(expectedTypeVariable, postponedAtom, variable.builtIns, diagnosticsHolder) ?: return false) + + return true + } + + private fun Context.preparePostponedAtom( + expectedTypeVariable: TypeConstructor, + postponedAtom: PostponedResolvedAtom, + builtIns: KotlinBuiltIns, + diagnosticsHolder: KotlinDiagnosticsHolder + ): PostponedResolvedAtom? { + val csBuilder = (this as? NewConstraintSystem)?.getBuilder() ?: return null + + return when (postponedAtom) { is PostponedCallableReferenceAtom -> postponedAtom.preparePostponedAtomWithTypeVariableAsExpectedType( - c, csBuilder, expectedTypeVariable, + this, csBuilder, expectedTypeVariable, parameterTypes = null, isSuitable = KotlinType::isBuiltinFunctionalTypeOrSubtype, typeVariableCreator = { TypeVariableForCallableReferenceReturnType(builtIns, "_Q") }, @@ -183,7 +249,7 @@ class KotlinConstraintSystemCompleter( } ) is LambdaWithTypeVariableAsExpectedTypeAtom -> postponedAtom.preparePostponedAtomWithTypeVariableAsExpectedType( - c, csBuilder, expectedTypeVariable, + this, csBuilder, expectedTypeVariable, parameterTypes = postponedAtom.atom.parametersTypes, isSuitable = KotlinType::isBuiltinFunctionalType, typeVariableCreator = { TypeVariableForLambdaReturnType(postponedAtom.atom, builtIns, "_R") }, @@ -191,10 +257,8 @@ class KotlinConstraintSystemCompleter( postponedAtom.transformToResolvedLambda(csBuilder, diagnosticsHolder, expectedType, returnVariable) } ) - else -> return false + else -> null } - analyze(atomToAnalyze) - return true } private inline fun T.preparePostponedAtomWithTypeVariableAsExpectedType( diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt index 1a30b1cb4c2..9949c4162a8 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt @@ -86,6 +86,13 @@ class VariableFixationFinder( } } + fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructorMarker): Boolean { + return notFixedTypeVariables[variable]?.constraints?.all { constraint -> + val isProperConstraint = isProperArgumentConstraint(constraint) + isProperConstraint && trivialConstraintTypeInferenceOracle.isNotInterestingConstraint(constraint) || !isProperConstraint + } ?: false + } + private fun Context.findTypeVariableForFixation( allTypeVariables: List, postponedArguments: List, @@ -120,13 +127,6 @@ class VariableFixationFinder( return false } - private fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructorMarker): Boolean { - return notFixedTypeVariables[variable]?.constraints?.all { constraint -> - val isProperConstraint = isProperArgumentConstraint(constraint) - isProperConstraint && trivialConstraintTypeInferenceOracle.isNotInterestingConstraint(constraint) || !isProperConstraint - } ?: false - } - private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructorMarker): Boolean = notFixedTypeVariables[variable]?.constraints?.any { isProperArgumentConstraint(it) } ?: false diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index 1ed07c89d9b..b0af7f71892 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -109,6 +109,7 @@ class LambdaWithTypeVariableAsExpectedTypeAtom( ) : PostponedResolvedAtom() { override val inputTypes: Collection get() = listOf(expectedType) override val outputType: UnwrappedType? get() = null + var isReturnArgumentOfAnotherLambda: Boolean = false fun setAnalyzed(resolvedLambdaAtom: ResolvedLambdaAtom) { setAnalyzedResults(listOf(resolvedLambdaAtom)) diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.fail b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.fail new file mode 100644 index 00000000000..b00ddcff6f5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.fail @@ -0,0 +1,8 @@ +Failures detected in FirBodyResolveTransformerAdapter, file: /nestedCallWithOverload.fir.kt +Cause: java.lang.RuntimeException: While resolving call R?C|/baz|(R?C|/id|( = id@fun .(): { + it#.inv#() +} +), R|/id| kotlin/Unit|>( = id@fun (it: R|kotlin/Int|): R|kotlin/Unit| { + Unit +} +)) diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt index de5c7647851..83713f29fc1 100644 --- a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.fir.kt @@ -19,4 +19,6 @@ fun test() { baz<(Int) -> Unit>(id(::foo), id(id(::foo))) baz(id(::foo), id(id<(Int) -> Unit>(::foo))) baz(id(::foo), id<(Int) -> Unit>(id(::foo))) + + baz(id { it.inv() }, id<(Int) -> Unit> { }) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt index 4dcb4810326..477ab16ce32 100644 --- a/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt +++ b/compiler/testData/diagnostics/tests/callableReference/generic/nestedCallWithOverload.kt @@ -19,4 +19,6 @@ fun test() { baz<(Int) -> Unit>(id(::foo), id(id(::foo))) baz(id(::foo), id(id<(Int) -> Unit>(::foo))) baz(id(::foo), id<(Int) -> Unit>(id(::foo))) + + baz(id { it.inv() }, id<(Int) -> Unit> { }) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/kt36044.fir.fail b/compiler/testData/diagnostics/tests/inference/kt36044.fir.fail new file mode 100644 index 00000000000..2c348c48475 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt36044.fir.fail @@ -0,0 +1,8 @@ +Failures detected in FirBodyResolveTransformerAdapter, file: /kt36044.fir.kt +Cause: java.lang.RuntimeException: While resolving call R?C|/select|(Char(a), R?C|/map|( = map@fun (): { + ^ map@fun .(): { + String() + } + +} +)) diff --git a/compiler/testData/diagnostics/tests/inference/kt36044.fir.kt b/compiler/testData/diagnostics/tests/inference/kt36044.fir.kt new file mode 100644 index 00000000000..8a9c12c2254 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt36044.fir.kt @@ -0,0 +1,9 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// Issue: KT-36044 + +fun select(x: A, f: () -> A) = f() +fun map(f: () -> B) = f() + +fun main() { + select('a', map { { "" } }) +} diff --git a/compiler/testData/diagnostics/tests/inference/kt36044.kt b/compiler/testData/diagnostics/tests/inference/kt36044.kt new file mode 100644 index 00000000000..8a9c12c2254 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt36044.kt @@ -0,0 +1,9 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// Issue: KT-36044 + +fun select(x: A, f: () -> A) = f() +fun map(f: () -> B) = f() + +fun main() { + select('a', map { { "" } }) +} diff --git a/compiler/testData/diagnostics/tests/inference/kt36044.txt b/compiler/testData/diagnostics/tests/inference/kt36044.txt new file mode 100644 index 00000000000..89567967855 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt36044.txt @@ -0,0 +1,5 @@ +package + +public fun main(): kotlin.Unit +public fun map(/*0*/ f: () -> B): B +public fun select(/*0*/ x: A, /*1*/ f: () -> A): A diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 7d8e44128b6..ad672b9bf6e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10113,6 +10113,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/inference/kt35702.kt"); } + @TestMetadata("kt36044.kt") + public void testKt36044() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt36044.kt"); + } + @TestMetadata("kt36819.kt") public void testKt36819() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/kt36819.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 15a5a000159..43ea8baa030 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10108,6 +10108,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/kt35702.kt"); } + @TestMetadata("kt36044.kt") + public void testKt36044() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt36044.kt"); + } + @TestMetadata("kt36819.kt") public void testKt36819() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/kt36819.kt");