JS: support non-local return from secondary constructor

See KT-14549
This commit is contained in:
Alexey Andreev
2017-09-27 17:14:33 +03:00
parent e323da3c5e
commit c15847a957
5 changed files with 21 additions and 10 deletions
@@ -1,6 +1,3 @@
// TODO enable for JS backend too when KT-14549 will be fixed
// IGNORE_BACKEND: JS
inline fun run(block: () -> Unit) = block()
class A {
@@ -53,6 +53,8 @@ var JsNameRef.psiElement: PsiElement? by MetadataProperty(default = null)
var JsFunction.isLocal: Boolean by MetadataProperty(default = false)
var JsFunction.forcedReturnVariable: JsName? by MetadataProperty(default = null)
var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
var JsInvocation.typeCheck: TypeCheck? by MetadataProperty(default = null)
@@ -361,6 +361,22 @@ public class JsInliner extends JsVisitorWithContextImpl {
// body of inline function can contain call to lambdas that need to be inlined
JsStatement inlineableBodyWithLambdasInlined = accept(inlineableBody);
assert inlineableBody == inlineableBodyWithLambdasInlined;
// Support non-local return from secondary constructor
// Returns from secondary constructors should return `$this` object.
JsFunction currentFunction = getCurrentNamedFunction();
if (currentFunction != null) {
JsName returnVariable = MetadataProperties.getForcedReturnVariable(currentFunction);
if (returnVariable != null) {
inlineableBody.accept(new RecursiveJsVisitor() {
@Override
public void visitReturn(@NotNull JsReturn x) {
x.setExpression(returnVariable.makeRef());
}
});
}
}
statementContext.addPrevious(flattenStatement(inlineableBody));
/*
@@ -21884,13 +21884,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("withNonLocalReturn.kt")
public void testWithNonLocalReturn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/secondaryConstructors/withNonLocalReturn.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("withReturn.kt")
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.forcedReturnVariable
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
import org.jetbrains.kotlin.js.translate.context.*
@@ -281,6 +282,7 @@ class ClassTranslator private constructor(
}
constructorInitializer.parameters += JsParameter(thisName)
constructorInitializer.forcedReturnVariable = thisName
// Generate super/this call to insert to beginning of the function
val resolvedCall = BindingContextUtils.getDelegationConstructorCall(context.bindingContext(), constructorDescriptor)