diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt index cb7460aad0c..9a37dcdcb6a 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt @@ -37,7 +37,7 @@ fun errorWithLambda(): String { return@foo } foo { bar() - return@foo 10 + return@foo 10 } return "" diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt index 6c2acf0bbc7..f7f97cbc7db 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt @@ -9,19 +9,20 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtRealSourceElementKind import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn -import org.jetbrains.kotlin.fir.analysis.cfa.util.previousCfgNodes import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.declaration.hasExplicitReturnType import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULL_FOR_NONNULL_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE -import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction +import org.jetbrains.kotlin.fir.declarations.FirConstructor +import org.jetbrains.kotlin.fir.declarations.FirErrorFunction +import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor import org.jetbrains.kotlin.fir.expressions.FirReturnExpression import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression import org.jetbrains.kotlin.fir.expressions.FirWhenExpression import org.jetbrains.kotlin.fir.expressions.isExhaustive -import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph import org.jetbrains.kotlin.fir.types.* object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() { @@ -30,7 +31,7 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() { if (expression.source?.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor) return val targetElement = expression.target.labeledElement - if (targetElement is FirErrorFunction) { + if (targetElement is FirErrorFunction || targetElement is FirAnonymousFunction && targetElement.isLambda) { return } @@ -90,21 +91,7 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() { ) } } - } else if (resultExpression.source?.kind is KtFakeSourceElementKind.ImplicitUnit && - !functionReturnType.isUnit && - shouldCheckMismatchForAnonymousFunction(targetElement, expression) - ) { - // Disallow cases like - // fun foo(): Any { return } - // Allow cases like - // fun foo(): Unit { return } - // fun foo() { return Unit } - // But ignore anonymous functions without explicit returns, the following code is valid (where type of parameter R is being inferenced): - // run { - // if (flag) return@run - // "str" - // } - // If type parameter is specified explicitly, checking is performed in the branch above and RETURN_TYPE_MISMATCH is reported + } else if (resultExpression.source?.kind is KtFakeSourceElementKind.ImplicitUnit && !functionReturnType.isUnit) { reporter.reportOn( resultExpression.source, RETURN_TYPE_MISMATCH, @@ -116,12 +103,4 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() { ) } } - - private fun shouldCheckMismatchForAnonymousFunction(targetElement: FirFunction, expression: FirReturnExpression): Boolean { - if (targetElement !is FirAnonymousFunction || !targetElement.isLambda) return true - val cfgNodes = targetElement.controlFlowGraphReference?.controlFlowGraph?.exitNode?.previousCfgNodes ?: return true - // Check if any return expression other than the current is explicit - return cfgNodes.any { if (it.fir === expression) false else it.fir is FirReturnExpression } - } } - diff --git a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnNoCoercionToUnit.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnNoCoercionToUnit.fir.kt index ed8325c002e..bd241153105 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnNoCoercionToUnit.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnNoCoercionToUnit.fir.kt @@ -1,6 +1,6 @@ fun test(a: Int) { run f@{ - if (a > 0) return@f + if (a > 0) return@f else return@f 1 } } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnSecondUnit.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnSecondUnit.fir.kt new file mode 100644 index 00000000000..d1fb85056b4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnSecondUnit.fir.kt @@ -0,0 +1,6 @@ +val flag = true + +val a = b@ { + if (flag) return@b 4 + return@b +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnSecondUnit.kt b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnSecondUnit.kt index 11d8ab569cd..859d60ede90 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnSecondUnit.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnSecondUnit.kt @@ -1,7 +1,6 @@ -// FIR_IDENTICAL val flag = true val a = b@ { if (flag) return@b 4 return@b -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnUnitAndDontCareType.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnUnitAndDontCareType.fir.kt index 47b2f719cb8..0dcc17c600a 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnUnitAndDontCareType.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnUnitAndDontCareType.fir.kt @@ -14,7 +14,7 @@ val b = run { // Unit val c = run { - if (flag) return@run + if (flag) return@run return@run 4 -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnsWithExplicitReturnType.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnsWithExplicitReturnType.fir.kt index 959a6fdc54d..e5f864f2baa 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnsWithExplicitReturnType.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/return/LocalReturnsWithExplicitReturnType.fir.kt @@ -1,6 +1,6 @@ fun test(a: Int) { runf@{ - if (a > 0) return@f "" + if (a > 0) return@f "" return@f 1 } diff --git a/compiler/testData/diagnostics/tests/generics/projectionsScope/typeMismatchInLambda.fir.kt b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeMismatchInLambda.fir.kt index ba6cde6ace1..c71c7c06a0f 100644 --- a/compiler/testData/diagnostics/tests/generics/projectionsScope/typeMismatchInLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/projectionsScope/typeMismatchInLambda.fir.kt @@ -20,7 +20,7 @@ fun test(a: A, z: Out) { a.bar { z.id() } a.foo { - z.foobar(if (1 > 2) return@foo "" else "") + z.foobar(if (1 > 2) return@foo "" else "") "" } } diff --git a/compiler/testData/diagnostics/tests/inference/nothingType/returnAsLastStatementInLambda.fir.kt b/compiler/testData/diagnostics/tests/inference/nothingType/returnAsLastStatementInLambda.fir.kt index dd9b4bd9ba8..680fdb4122e 100644 --- a/compiler/testData/diagnostics/tests/inference/nothingType/returnAsLastStatementInLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/nothingType/returnAsLastStatementInLambda.fir.kt @@ -32,9 +32,9 @@ fun foo() { // Doesn't work both in K1 and K2, but probably should (KT-58232 for tracking) val dates3 = myRun { when { - else -> return@myRun buildList { + else -> return@myRun buildList { add(4) - } + } } } }