From 86d1c7b7ec113ca228e80fe59795f21e4010b3e0 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 15 Feb 2017 17:58:12 +0300 Subject: [PATCH] JS: fix absence of temporary variable in secondary constructors. See KT-16377 --- .../js/test/semantics/BoxJsTestGenerated.java | 6 +++++ .../js/test/utils/DirectiveTestUtils.java | 27 ++++++++++++++++++- .../translate/declaration/ClassTranslator.kt | 3 ++- .../secondaryConstructorTemporaryVars.kt | 22 +++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 js/js.translator/testData/box/expression/evaluationOrder/secondaryConstructorTemporaryVars.kt diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index c2e5714e033..cceac5caf30 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -2149,6 +2149,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("secondaryConstructorTemporaryVars.kt") + public void testSecondaryConstructorTemporaryVars() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/expression/evaluationOrder/secondaryConstructorTemporaryVars.kt"); + doTest(fileName); + } + @TestMetadata("whenAsMinusArgument.kt") public void testWhenAsMinusArgument() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/expression/evaluationOrder/whenAsMinusArgument.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/DirectiveTestUtils.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/DirectiveTestUtils.java index 5042a1bbc3b..5bd5e746ec8 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/DirectiveTestUtils.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/DirectiveTestUtils.java @@ -16,9 +16,11 @@ package org.jetbrains.kotlin.js.test.utils; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.js.backend.ast.*; +import org.jetbrains.kotlin.js.inline.util.CollectUtilsKt; import org.jetbrains.kotlin.js.translate.expression.InlineMetadata; import java.util.*; @@ -261,6 +263,28 @@ public class DirectiveTestUtils { } }; + private static final DirectiveHandler HAS_NO_CAPTURED_VARS = new DirectiveHandler("HAS_NO_CAPTURED_VARS") { + @Override + void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception { + String functionName = arguments.getNamedArgument("function"); + + Set except = new HashSet(); + String exceptString = arguments.findNamedArgument("except"); + if (exceptString != null) { + for (String exceptId : StringUtil.split(exceptString, ";")) { + except.add(exceptId.trim()); + } + } + + JsFunction function = AstSearchUtil.getFunction(ast, functionName); + Set freeVars = CollectUtilsKt.collectFreeVariables(function); + for (JsName freeVar : freeVars) { + assertTrue("Function " + functionName + " captures free variable " + freeVar.getIdent(), + except.contains(freeVar.getIdent())); + } + } + }; + private static final List DIRECTIVE_HANDLERS = Arrays.asList( FUNCTION_CONTAINS_NO_CALLS, FUNCTION_NOT_CALLED, @@ -278,7 +302,8 @@ public class DirectiveTestUtils { COUNT_NULLS, NOT_REFERENCED, HAS_INLINE_METADATA, - HAS_NO_INLINE_METADATA + HAS_NO_INLINE_METADATA, + HAS_NO_CAPTURED_VARS ); public static void processDirectives(@NotNull JsNode ast, @NotNull String sourceCode) throws Exception { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index 6f85f1648d9..720a9afc901 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -217,13 +217,14 @@ class ClassTranslator private constructor( val constructorInitializer = context.getFunctionObject(constructorDescriptor) constructorInitializer.name = context.getInnerNameForDescriptor(constructorDescriptor) context.addDeclarationStatement(constructorInitializer.makeStmt()) + + context = context.contextWithScope(constructorInitializer) context.translateAndAliasParameters(constructorDescriptor, constructorInitializer.parameters) .translateFunction(constructor, constructorInitializer) // Translate super/this call val superCallGenerators = mutableListOf<(MutableList) -> Unit>() val referenceToClass = context.getInnerReference(classDescriptor) - context = context.contextWithScope(constructorInitializer) superCallGenerators += { it += FunctionBodyTranslator.setDefaultValueForArguments(constructorDescriptor, context) } diff --git a/js/js.translator/testData/box/expression/evaluationOrder/secondaryConstructorTemporaryVars.kt b/js/js.translator/testData/box/expression/evaluationOrder/secondaryConstructorTemporaryVars.kt new file mode 100644 index 00000000000..a983fbf3b8f --- /dev/null +++ b/js/js.translator/testData/box/expression/evaluationOrder/secondaryConstructorTemporaryVars.kt @@ -0,0 +1,22 @@ +// HAS_NO_CAPTURED_VARS: function=A_init except=Kotlin;A + +class A() { + var y: String? = null + var z: Any? = null + + constructor(x: Any) : this() { + y = if (x == "foo") "!!!" else { z = x; ">>>" } + } +} + +fun box(): String { + val a = A("foo") + if (a.y != "!!!") return "fail1: ${a.y}" + if (a.z != null) return "fail2: ${a.z}" + + val b = A(23) + if (b.y != ">>>") return "fail3: ${b.y}" + if (b.z != 23) return "fail4: ${b.z}" + + return "OK" +} \ No newline at end of file