From 6239301f4ea7e291c47ad3a4af30dd5c626d2481 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 8 Dec 2020 14:53:04 -0800 Subject: [PATCH] FIR: no constraint for coerced-to-Unit last expression of lambda --- .../RedundantReturnUnitTypeChecker.txt | 4 +-- .../resolveWithStdlib/complexPostponedCfg.dot | 2 +- .../resolveWithStdlib/complexPostponedCfg.txt | 2 +- .../inference/PostponedArgumentsAnalyzer.kt | 32 ++++++++++++------- ...rLambdaReturnTypeWithFlexibleConstraint.kt | 1 - .../postponedArgumentsAnalysis/basic.fir.kt | 4 +-- .../suspendFunctions.fir.kt | 8 ++--- 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantReturnUnitTypeChecker.txt b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantReturnUnitTypeChecker.txt index ede0c8c0e4e..58e4524988a 100644 --- a/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantReturnUnitTypeChecker.txt +++ b/compiler/fir/analysis-tests/testData/extendedCheckers/RedundantReturnUnitTypeChecker.txt @@ -59,7 +59,7 @@ FILE: RedundantReturnUnitTypeChecker.kt } public final fun foo(): R|kotlin/Unit| { - ^foo this@R|/B|.R|/B.run|( = run@fun (): R|kotlin/Int| { + ^foo this@R|/B|.R|/B.run|( = run@fun (): R|kotlin/Unit| { this@R|/B|.R|/B.bar|() } ) @@ -88,7 +88,7 @@ FILE: RedundantReturnUnitTypeChecker.kt } public final fun goo(): R|kotlin/Unit| { - ^goo (this@R|/B|, Int(1)).R|/B.let|( = let@fun (it: R|kotlin/Int|): R|kotlin/Int| { + ^goo (this@R|/B|, Int(1)).R|/B.let|( = let@fun (it: R|kotlin/Int|): R|kotlin/Unit| { this@R|/B|.R|/B.bar|() } ) diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot index bdb4b3cb219..f4efbcab670 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.dot @@ -63,7 +63,7 @@ digraph complexPostponedCfg_kt { } 34 [label="Call arguments union" style="filled" fillcolor=yellow]; 35 [label="Postponed exit from lambda"]; - 36 [label="Function call: R|kotlin/with|(...)"]; + 36 [label="Function call: R|kotlin/with|(...)"]; 37 [label="Exit block"]; } 38 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt index 9ece8fb6153..567a734e67b 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/complexPostponedCfg.txt @@ -7,7 +7,7 @@ FILE: complexPostponedCfg.kt lval firstCalls: R|kotlin/collections/List| = R|kotlin/with||>((R|/statements|.R|kotlin/collections/last|() as R|FirFunctionCall|), = setCall@fun R|FirFunctionCall|.(): R|kotlin/collections/List| { ^ R|kotlin/collections/buildList|( = buildList@fun R|kotlin/collections/MutableList|.(): R|kotlin/Unit| { this@R|special/anonymous|.R|SubstitutionOverride|(this@R|special/anonymous|) - R|kotlin/with|((R|/arguments|.R|kotlin/collections/last|() as R|FirFunctionCall|), = plusCall@fun R|FirFunctionCall|.(): R|kotlin/Boolean| { + R|kotlin/with|((R|/arguments|.R|kotlin/collections/last|() as R|FirFunctionCall|), = plusCall@fun R|FirFunctionCall|.(): R|kotlin/Unit| { this@R|special/anonymous|.R|SubstitutionOverride|(this@R|special/anonymous|) this@R|special/anonymous|.R|SubstitutionOverride|((R|/explicitReceiver| as R|FirFunctionCall|)) } 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 886b301fb1c..617fc230892 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 @@ -130,7 +130,7 @@ class PostponedArgumentsAnalyzer( rawReturnType, stubsForPostponedVariables ) - applyResultsOfAnalyzedLambdaToCandidateSystem(c, lambda, candidate, results, ::substitute) + applyResultsOfAnalyzedLambdaToCandidateSystem(c, lambda, candidate, results, expectedTypeForReturnArguments, ::substitute) return results } @@ -139,6 +139,7 @@ class PostponedArgumentsAnalyzer( lambda: ResolvedLambdaAtom, candidate: Candidate, results: ReturnArgumentsAnalysisResult, + expectedReturnType: ConeKotlinType? = null, substitute: (ConeKotlinType) -> ConeKotlinType = c.createSubstituteFunctorForLambdaAnalysis() ) { val (returnArguments, inferenceSession) = results @@ -164,21 +165,30 @@ class PostponedArgumentsAnalyzer( val checkerSink: CheckerSink = CheckerSinkImpl(candidate) + val lastExpression = lambda.atom.body?.statements?.lastOrNull() as? FirExpression var hasExpressionInReturnArguments = false + // No constraint for return expressions of lambda if it has Unit return type. val lambdaReturnType = lambda.returnType.let(substitute).takeUnless { it.isUnit } returnArguments.forEach { if (it !is FirExpression) return@forEach hasExpressionInReturnArguments = true - candidate.resolveArgumentExpression( - c.getBuilder(), - it, - lambdaReturnType, - lambda.atom.returnTypeRef, // TODO: proper ref - checkerSink, - context = resolutionContext, - isReceiver = false, - isDispatch = false - ) + // If it is the last expression, and the expected type is Unit, that expression will be coerced to Unit. + // If the last expression is of Unit type, of course it's not coercion-to-Unit case. + val lastExpressionCoercedToUnit = + it == lastExpression && expectedReturnType?.isUnit == true && !it.typeRef.coneType.isUnit + // No constraint for the last expression of lambda if it will be coerced to Unit. + if (!lastExpressionCoercedToUnit) { + candidate.resolveArgumentExpression( + c.getBuilder(), + it, + lambdaReturnType, + lambda.atom.returnTypeRef, // TODO: proper ref + checkerSink, + context = resolutionContext, + isReceiver = false, + isDispatch = false + ) + } } if (!hasExpressionInReturnArguments && lambdaReturnType != null) { diff --git a/compiler/testData/codegen/box/inference/coercionToUnitForLambdaReturnTypeWithFlexibleConstraint.kt b/compiler/testData/codegen/box/inference/coercionToUnitForLambdaReturnTypeWithFlexibleConstraint.kt index 508097cad2a..18743a61156 100644 --- a/compiler/testData/codegen/box/inference/coercionToUnitForLambdaReturnTypeWithFlexibleConstraint.kt +++ b/compiler/testData/codegen/box/inference/coercionToUnitForLambdaReturnTypeWithFlexibleConstraint.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FILE: TestJ.java 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 06588262147..86870041ce5 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt @@ -142,8 +142,8 @@ fun main() { 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) {})) - val x20: String.() -> Unit = select(")!>{ this }, (fun(x: String) {})) + val x19: String.() -> Unit = select(")!>id { this }, ")!>id(fun(x: String) {})) + val x20: String.() -> Unit = select(")!>{ this }, (fun(x: String) {})) val x21: String.() -> Unit = select(")!>id(fun(x: String) {}), ")!>id(fun(x: String) {})) select(id Unit>(fun(x: String) {}), ")!>id(fun(x: String) {})) select(")!>id(fun String.(x: String) {}), ")!>id(fun(x: String, y: 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 5b464405de2..3eac7717eb6 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt @@ -14,12 +14,12 @@ fun main() { select(")!>id {}, id(suspend {})) select(")!>id {}, id Unit> {}) - takeSuspend(")!>id { it }, ")!>{ x -> x }) + takeSuspend(")!>id { it }, ")!>{ x -> x }) - val x1: suspend (Int) -> Unit = takeSuspend(")!>id { it }, ")!>{ x -> x }) + 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> {}, {}) }