diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 0f4f21b9d32..610fe9b0805 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -15229,6 +15229,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/lambdaWithNullableUnitInElvis.kt"); } + @Test + @TestMetadata("nestedLambda.kt") + public void testNestedLambda() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/nestedLambda.kt"); + } + @Test @TestMetadata("noCoercion.kt") public void testNoCoercion() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index f7e5b24f24c..b48da1ac310 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -15235,6 +15235,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/lambdaWithNullableUnitInElvis.kt"); } + @Test + @TestMetadata("nestedLambda.kt") + public void testNestedLambda() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/nestedLambda.kt"); + } + @Test @TestMetadata("noCoercion.kt") public void testNoCoercion() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 769a49e37b6..3169f975469 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -15229,6 +15229,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/lambdaWithNullableUnitInElvis.kt"); } + @Test + @TestMetadata("nestedLambda.kt") + public void testNestedLambda() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/nestedLambda.kt"); + } + @Test @TestMetadata("noCoercion.kt") public void testNoCoercion() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt index b6b9932fc8e..36c7496e0bb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt @@ -15,11 +15,10 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition import org.jetbrains.kotlin.fir.resolve.shouldReturnUnit import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.ConeTypeVariable +import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef -import org.jetbrains.kotlin.fir.types.isMarkedNullable import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzerContext import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode @@ -152,7 +151,6 @@ class PostponedArgumentsAnalyzer( candidate, results, completionMode, - expectedTypeForReturnArguments, ::substitute ) return results @@ -164,7 +162,6 @@ class PostponedArgumentsAnalyzer( candidate: Candidate, results: ReturnArgumentsAnalysisResult, completionMode: ConstraintSystemCompletionMode, - expectedReturnType: ConeKotlinType? = null, substitute: (ConeKotlinType) -> ConeKotlinType = c.createSubstituteFunctorForLambdaAnalysis() ) { val (returnArguments, inferenceSession) = results @@ -174,7 +171,9 @@ class PostponedArgumentsAnalyzer( val lastExpression = lambda.atom.body?.statements?.lastOrNull() as? FirExpression var hasExpressionInReturnArguments = false - val lambdaReturnType = lambda.returnType.let(substitute) + val returnTypeRef = lambda.atom.returnTypeRef.let { + it as? FirResolvedTypeRef ?: it.resolvedTypeFromPrototype(substitute(lambda.returnType)) + } returnArguments.forEach { val haveSubsystem = c.addSubsystemFromExpression(it) // If the lambda returns Unit, the last expression is not returned and should not be constrained. @@ -186,7 +185,7 @@ class PostponedArgumentsAnalyzer( // } // Things get even weirder if T has an upper bound incompatible with Unit. if (it == lastExpression && !haveSubsystem && - (expectedReturnType?.isUnitOrFlexibleUnit == true || lambda.atom.shouldReturnUnit(returnArguments)) + (returnTypeRef.type.isUnitOrFlexibleUnit || lambda.atom.shouldReturnUnit(returnArguments)) ) return@forEach hasExpressionInReturnArguments = true @@ -194,8 +193,8 @@ class PostponedArgumentsAnalyzer( candidate.resolveArgumentExpression( builder, it, - lambdaReturnType, - lambda.atom.returnTypeRef, // TODO: proper ref + returnTypeRef.type, + returnTypeRef, checkerSink, context = resolutionContext, isReceiver = false, @@ -204,10 +203,10 @@ class PostponedArgumentsAnalyzer( } } - if (!hasExpressionInReturnArguments && !lambdaReturnType.isUnitOrFlexibleUnit) { + if (!hasExpressionInReturnArguments && !returnTypeRef.type.isUnitOrFlexibleUnit) { builder.addSubtypeConstraint( components.session.builtinTypes.unitType.type, - lambdaReturnType, + returnTypeRef.type, ConeLambdaArgumentConstraintPosition(lambda.atom) ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt index 76cfda5275b..fd4e2e19aa6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt @@ -661,7 +661,7 @@ class BodyResolveContext( val labelName = anonymousFunction.label?.name?.let { Name.identifier(it) } withContainer(anonymousFunction) { withLabelAndReceiverType(labelName, anonymousFunction, receiverTypeRef?.coneType, holder) { - if (mode is ResolutionMode.LambdaResolution) { + if (mode is ResolutionMode.LambdaResolution && mode.expectedReturnTypeRef == null) { withLambdaBeingAnalyzedInDependentContext(anonymousFunction.symbol, f) } else { f() diff --git a/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt index 1eb65c77223..90c53a98a77 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt @@ -27,7 +27,7 @@ fun testResultOfAnonFun2() = fun testReturnFromAnonFun() = run(fun () { - return if (true) 42 else println() + return if (true) 42 else println() }) fun testReturn1() = diff --git a/compiler/testData/diagnostics/tests/inference/coercionToUnit/nestedLambda.kt b/compiler/testData/diagnostics/tests/inference/coercionToUnit/nestedLambda.kt new file mode 100644 index 00000000000..6ccbc2d4e0c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/coercionToUnit/nestedLambda.kt @@ -0,0 +1,20 @@ +// FIR_IDENTICAL +// !SKIP_TXT +interface Context { + fun proceed(): T +} + +interface A { + fun process(block: Context.(T) -> Unit) +} + +fun processNested(body: () -> T): T { + return body() +} + +fun test(pipeline: A) { + pipeline.process { + // OK: processNested { /* no return */ proceed() /*: Any */ /* implicit coercion to Unit */ } + return@process processNested { proceed() } + } +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt index db821b0f188..78caf68098d 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt @@ -139,8 +139,8 @@ fun main() { * K <: (C) -> Unit -> TypeVariable(_RP1) >: C * K == (B) -> Unit -> TypeVariable(_RP1) == B */ - val x17: (C) -> Unit = selectB(id { it }, id { it }, id<(B) -> Unit> { x -> x }) - val x18: (C) -> Unit = select(id { it }, { it }, id<(B) -> Unit> { x -> x }) + val x17: (C) -> Unit = selectB(id { it }, id { it }, id<(B) -> Unit> { x -> x }) + val x18: (C) -> Unit = select(id { it }, { it }, id<(B) -> Unit> { x -> x }) // Resolution of extension/non-extension functions combination val x19: String.() -> Unit = select(")!>id { this }, ")!>id(fun(x: String) {})) diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt index 1520a1d44a4..7d960f86839 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt @@ -19,7 +19,7 @@ fun main() { val x1: suspend (Int) -> Unit = takeSuspend(")!>id { it }, ")!>{ x -> x }) // Here, the error should be - val x2: (Int) -> Unit = takeSuspend(")!>id { it }, ")!>{ x -> x }) - val x3: suspend (Int) -> Unit = takeSimpleFunction(")!>id { it }, ")!>{ x -> x }) + val x2: (Int) -> Unit = takeSuspend(")!>id { it }, ")!>{ x -> x }) + val x3: suspend (Int) -> Unit = takeSimpleFunction(")!>id { it }, ")!>{ x -> x }) val x4: (Int) -> Unit = takeSimpleFunction(id Unit> {}, ")!>{}) } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index e9510f43d39..8e28ee0d409 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -15235,6 +15235,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/lambdaWithNullableUnitInElvis.kt"); } + @Test + @TestMetadata("nestedLambda.kt") + public void testNestedLambda() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/nestedLambda.kt"); + } + @Test @TestMetadata("noCoercion.kt") public void testNoCoercion() throws Exception {