Skip to content

Commit c9b4685

Browse files
committed
Fix type checking of local return inside return expression
#KT-16426 Fixed
1 parent 7f287a4 commit c9b4685

File tree

9 files changed

+105
-22
lines changed

9 files changed

+105
-22
lines changed

compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
268268
val result = Lists.newArrayList<KtReturnExpression>()
269269
val bodyExpression = functionLiteral.bodyExpression
270270
bodyExpression?.accept(object : KtTreeVisitor<MutableList<KtReturnExpression>>() {
271-
override fun visitReturnExpression(expression: KtReturnExpression, data: MutableList<KtReturnExpression>): Void? {
272-
data.add(expression)
271+
override fun visitReturnExpression(expression: KtReturnExpression, insideActualFunction: MutableList<KtReturnExpression>): Void? {
272+
insideActualFunction.add(expression)
273273
return null
274274
}
275275
}, result)
@@ -285,39 +285,49 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
285285
if ((function !is KtNamedFunction || function.typeReference != null)
286286
&& (function !is KtPropertyAccessor || function.returnTypeReference == null)) return
287287

288-
val bodyExpression = function.bodyExpression ?: return
288+
for (returnForCheck in collectReturns(function, trace)) {
289+
val expression = returnForCheck.returnedExpression
290+
if (expression == null) {
291+
if (!actualReturnType.isUnit()) {
292+
trace.report(Errors.RETURN_TYPE_MISMATCH.on(returnForCheck, actualReturnType))
293+
}
294+
continue
295+
}
296+
297+
val expressionType = trace.getType(expression) ?: continue
298+
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, actualReturnType)) {
299+
trace.report(Errors.TYPE_MISMATCH.on(expression, expressionType, actualReturnType))
300+
}
301+
}
302+
}
303+
304+
private fun collectReturns(function: KtDeclarationWithBody, trace: BindingTrace): List<KtReturnExpression> {
305+
val bodyExpression = function.bodyExpression ?: return emptyList()
289306
val returns = ArrayList<KtReturnExpression>()
290307

291-
// data == false means, that we inside other function, so ours return should be with label
292308
bodyExpression.accept(object : KtTreeVisitor<Boolean>() {
293-
override fun visitReturnExpression(expression: KtReturnExpression, data: Boolean): Void? {
294-
val label = expression.getTargetLabel()
295-
if ((label != null && trace[BindingContext.LABEL_TARGET, label] == function)
296-
|| (label == null && data)
297-
) {
309+
override fun visitReturnExpression(expression: KtReturnExpression, insideActualFunction: Boolean): Void? {
310+
val labelTarget = expression.getTargetLabel()?.let { trace[BindingContext.LABEL_TARGET, it] }
311+
if (labelTarget == function || (labelTarget == null && insideActualFunction)) {
298312
returns.add(expression)
299313
}
300-
return super.visitReturnExpression(expression, data)
314+
315+
return super.visitReturnExpression(expression, insideActualFunction)
301316
}
302317

303318
override fun visitNamedFunction(function: KtNamedFunction, data: Boolean): Void? {
304319
return super.visitNamedFunction(function, false)
305320
}
306-
}, true)
307321

308-
for (returnForCheck in returns) {
309-
val expression = returnForCheck.returnedExpression
310-
if (expression == null) {
311-
if (!actualReturnType.isUnit()) {
312-
trace.report(Errors.RETURN_TYPE_MISMATCH.on(returnForCheck, actualReturnType))
313-
}
314-
continue
322+
override fun visitPropertyAccessor(accessor: KtPropertyAccessor, data: Boolean): Void? {
323+
return super.visitPropertyAccessor(accessor, false)
315324
}
316325

317-
val expressionType = trace.getType(expression) ?: continue
318-
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, actualReturnType)) {
319-
trace.report(Errors.TYPE_MISMATCH.on(expression, expressionType, actualReturnType))
326+
override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer, data: Boolean): Void? {
327+
return super.visitAnonymousInitializer(initializer, false)
320328
}
321-
}
329+
}, true)
330+
331+
return returns
322332
}
323333
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
interface ClassData
2+
3+
fun f() = object : ClassData {
4+
val someInt: Int
5+
get() {
6+
return 5
7+
}
8+
}
9+
10+
fun box(): String{
11+
f()
12+
return "OK"
13+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
interface ClassData
2+
3+
fun f() = object : ClassData {
4+
val someInt: Int
5+
get() {
6+
return 5
7+
}
8+
}
9+
10+
fun g() = object : ClassData {
11+
init {
12+
if (true) {
13+
<!RETURN_NOT_ALLOWED, RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY!>return<!> 0
14+
}
15+
}
16+
17+
fun some(): Int {
18+
return 6
19+
}
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package
2+
3+
public fun f(): ClassData
4+
public fun g(): ClassData
5+
6+
public interface ClassData {
7+
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
8+
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
9+
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
10+
}

compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11093,6 +11093,12 @@ public void testKt9644let() throws Exception {
1109311093
doTest(fileName);
1109411094
}
1109511095

11096+
@TestMetadata("localReturnInsideProperty.kt")
11097+
public void testLocalReturnInsideProperty() throws Exception {
11098+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
11099+
doTest(fileName);
11100+
}
11101+
1109611102
@TestMetadata("use.kt")
1109711103
public void testUse() throws Exception {
1109811104
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");

compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4534,6 +4534,12 @@ public void testLambdasInExclExclAndElvis() throws Exception {
45344534
doTest(fileName);
45354535
}
45364536

4537+
@TestMetadata("localReturnInsidePropertyAccessor.kt")
4538+
public void testLocalReturnInsidePropertyAccessor() throws Exception {
4539+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.kt");
4540+
doTest(fileName);
4541+
}
4542+
45374543
@TestMetadata("specialConstructsAndPlatformTypes.kt")
45384544
public void testSpecialConstructsAndPlatformTypes() throws Exception {
45394545
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt");

compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11093,6 +11093,12 @@ public void testKt9644let() throws Exception {
1109311093
doTest(fileName);
1109411094
}
1109511095

11096+
@TestMetadata("localReturnInsideProperty.kt")
11097+
public void testLocalReturnInsideProperty() throws Exception {
11098+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
11099+
doTest(fileName);
11100+
}
11101+
1109611102
@TestMetadata("use.kt")
1109711103
public void testUse() throws Exception {
1109811104
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");

compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11093,6 +11093,12 @@ public void testKt9644let() throws Exception {
1109311093
doTest(fileName);
1109411094
}
1109511095

11096+
@TestMetadata("localReturnInsideProperty.kt")
11097+
public void testLocalReturnInsideProperty() throws Exception {
11098+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
11099+
doTest(fileName);
11100+
}
11101+
1109611102
@TestMetadata("use.kt")
1109711103
public void testUse() throws Exception {
1109811104
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");

js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12505,6 +12505,12 @@ public void testKt9644let() throws Exception {
1250512505
doTest(fileName);
1250612506
}
1250712507

12508+
@TestMetadata("localReturnInsideProperty.kt")
12509+
public void testLocalReturnInsideProperty() throws Exception {
12510+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
12511+
doTest(fileName);
12512+
}
12513+
1250812514
@TestMetadata("use.kt")
1250912515
public void testUse() throws Exception {
1251012516
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");

0 commit comments

Comments
 (0)