diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index 8f6eaa931c0..eafb1b1d329 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -2859,6 +2859,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt"); } + @Test + @TestMetadata("lambdaWithoutExpectedType.kt") + public void testLambdaWithoutExpectedType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.kt"); + } + @Test @TestMetadata("lambdasReturns.kt") public void testLambdasReturns() throws Exception { diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 119ecafeff0..9895006a3cc 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -2511,6 +2511,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt"); } + @TestMetadata("lambdaWithoutExpectedType.kt") + public void testLambdaWithoutExpectedType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.kt"); + } + @TestMetadata("lambdasReturns.kt") public void testLambdasReturns() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.fir.txt b/compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.fir.txt new file mode 100644 index 00000000000..43fcff178bb --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.fir.txt @@ -0,0 +1,60 @@ +FILE: lambdaWithoutExpectedType.kt + public abstract interface XdEntity : R|kotlin/Any| { + } + public abstract interface XdEntityType : R|kotlin/Any| { + } + public abstract interface XdNaturalEntityType : R|XdEntityType| { + } + public final class XdProject : R|XdEntity| { + public constructor(name: R|kotlin/String|): R|XdProject| { + super() + } + + public final var name: R|kotlin/String| = R|/name| + public get(): R|kotlin/String| + public set(value: R|kotlin/String|): R|kotlin/Unit| + + public final companion object Companion : R|XdNaturalEntityType| { + private constructor(): R|XdProject.Companion| { + super() + } + + } + + } + public abstract interface XdSearchingNode : R|kotlin/Any| { + } + public abstract interface XdQuery : R|kotlin/Any| { + } + public final fun R|XdQuery|.firstOrNull(): R|T?| { + ^firstOrNull Null(null) + } + public final object FilteringContext : R|kotlin/Any| { + private constructor(): R|FilteringContext| { + super() + } + + public final infix fun |> R|T?|.eq(value: R|T?|): R|XdSearchingNode| { + ^eq Null(null)!! + } + + } + public final fun R|XdEntityType|.filter(clause: R|FilteringContext.(T) -> XdSearchingNode|): R|XdQuery| { + ^filter Null(null)!! + } + public abstract interface XdIssue : R|kotlin/Any| { + } + public abstract interface XdIssueFolder : R|kotlin/Any| { + } + public final fun test(): R|kotlin/Unit| { + lval array: R|kotlin/Array| = R|kotlin/arrayOf|(vararg(String(Project), arrayOf@fun (): R|XdProject?| { + ^ Q|XdProject|.R|/filter|( = filter@fun R|FilteringContext|.(it: R|XdProject|): R|XdSearchingNode| { + ^ (this@R|special/anonymous|, R|/it|.R|/XdProject.name|).R|/FilteringContext.eq|(String(foo)) + } + ).R|/firstOrNull|() + } + , arrayOf@fun (: R|XdIssue|, : R|XdIssueFolder|): R|kotlin/Unit| { + ^@arrayOf Unit + } + )) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.kt b/compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.kt new file mode 100644 index 00000000000..8b341e854fe --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.kt @@ -0,0 +1,34 @@ +// WITH_STDLIB + +interface XdEntity + +interface XdEntityType +interface XdNaturalEntityType : XdEntityType + +class XdProject(var name: String) : XdEntity { + companion object : XdNaturalEntityType {} +} + +interface XdSearchingNode +interface XdQuery + +fun XdQuery.firstOrNull(): T? = null + +object FilteringContext { + infix fun > T?.eq(value: T?): XdSearchingNode = null!! +} + +fun XdEntityType.filter(clause: FilteringContext.(T) -> XdSearchingNode): XdQuery { + return null!! +} + +interface XdIssue +interface XdIssueFolder + +fun test() { + val array = arrayOf( + "Project", + { XdProject.filter { it.name eq "foo" }.firstOrNull() }, + { _: XdIssue, _: XdIssueFolder -> } + ) +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 1e3f28e775c..7bd7d21ea62 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -2859,6 +2859,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt"); } + @Test + @TestMetadata("lambdaWithoutExpectedType.kt") + public void testLambdaWithoutExpectedType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.kt"); + } + @Test @TestMetadata("lambdasReturns.kt") public void testLambdasReturns() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 009c90821cd..c589ca72009 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -2859,6 +2859,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt"); } + @Test + @TestMetadata("lambdaWithoutExpectedType.kt") + public void testLambdaWithoutExpectedType() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaWithoutExpectedType.kt"); + } + @Test @TestMetadata("lambdasReturns.kt") public void testLambdasReturns() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt index 93a819fb7b1..1c6b3f050c5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt @@ -15,9 +15,12 @@ import org.jetbrains.kotlin.fir.resolve.calls.CheckerSink import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext import org.jetbrains.kotlin.fir.resolve.createFunctionalType import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition +import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind +import org.jetbrains.kotlin.types.model.typeConstructor import org.jetbrains.kotlin.utils.addToStdlib.safeAs fun Candidate.preprocessLambdaArgument( @@ -31,7 +34,17 @@ fun Candidate.preprocessLambdaArgument( returnTypeVariable: ConeTypeVariableForLambdaReturnType? = null ): PostponedResolvedAtom { if (expectedType != null && expectedTypeRef != null && !duringCompletion && csBuilder.isTypeVariable(expectedType)) { - return LambdaWithTypeVariableAsExpectedTypeAtom(argument, expectedType, expectedTypeRef, this) + val expectedTypeVariableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[expectedType.typeConstructor(context.typeContext)] + + if (expectedTypeVariableWithConstraints != null) { + val explicitTypeArgument = expectedTypeVariableWithConstraints.constraints.find { + it.kind == ConstraintKind.EQUALITY && it.position.from is ConeExplicitTypeParameterConstraintPosition + }?.type as ConeKotlinType? + + if (explicitTypeArgument == null || explicitTypeArgument.typeArguments.isNotEmpty()) { + return LambdaWithTypeVariableAsExpectedTypeAtom(argument, expectedType, expectedTypeRef, this) + } + } } val anonymousFunction = argument.anonymousFunction