diff --git a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt index 578c5a82c2c..cadb11e7f58 100644 --- a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt +++ b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt @@ -55,7 +55,7 @@ var JsReturn.returnTarget: FunctionDescriptor? by MetadataProperty(default = nul var HasMetadata.synthetic: Boolean by MetadataProperty(default = false) -var HasMetadata.sideEffects: Boolean by MetadataProperty(default = true) +var HasMetadata.sideEffects: SideEffectKind by MetadataProperty(default = SideEffectKind.AFFECTS_STATE) enum class TypeCheck { TYPEOF, @@ -64,3 +64,9 @@ enum class TypeCheck { IS_ANY, AND_PREDICATE } + +enum class SideEffectKind { + AFFECTS_STATE, + DEPENDS_ON_STATE, + PURE +} \ No newline at end of file diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt index 88a3f904faa..f1750efbdbb 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/ExpressionDecomposer.kt @@ -17,10 +17,7 @@ package org.jetbrains.kotlin.js.inline import com.google.dart.compiler.backend.js.ast.* -import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata -import com.google.dart.compiler.backend.js.ast.metadata.sideEffects -import com.google.dart.compiler.backend.js.ast.metadata.staticRef -import com.google.dart.compiler.backend.js.ast.metadata.synthetic +import com.google.dart.compiler.backend.js.ast.metadata.* import com.intellij.util.SmartList import org.jetbrains.kotlin.js.inline.util.IdentitySet import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.* @@ -270,7 +267,7 @@ internal class ExpressionDecomposer private constructor( // Qualifier might be a reference to lambda property. See KT-7674 // An exception here is `fn.call()`, which are marked as side effect free. Further recognition of such // case in inliner might be quite difficult, so never extract such call (and other calls marked this way). - if (qualifier in containsNodeWithSideEffect && (qualifier as? HasMetadata)?.sideEffects ?: true) { + if (qualifier in containsNodeWithSideEffect && (qualifier as? HasMetadata)?.sideEffects != SideEffectKind.PURE) { qualifier = qualifier.extractToTemporary() } else if (callee != null && receiver != null && receiver in containsNodeWithSideEffect) { diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/IneffectiveStatementElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/IneffectiveStatementElimination.kt index 4c8e7007256..db13093fdb5 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/IneffectiveStatementElimination.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/IneffectiveStatementElimination.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.js.inline.clean import com.google.dart.compiler.backend.js.ast.* +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import com.google.dart.compiler.backend.js.ast.metadata.synthetic import org.jetbrains.kotlin.js.inline.util.collectLocalVariables @@ -53,7 +54,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) { if (expression.name in localVars) { listOf() } - else if (!expression.sideEffects) { + else if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) { val qualifier = expression.qualifier if (qualifier != null) replace(qualifier) else listOf() } @@ -78,7 +79,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) { } is JsBinaryOperation -> { - if (expression.sideEffects) { + if (expression.sideEffects == SideEffectKind.AFFECTS_STATE) { when (expression.operator) { JsBinaryOperator.BIT_AND, JsBinaryOperator.BIT_OR, @@ -130,7 +131,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) { } is JsInvocation -> { - if (!expression.sideEffects) { + if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) { replace(expression.qualifier) + replaceMany(expression.arguments) } else { @@ -139,7 +140,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) { } is JsNew -> { - if (!expression.sideEffects) { + if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) { replace(expression.constructorExpression) + replaceMany(expression.arguments) } else { @@ -166,7 +167,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) { // Then, inlined body of `bar` never uses `$tmp`, therefore we can eliminate it, so `Kotlin.modules['foo']` remains. // It's good to eliminate such useless expression. is JsArrayAccess -> { - if (!expression.sideEffects) { + if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) { replace(expression.arrayExpression) + replace(expression.indexExpression) } else { diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt index ffe8a425175..4bef65233eb 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.js.inline.clean import com.google.dart.compiler.backend.js.ast.* +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import com.google.dart.compiler.backend.js.ast.metadata.synthetic import org.jetbrains.kotlin.js.inline.util.collectFreeVariables @@ -180,14 +181,14 @@ internal class TemporaryVariableElimination(function: JsFunction) { } super.visitNameRef(nameRef) - if (nameRef.qualifier != null && nameRef.sideEffects) { + if (nameRef.qualifier != null && nameRef.sideEffects == SideEffectKind.AFFECTS_STATE) { sideEffectOccurred = true } } override fun visitInvocation(invocation: JsInvocation) { super.visitInvocation(invocation) - if (invocation.sideEffects) { + if (invocation.sideEffects == SideEffectKind.AFFECTS_STATE) { sideEffectOccurred = true } } @@ -242,7 +243,7 @@ internal class TemporaryVariableElimination(function: JsFunction) { override fun visitArrayAccess(x: JsArrayAccess) { super.visitArrayAccess(x) - if (x.sideEffects) { + if (x.sideEffects == SideEffectKind.AFFECTS_STATE) { sideEffectOccurred = true } } @@ -533,15 +534,21 @@ internal class TemporaryVariableElimination(function: JsFunction) { private fun isTrivial(expr: JsExpression): Boolean = when (expr) { is JsNameRef -> { - val name = expr.name - name in namesToProcess && when (definitions[name]) { - null, 0 -> true - 1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false - else -> false + val qualifier = expr.qualifier + if (expr.sideEffects == SideEffectKind.PURE && (qualifier == null || isTrivial(qualifier))) { + true + } + else { + val name = expr.name + name in namesToProcess && when (definitions[name]) { + null, 0 -> true + 1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false + else -> false + } } } is JsLiteral.JsValueLiteral -> true - is JsInvocation -> !expr.sideEffects && isTrivial(expr.qualifier) && expr.arguments.all { isTrivial(it) } + is JsInvocation -> expr.sideEffects == SideEffectKind.PURE && isTrivial(expr.qualifier) && expr.arguments.all { isTrivial(it) } is JsArrayAccess -> isTrivial(expr.arrayExpression) && isTrivial(expr.indexExpression) else -> false } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/sideEffectUtils.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/sideEffectUtils.kt index b8af2434035..8bdd5b8c15f 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/sideEffectUtils.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/sideEffectUtils.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.inline.util import com.google.dart.compiler.backend.js.ast.* import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.any @@ -28,7 +29,7 @@ fun JsExpression.canHaveOwnSideEffect(vars: Set) = when (this) { is JsConditional, is JsLiteral -> false is JsBinaryOperation -> operator.isAssignment - is JsNameRef -> name !in vars && sideEffects - is HasMetadata -> sideEffects + is JsNameRef -> name !in vars && sideEffects != SideEffectKind.PURE + is HasMetadata -> sideEffects != SideEffectKind.PURE else -> true } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineEvaluationOrderTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineEvaluationOrderTestGenerated.java index 21e64fd927e..edd990582a9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineEvaluationOrderTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/InlineEvaluationOrderTestGenerated.java @@ -257,6 +257,18 @@ public class InlineEvaluationOrderTestGenerated extends AbstractInlineEvaluation doTest(fileName); } + @TestMetadata("propertyAccessAfterModification.kt") + public void testPropertyAccessAfterModification() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAfterModification.kt"); + doTest(fileName); + } + + @TestMetadata("propertyAccessAndInitializer.kt") + public void testPropertyAccessAndInitializer() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAndInitializer.kt"); + doTest(fileName); + } + @TestMetadata("propertyAccessWithSideEffect.kt") public void testPropertyAccessWithSideEffect() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessWithSideEffect.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt index fc54d6a3387..9b072e06aaa 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt @@ -20,6 +20,7 @@ import com.google.dart.compiler.backend.js.ast.JsEmptyExpression import com.google.dart.compiler.backend.js.ast.JsExpression import com.google.dart.compiler.backend.js.ast.JsName import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -76,7 +77,7 @@ fun VariableAccessInfo.constructAccessExpression(ref: JsExpression): JsExpressio return ref } else { return if (value !is JsEmptyExpression) { - (ref as? HasMetadata)?.let { it.sideEffects = false } + (ref as? HasMetadata)?.let { it.sideEffects = SideEffectKind.PURE } JsAstUtils.assignment(ref, value!!) } else { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt index 289eb2d72d0..2f1113d63f9 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.js.translate.operation.OperatorTable import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn import org.jetbrains.kotlin.js.translate.utils.PsiUtils import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -59,7 +59,7 @@ object DefaultFunctionCallCase : FunctionCallCase() { if (isNative && hasSpreadOperator) { return nativeSpreadFunWithDispatchOrExtensionReceiver(argumentsInfo, functionName) } - return JsInvocation(fqnWithoutSideEffects(functionName, dispatchReceiver), argumentsInfo.translateArguments) + return JsInvocation(pureFqn(functionName, dispatchReceiver), argumentsInfo.translateArguments) } fun buildDefaultCallWithoutReceiver(context: TranslationContext, @@ -78,7 +78,7 @@ object DefaultFunctionCallCase : FunctionCallCase() { val functionRef = context.aliasOrValue(callableDescriptor) { val qualifierForFunction = context.getQualifierForDescriptor(it) - fqnWithoutSideEffects(functionName, qualifierForFunction) + pureFqn(functionName, qualifierForFunction) } return JsInvocation(functionRef, argumentsInfo.translateArguments) } @@ -101,7 +101,7 @@ object DefaultFunctionCallCase : FunctionCallCase() { val functionRef = context.aliasOrValue(callableDescriptor) { val qualifierForFunction = context.getQualifierForDescriptor(it) - fqnWithoutSideEffects(functionName, qualifierForFunction) // TODO: remake to call + pureFqn(functionName, qualifierForFunction) // TODO: remake to call } val referenceToCall = @@ -238,7 +238,7 @@ object SuperCallCase : FunctionCallCase() { override fun FunctionCallInfo.dispatchReceiver(): JsExpression { // TODO: spread operator - val prototypeClass = fqnWithoutSideEffects(Namer.getPrototypeName(), calleeOwner) + val prototypeClass = pureFqn(Namer.getPrototypeName(), calleeOwner) val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass)) return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(dispatchReceiver!!)) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt index 414fcf982e5..0725fd26396 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.translate.callTranslator import com.google.dart.compiler.backend.js.ast.JsExpression import com.google.dart.compiler.backend.js.ast.JsInvocation import com.google.dart.compiler.backend.js.ast.JsNameRef +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -74,8 +75,8 @@ object DefaultVariableAccessCase : VariableAccessCase() { override fun VariableAccessInfo.dispatchReceiver(): JsExpression { val accessor = JsNameRef(variableName, dispatchReceiver!!) val descriptor = callableDescriptor - if (descriptor is PropertyDescriptor && JsDescriptorUtils.sideEffectsPossible(descriptor)) { - accessor.sideEffects = false + if (descriptor is PropertyDescriptor && !JsDescriptorUtils.sideEffectsPossible(descriptor)) { + accessor.sideEffects = SideEffectKind.DEPENDS_ON_STATE } return constructAccessExpression(accessor) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index 8750c1e8846..47ca0f95347 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -17,13 +17,12 @@ package org.jetbrains.kotlin.js.translate.context; import com.google.dart.compiler.backend.js.ast.*; -import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata; import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind; import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; @@ -38,7 +37,7 @@ import java.util.Collections; import java.util.List; import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects; +import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn; import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName; @@ -143,7 +142,7 @@ public final class Namer { @NotNull public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) { - return fqnWithoutSideEffects(SUPER_METHOD_NAME, superClassJsName.makeRef()); + return pureFqn(SUPER_METHOD_NAME, superClassJsName.makeRef()); } @NotNull @@ -182,7 +181,7 @@ public final class Namer { @NotNull public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) { - return fqnWithoutSideEffects(getPrototypeName(), classOrTraitExpression); + return pureFqn(getPrototypeName(), classOrTraitExpression); } @NotNull @@ -207,12 +206,12 @@ public final class Namer { @NotNull public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) { - return fqnWithoutSideEffects(CALL_FUNCTION, functionExpression); + return pureFqn(CALL_FUNCTION, functionExpression); } @NotNull public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) { - return fqnWithoutSideEffects(APPLY_FUNCTION, functionExpression); + return pureFqn(APPLY_FUNCTION, functionExpression); } @NotNull @@ -222,7 +221,7 @@ public final class Namer { @NotNull public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) { - return fqnWithoutSideEffects(CAPTURED_VAR_FIELD, ref); + return pureFqn(CAPTURED_VAR_FIELD, ref); } @NotNull @@ -297,7 +296,6 @@ public final class Namer { isTypeName = kotlinScope.declareName("isType"); modulesMap = kotlin("modules"); - MetadataProperties.setSideEffects((HasMetadata) modulesMap, false); } @NotNull @@ -377,7 +375,7 @@ public final class Namer { @NotNull public static JsNameRef kotlin(@NotNull JsName name) { - return fqnWithoutSideEffects(name, kotlinObject()); + return pureFqn(name, kotlinObject()); } @NotNull @@ -387,7 +385,7 @@ public final class Namer { @NotNull public static JsNameRef kotlinObject() { - return fqnWithoutSideEffects(KOTLIN_NAME, null); + return pureFqn(KOTLIN_NAME, null); } @NotNull @@ -444,14 +442,14 @@ public final class Namer { JsInvocation invocation = new JsInvocation(kotlin(functionName)); invocation.getArguments().addAll(arguments); MetadataProperties.setTypeCheck(invocation, metadata); - MetadataProperties.setSideEffects(invocation, false); + MetadataProperties.setSideEffects(invocation, SideEffectKind.PURE); return invocation; } @NotNull public JsExpression isInstanceOf(@NotNull JsExpression instance, @NotNull JsExpression type) { JsInvocation result = new JsInvocation(kotlin(isTypeName), instance, type); - MetadataProperties.setSideEffects(result, false); + MetadataProperties.setSideEffects(result, SideEffectKind.PURE); return result; } @@ -501,16 +499,16 @@ public final class Namer { @NotNull public JsExpression getModuleReference(@NotNull JsStringLiteral moduleName) { JsArrayAccess result = new JsArrayAccess(modulesMap, moduleName); - MetadataProperties.setSideEffects(result, false); + MetadataProperties.setSideEffects(result, SideEffectKind.PURE); return result; } public static JsNameRef kotlinLong() { - return fqnWithoutSideEffects("Long", kotlinObject()); + return pureFqn("Long", kotlinObject()); } @NotNull public static JsNameRef createInlineFunction() { - return fqnWithoutSideEffects(DEFINE_INLINE_FUNCTION, kotlinObject()); + return pureFqn(DEFINE_INLINE_FUNCTION, kotlinObject()); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index c1427af16fb..7e8b364d776 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -21,6 +21,7 @@ import com.google.common.collect.Maps; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata; import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind; import com.intellij.openapi.util.Factory; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; @@ -45,7 +46,7 @@ import java.util.Map; import java.util.Set; import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects; +import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn; import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.*; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName; @@ -196,7 +197,7 @@ public final class StaticContext { @NotNull public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) { JsName packageName = getNameForPackage(packageFqName); - return fqnWithoutSideEffects(packageName, packageFqName.isRoot() ? null : getQualifierForParentPackage(packageFqName.parent())); + return pureFqn(packageName, packageFqName.isRoot() ? null : getQualifierForParentPackage(packageFqName.parent())); } @NotNull @@ -225,7 +226,7 @@ public final class StaticContext { FqName fqName = packageFqName; while (true) { - JsNameRef ref = fqnWithoutSideEffects(getNameForPackage(fqName), null); + JsNameRef ref = pureFqn(getNameForPackage(fqName), null); if (qualifier == null) { result = ref; @@ -640,7 +641,7 @@ public final class StaticContext { descriptor instanceof PackageFragmentDescriptor || descriptor instanceof ClassDescriptor ) { - MetadataProperties.setSideEffects((HasMetadata) expression, false); + MetadataProperties.setSideEffects((HasMetadata) expression, SideEffectKind.PURE); } } return expression; 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 06c4322aea3..5d7f7bad47a 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 @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.js.translate.declaration import com.google.dart.compiler.backend.js.ast.* +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind +import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import com.intellij.util.SmartList import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.bridges.Bridge diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt index 40d0130f9d5..9a8af4c868e 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.js.translate.context.Namer.getReceiverParameterName import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.general.Translation -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference @@ -168,8 +168,7 @@ private class PropertyTranslator( val fakeArgumentExpression = (delegatedCall.valueArgumentsByIndex!![1] as ExpressionValueArgument).valueArgument!!.getArgumentExpression() return context.innerContextWithAliasesForExpressions(mapOf( - fakeArgumentExpression to JsNew(fqnWithoutSideEffects("PropertyMetadata", Namer.kotlinObject()), - listOf(propertyNameLiteral)) + fakeArgumentExpression to JsNew(pureFqn("PropertyMetadata", Namer.kotlinObject()), listOf(propertyNameLiteral)) )) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt index d0ad2e414d5..92882d055db 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt @@ -17,10 +17,7 @@ package org.jetbrains.kotlin.js.translate.expression import com.google.dart.compiler.backend.js.ast.* -import com.google.dart.compiler.backend.js.ast.metadata.functionDescriptor -import com.google.dart.compiler.backend.js.ast.metadata.isLocal -import com.google.dart.compiler.backend.js.ast.metadata.sideEffects -import com.google.dart.compiler.backend.js.ast.metadata.staticRef +import com.google.dart.compiler.backend.js.ast.metadata.* import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.js.inline.util.getInnerFunction import org.jetbrains.kotlin.js.translate.context.TranslationContext @@ -63,13 +60,13 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato } lambda.isLocal = true - return invokingContext.define(descriptor, lambda).apply { sideEffects = false } + return invokingContext.define(descriptor, lambda).apply { sideEffects = SideEffectKind.PURE } } } fun JsFunction.withCapturedParameters(context: TranslationContext, invokingContext: TranslationContext, descriptor: MemberDescriptor): JsExpression { - val ref = invokingContext.define(descriptor, this).apply { sideEffects = false } - val invocation = JsInvocation(ref).apply { sideEffects = false } + val ref = invokingContext.define(descriptor, this).apply { sideEffects = SideEffectKind.PURE } + val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE } val invocationArguments = invocation.arguments val functionParameters = this.parameters diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java index 41460a74ffb..159adac5f04 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java @@ -43,7 +43,7 @@ import java.util.List; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.*; import static org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.setDefaultValueForArguments; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects; +import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn; import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getPrimaryConstructorParameters; import static org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType; @@ -124,8 +124,8 @@ public final class ClassInitializerTranslator extends AbstractTranslator { initFunction.getParameters().add(0, new JsParameter(outerName)); - JsExpression paramRef = fqnWithoutSideEffects(outerName, null); - JsExpression assignment = JsAstUtils.assignment(fqnWithoutSideEffects(outerName, JsLiteral.THIS), paramRef); + JsExpression paramRef = pureFqn(outerName, null); + JsExpression assignment = JsAstUtils.assignment(pureFqn(outerName, JsLiteral.THIS), paramRef); initFunction.getBody().getStatements().add(new JsExpressionStatement(assignment)); } @@ -178,7 +178,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator { } if (superDescriptor.getContainingDeclaration().isInner() && descriptor.isInner()) { - arguments.add(fqnWithoutSideEffects(Namer.OUTER_FIELD_NAME, JsLiteral.THIS)); + arguments.add(pureFqn(Namer.OUTER_FIELD_NAME, JsLiteral.THIS)); } if (!DescriptorUtils.isAnonymousObject(descriptor)) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInFunctionIntrinsic.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInFunctionIntrinsic.java index d91851132c7..a4c16b22f66 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInFunctionIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInFunctionIntrinsic.java @@ -25,8 +25,6 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import java.util.List; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects; - public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic { @NotNull @@ -44,6 +42,6 @@ public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic { @NotNull TranslationContext context ) { assert receiver != null; - return new JsInvocation(fqnWithoutSideEffects(functionName, receiver), arguments); + return new JsInvocation(JsAstUtils.pureFqn(functionName, receiver), arguments); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInPropertyIntrinsic.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInPropertyIntrinsic.java index fbb9964f0d4..e563f7137dc 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInPropertyIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/BuiltInPropertyIntrinsic.java @@ -24,8 +24,6 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import java.util.List; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects; - //TODO: find should be usages public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic { @@ -42,6 +40,6 @@ public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic { @NotNull TranslationContext context) { assert receiver != null; assert arguments.isEmpty() : "Properties can't have arguments."; - return fqnWithoutSideEffects(propertyName, receiver); + return JsAstUtils.pureFqn(propertyName, receiver); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java index f6e3f242bcc..78920a63faa 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ArrayFIF.java @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories; import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.JsArrayAccess; import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; @@ -97,9 +96,7 @@ public final class ArrayFIF extends CompositeFIF { assert receiver != null; assert arguments.size() == 1 : "Array get expression must have one argument."; JsExpression indexExpression = arguments.get(0); - JsArrayAccess result = new JsArrayAccess(receiver, indexExpression); - MetadataProperties.setSideEffects(result, false); - return result; + return new JsArrayAccess(receiver, indexExpression); } }; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java index 96d7a54bfe3..bea5ecec1be 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java @@ -43,7 +43,7 @@ public class KotlinFunctionIntrinsic extends FunctionIntrinsic { @NotNull List arguments, @NotNull TranslationContext context ) { - JsExpression function = JsAstUtils.fqnWithoutSideEffects(functionName, Namer.kotlinObject()); + JsExpression function = JsAstUtils.pureFqn(functionName, Namer.kotlinObject()); return new JsInvocation(function, receiver == null ? arguments : TranslationUtils.generateInvocationArguments(receiver, arguments)); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java index ff9039df7a5..ceff44088de 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -211,7 +211,7 @@ public final class TopLevelFIF extends CompositeFIF { String mangledName = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getMutableMap(), operationName()); - return new JsInvocation(JsAstUtils.fqnWithoutSideEffects(mangledName, thisOrReceiver), arguments); + return new JsInvocation(JsAstUtils.pureFqn(mangledName, thisOrReceiver), arguments); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt index 9e25411061b..0c27a510aea 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.js.translate.reference import com.google.dart.compiler.backend.js.ast.* +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind +import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import com.intellij.util.SmartList import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.js.translate.context.Namer @@ -143,7 +145,7 @@ class CallArgumentTranslator private constructor( concatArguments!!.addAll(result) if (!argsBeforeVararg!!.isEmpty()) { - concatArguments.add(0, JsArrayLiteral(argsBeforeVararg)) + concatArguments.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) } result = SmartList(concatArgumentsIfNeeded(concatArguments)) @@ -212,7 +214,7 @@ class CallArgumentTranslator private constructor( context: TranslationContext, shouldWrapVarargInArray: Boolean): ArgumentsKind { if (arguments.isEmpty()) { if (shouldWrapVarargInArray) { - result.add(JsArrayLiteral(listOf())) + result.add(JsArrayLiteral(listOf()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) } return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT } @@ -289,7 +291,7 @@ class CallArgumentTranslator private constructor( if (valueArgument.getSpreadElement() != null) { if (lastArrayContent.size > 0) { - concatArguments.add(JsArrayLiteral(lastArrayContent)) + concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) concatArguments.add(expressionArgument) lastArrayContent = SmartList() } @@ -302,7 +304,7 @@ class CallArgumentTranslator private constructor( } } if (lastArrayContent.size > 0) { - concatArguments.add(JsArrayLiteral(lastArrayContent)) + concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE }) } return concatArguments diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java index d4b65b62066..e051ee624b8 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.translate.utils; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; +import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind; import com.intellij.util.SmartList; import kotlin.Pair; import org.jetbrains.annotations.NotNull; @@ -32,12 +33,12 @@ import java.util.Collections; import java.util.List; public final class JsAstUtils { - private static final JsNameRef DEFINE_PROPERTY = fqnWithoutSideEffects("defineProperty", null); - public static final JsNameRef CREATE_OBJECT = fqnWithoutSideEffects("create", null); + private static final JsNameRef DEFINE_PROPERTY = pureFqn("defineProperty", null); + public static final JsNameRef CREATE_OBJECT = pureFqn("create", null); private static final JsNameRef VALUE = new JsNameRef("value"); - private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(fqnWithoutSideEffects("writable", null), JsLiteral.TRUE); - private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(fqnWithoutSideEffects("enumerable", null), JsLiteral.TRUE); + private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(pureFqn("writable", null), JsLiteral.TRUE); + private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(pureFqn("enumerable", null), JsLiteral.TRUE); public static final String LENDS_JS_DOC_TAG = "lends"; @@ -128,7 +129,7 @@ public final class JsAstUtils { @NotNull public static JsInvocation invokeMethod(@NotNull JsExpression thisObject, @NotNull String name, @NotNull JsExpression... arguments) { - return new JsInvocation(fqnWithoutSideEffects(name, thisObject), arguments); + return new JsInvocation(pureFqn(name, thisObject), arguments); } @NotNull @@ -173,7 +174,7 @@ public final class JsAstUtils { @NotNull private static JsExpression rangeTo(@NotNull String rangeClassName, @NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) { - JsNameRef expr = fqnWithoutSideEffects(rangeClassName, Namer.kotlinObject()); + JsNameRef expr = pureFqn(rangeClassName, Namer.kotlinObject()); JsNew numberRangeConstructorInvocation = new JsNew(expr); setArguments(numberRangeConstructorInvocation, rangeStart, rangeEnd); return numberRangeConstructorInvocation; @@ -488,16 +489,16 @@ public final class JsAstUtils { } @NotNull - public static JsNameRef fqnWithoutSideEffects(@NotNull String identifier, @Nullable JsExpression qualifier) { + public static JsNameRef pureFqn(@NotNull String identifier, @Nullable JsExpression qualifier) { JsNameRef result = new JsNameRef(identifier, qualifier); - MetadataProperties.setSideEffects(result, false); + MetadataProperties.setSideEffects(result, SideEffectKind.PURE); return result; } @NotNull - public static JsNameRef fqnWithoutSideEffects(@NotNull JsName identifier, @Nullable JsExpression qualifier) { + public static JsNameRef pureFqn(@NotNull JsName identifier, @Nullable JsExpression qualifier) { JsNameRef result = new JsNameRef(identifier, qualifier); - MetadataProperties.setSideEffects(result, false); + MetadataProperties.setSideEffects(result, SideEffectKind.PURE); return result; } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java index 65d31a24cde..21d3b9aa9ac 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java @@ -148,7 +148,13 @@ public final class JsDescriptorUtils { } public static boolean sideEffectsPossible(@NotNull PropertyDescriptor property) { - return isDefaultAccessor(property.getGetter()) && !ModalityKt.isOverridableOrOverrides(property); + return !isDefaultAccessor(property.getGetter()) || ModalityKt.isOverridableOrOverrides(property) || + isStaticInitializationPossible(property); + } + + private static boolean isStaticInitializationPossible(PropertyDescriptor property) { + DeclarationDescriptor container = property.getContainingDeclaration(); + return container instanceof PackageFragmentDescriptor || DescriptorUtils.isObject(container); } public static boolean isSimpleFinalProperty(@NotNull PropertyDescriptor propertyDescriptor) { diff --git a/js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAfterModification.kt b/js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAfterModification.kt new file mode 100644 index 00000000000..34fdbda5ca8 --- /dev/null +++ b/js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAfterModification.kt @@ -0,0 +1,16 @@ +package foo + +class A { + var x = 23 +} + +inline fun bar(value: Int, a: A): Int { + a.x = 42 + return value +} + +fun box(): String { + val a = A() + assertEquals(23, bar(a.x, a)) + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAndInitializer.kt b/js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAndInitializer.kt new file mode 100644 index 00000000000..76a03b3d78e --- /dev/null +++ b/js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessAndInitializer.kt @@ -0,0 +1,21 @@ +package foo + +object A { + init { + log("A.init") + } + + val x = 23 +} + +inline fun bar(value: Int) { + log("bar->begin") + log("value=$value") + log("bar->end") +} + +fun box(): String { + bar(A.x) + assertEquals("A.init;bar->begin;value=23;bar->end;", pullLog()) + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/inlineSizeReduction/cases/propertyAssignment.kt b/js/js.translator/testData/inlineSizeReduction/cases/propertyAssignment.kt index 6483c91d639..3de81a4bd1b 100644 --- a/js/js.translator/testData/inlineSizeReduction/cases/propertyAssignment.kt +++ b/js/js.translator/testData/inlineSizeReduction/cases/propertyAssignment.kt @@ -1,7 +1,7 @@ package foo // CHECK_CONTAINS_NO_CALLS: test -// CHECK_VARS_COUNT: function=test count=1 +// CHECK_VARS_COUNT: function=test count=0 object SumHolder { var sum = 0