Fix type checking of local return inside return expression
#KT-16426 Fixed
This commit is contained in:
+33
-23
@@ -268,8 +268,8 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
|
|||||||
val result = Lists.newArrayList<KtReturnExpression>()
|
val result = Lists.newArrayList<KtReturnExpression>()
|
||||||
val bodyExpression = functionLiteral.bodyExpression
|
val bodyExpression = functionLiteral.bodyExpression
|
||||||
bodyExpression?.accept(object : KtTreeVisitor<MutableList<KtReturnExpression>>() {
|
bodyExpression?.accept(object : KtTreeVisitor<MutableList<KtReturnExpression>>() {
|
||||||
override fun visitReturnExpression(expression: KtReturnExpression, data: MutableList<KtReturnExpression>): Void? {
|
override fun visitReturnExpression(expression: KtReturnExpression, insideActualFunction: MutableList<KtReturnExpression>): Void? {
|
||||||
data.add(expression)
|
insideActualFunction.add(expression)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}, result)
|
}, result)
|
||||||
@@ -285,27 +285,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
|
|||||||
if ((function !is KtNamedFunction || function.typeReference != null)
|
if ((function !is KtNamedFunction || function.typeReference != null)
|
||||||
&& (function !is KtPropertyAccessor || function.returnTypeReference == null)) return
|
&& (function !is KtPropertyAccessor || function.returnTypeReference == null)) return
|
||||||
|
|
||||||
val bodyExpression = function.bodyExpression ?: return
|
for (returnForCheck in collectReturns(function, trace)) {
|
||||||
val returns = ArrayList<KtReturnExpression>()
|
|
||||||
|
|
||||||
// data == false means, that we inside other function, so ours return should be with label
|
|
||||||
bodyExpression.accept(object : KtTreeVisitor<Boolean>() {
|
|
||||||
override fun visitReturnExpression(expression: KtReturnExpression, data: Boolean): Void? {
|
|
||||||
val label = expression.getTargetLabel()
|
|
||||||
if ((label != null && trace[BindingContext.LABEL_TARGET, label] == function)
|
|
||||||
|| (label == null && data)
|
|
||||||
) {
|
|
||||||
returns.add(expression)
|
|
||||||
}
|
|
||||||
return super.visitReturnExpression(expression, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitNamedFunction(function: KtNamedFunction, data: Boolean): Void? {
|
|
||||||
return super.visitNamedFunction(function, false)
|
|
||||||
}
|
|
||||||
}, true)
|
|
||||||
|
|
||||||
for (returnForCheck in returns) {
|
|
||||||
val expression = returnForCheck.returnedExpression
|
val expression = returnForCheck.returnedExpression
|
||||||
if (expression == null) {
|
if (expression == null) {
|
||||||
if (!actualReturnType.isUnit()) {
|
if (!actualReturnType.isUnit()) {
|
||||||
@@ -320,4 +300,34 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun collectReturns(function: KtDeclarationWithBody, trace: BindingTrace): List<KtReturnExpression> {
|
||||||
|
val bodyExpression = function.bodyExpression ?: return emptyList()
|
||||||
|
val returns = ArrayList<KtReturnExpression>()
|
||||||
|
|
||||||
|
bodyExpression.accept(object : KtTreeVisitor<Boolean>() {
|
||||||
|
override fun visitReturnExpression(expression: KtReturnExpression, insideActualFunction: Boolean): Void? {
|
||||||
|
val labelTarget = expression.getTargetLabel()?.let { trace[BindingContext.LABEL_TARGET, it] }
|
||||||
|
if (labelTarget == function || (labelTarget == null && insideActualFunction)) {
|
||||||
|
returns.add(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitReturnExpression(expression, insideActualFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitNamedFunction(function: KtNamedFunction, data: Boolean): Void? {
|
||||||
|
return super.visitNamedFunction(function, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPropertyAccessor(accessor: KtPropertyAccessor, data: Boolean): Void? {
|
||||||
|
return super.visitPropertyAccessor(accessor, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer, data: Boolean): Void? {
|
||||||
|
return super.visitAnonymousInitializer(initializer, false)
|
||||||
|
}
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
return returns
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
interface ClassData
|
||||||
|
|
||||||
|
fun f() = object : ClassData {
|
||||||
|
val someInt: Int
|
||||||
|
get() {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String{
|
||||||
|
f()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
interface ClassData
|
||||||
|
|
||||||
|
fun f() = object : ClassData {
|
||||||
|
val someInt: Int
|
||||||
|
get() {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun g() = object : ClassData {
|
||||||
|
init {
|
||||||
|
if (true) {
|
||||||
|
<!RETURN_NOT_ALLOWED, RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY!>return<!> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun some(): Int {
|
||||||
|
return 6
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun f(): ClassData
|
||||||
|
public fun g(): ClassData
|
||||||
|
|
||||||
|
public interface ClassData {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+6
@@ -11093,6 +11093,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localReturnInsideProperty.kt")
|
||||||
|
public void testLocalReturnInsideProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("use.kt")
|
@TestMetadata("use.kt")
|
||||||
public void testUse() throws Exception {
|
public void testUse() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
||||||
|
|||||||
@@ -4534,6 +4534,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localReturnInsidePropertyAccessor.kt")
|
||||||
|
public void testLocalReturnInsidePropertyAccessor() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("specialConstructsAndPlatformTypes.kt")
|
@TestMetadata("specialConstructsAndPlatformTypes.kt")
|
||||||
public void testSpecialConstructsAndPlatformTypes() throws Exception {
|
public void testSpecialConstructsAndPlatformTypes() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt");
|
||||||
|
|||||||
@@ -11093,6 +11093,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localReturnInsideProperty.kt")
|
||||||
|
public void testLocalReturnInsideProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("use.kt")
|
@TestMetadata("use.kt")
|
||||||
public void testUse() throws Exception {
|
public void testUse() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
||||||
|
|||||||
@@ -11093,6 +11093,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localReturnInsideProperty.kt")
|
||||||
|
public void testLocalReturnInsideProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("use.kt")
|
@TestMetadata("use.kt")
|
||||||
public void testUse() throws Exception {
|
public void testUse() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
||||||
|
|||||||
@@ -12505,6 +12505,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localReturnInsideProperty.kt")
|
||||||
|
public void testLocalReturnInsideProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/localReturnInsideProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("use.kt")
|
@TestMetadata("use.kt")
|
||||||
public void testUse() throws Exception {
|
public void testUse() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/nonLocalReturns/use.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user