[FIR] Fix missing RETURN_TYPE_MISMATCH for labeled return statements
in lambda functions, ^KT-59907 Fixed
This commit is contained in:
committed by
Space Team
parent
2e4d486131
commit
8e72f60996
+1
-1
@@ -37,7 +37,7 @@ fun errorWithLambda(): String {
|
|||||||
return@foo
|
return@foo
|
||||||
} foo {
|
} foo {
|
||||||
bar()
|
bar()
|
||||||
return@foo <!ARGUMENT_TYPE_MISMATCH!>10<!>
|
return@foo <!ARGUMENT_TYPE_MISMATCH, RETURN_TYPE_MISMATCH!>10<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
+27
-6
@@ -9,20 +9,19 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
|
|||||||
import org.jetbrains.kotlin.KtRealSourceElementKind
|
import org.jetbrains.kotlin.KtRealSourceElementKind
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
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.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.hasExplicitReturnType
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.hasExplicitReturnType
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch
|
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.NULL_FOR_NONNULL_TYPE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH
|
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.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
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.FirReturnExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
|
||||||
object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||||
@@ -31,7 +30,7 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
|||||||
if (expression.source?.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor) return
|
if (expression.source?.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor) return
|
||||||
|
|
||||||
val targetElement = expression.target.labeledElement
|
val targetElement = expression.target.labeledElement
|
||||||
if (targetElement is FirErrorFunction || targetElement is FirAnonymousFunction && targetElement.isLambda) {
|
if (targetElement is FirErrorFunction) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +90,21 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (resultExpression.source?.kind is KtFakeSourceElementKind.ImplicitUnit && !functionReturnType.isUnit) {
|
} 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
|
||||||
reporter.reportOn(
|
reporter.reportOn(
|
||||||
resultExpression.source,
|
resultExpression.source,
|
||||||
RETURN_TYPE_MISMATCH,
|
RETURN_TYPE_MISMATCH,
|
||||||
@@ -103,4 +116,12 @@ 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 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
fun test(a: Int) {
|
fun test(a: Int) {
|
||||||
run f@{
|
run f@{
|
||||||
if (a > 0) return@f
|
if (a > 0) <!RETURN_TYPE_MISMATCH!>return@f<!>
|
||||||
else return@f 1
|
else return@f 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-6
@@ -1,6 +0,0 @@
|
|||||||
val flag = true
|
|
||||||
|
|
||||||
val a = b@ {
|
|
||||||
if (flag) return@b 4
|
|
||||||
return@b
|
|
||||||
}
|
|
||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
val flag = true
|
val flag = true
|
||||||
|
|
||||||
val a = b@ {
|
val a = b@ {
|
||||||
if (flag) return@b <!RETURN_TYPE_MISMATCH!>4<!>
|
if (flag) return@b <!RETURN_TYPE_MISMATCH!>4<!>
|
||||||
return@b
|
return@b
|
||||||
}
|
}
|
||||||
Vendored
+2
-2
@@ -14,7 +14,7 @@ val b = run {
|
|||||||
|
|
||||||
// Unit
|
// Unit
|
||||||
val c = run {
|
val c = run {
|
||||||
if (flag) return@run
|
if (flag) <!RETURN_TYPE_MISMATCH!>return@run<!>
|
||||||
|
|
||||||
return@run 4
|
return@run 4
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
fun test(a: Int) {
|
fun test(a: Int) {
|
||||||
run<Int>f@{
|
run<Int>f@{
|
||||||
if (a > 0) return@f <!ARGUMENT_TYPE_MISMATCH!>""<!>
|
if (a > 0) return@f <!ARGUMENT_TYPE_MISMATCH, RETURN_TYPE_MISMATCH!>""<!>
|
||||||
return@f 1
|
return@f 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ fun test(a: A<out CharSequence>, z: Out<CharSequence>) {
|
|||||||
a.bar { <!ARGUMENT_TYPE_MISMATCH, TYPE_MISMATCH!>z.id()<!> }
|
a.bar { <!ARGUMENT_TYPE_MISMATCH, TYPE_MISMATCH!>z.id()<!> }
|
||||||
|
|
||||||
a.foo {
|
a.foo {
|
||||||
z.foobar(if (1 > 2) return@foo <!ARGUMENT_TYPE_MISMATCH!>""<!> else "")
|
z.foobar(if (1 > 2) return@foo <!ARGUMENT_TYPE_MISMATCH, RETURN_TYPE_MISMATCH!>""<!> else "")
|
||||||
<!ARGUMENT_TYPE_MISMATCH!>""<!>
|
<!ARGUMENT_TYPE_MISMATCH!>""<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-2
@@ -32,9 +32,9 @@ fun foo() {
|
|||||||
// Doesn't work both in K1 and K2, but probably should (KT-58232 for tracking)
|
// Doesn't work both in K1 and K2, but probably should (KT-58232 for tracking)
|
||||||
val dates3 = <!NEW_INFERENCE_ERROR!>myRun {
|
val dates3 = <!NEW_INFERENCE_ERROR!>myRun {
|
||||||
when {
|
when {
|
||||||
else -> return@myRun buildList {
|
else -> return@myRun <!RETURN_TYPE_MISMATCH!>buildList {
|
||||||
add(4)
|
add(4)
|
||||||
}
|
}<!>
|
||||||
}
|
}
|
||||||
}<!>
|
}<!>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user