JS/Inlining: change sideEffects metadata to take three values: producing side effect, dependding on side effect and purity

This commit is contained in:
Alexey Andreev
2016-06-02 17:41:17 +03:00
parent 774efa4e70
commit 6b99d4e1c5
26 changed files with 154 additions and 92 deletions
@@ -55,7 +55,7 @@ var JsReturn.returnTarget: FunctionDescriptor? by MetadataProperty(default = nul
var HasMetadata.synthetic: Boolean by MetadataProperty(default = false) 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 { enum class TypeCheck {
TYPEOF, TYPEOF,
@@ -64,3 +64,9 @@ enum class TypeCheck {
IS_ANY, IS_ANY,
AND_PREDICATE AND_PREDICATE
} }
enum class SideEffectKind {
AFFECTS_STATE,
DEPENDS_ON_STATE,
PURE
}
@@ -17,10 +17,7 @@
package org.jetbrains.kotlin.js.inline package org.jetbrains.kotlin.js.inline
import com.google.dart.compiler.backend.js.ast.* 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.*
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.intellij.util.SmartList import com.intellij.util.SmartList
import org.jetbrains.kotlin.js.inline.util.IdentitySet import org.jetbrains.kotlin.js.inline.util.IdentitySet
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.* 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 // 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 // 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). // 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() qualifier = qualifier.extractToTemporary()
} }
else if (callee != null && receiver != null && receiver in containsNodeWithSideEffect) { else if (callee != null && receiver != null && receiver in containsNodeWithSideEffect) {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.inline.clean package org.jetbrains.kotlin.js.inline.clean
import com.google.dart.compiler.backend.js.ast.* 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.sideEffects
import com.google.dart.compiler.backend.js.ast.metadata.synthetic import com.google.dart.compiler.backend.js.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.util.collectLocalVariables import org.jetbrains.kotlin.js.inline.util.collectLocalVariables
@@ -53,7 +54,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
if (expression.name in localVars) { if (expression.name in localVars) {
listOf() listOf()
} }
else if (!expression.sideEffects) { else if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
val qualifier = expression.qualifier val qualifier = expression.qualifier
if (qualifier != null) replace(qualifier) else listOf() if (qualifier != null) replace(qualifier) else listOf()
} }
@@ -78,7 +79,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
} }
is JsBinaryOperation -> { is JsBinaryOperation -> {
if (expression.sideEffects) { if (expression.sideEffects == SideEffectKind.AFFECTS_STATE) {
when (expression.operator) { when (expression.operator) {
JsBinaryOperator.BIT_AND, JsBinaryOperator.BIT_AND,
JsBinaryOperator.BIT_OR, JsBinaryOperator.BIT_OR,
@@ -130,7 +131,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
} }
is JsInvocation -> { is JsInvocation -> {
if (!expression.sideEffects) { if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
replace(expression.qualifier) + replaceMany(expression.arguments) replace(expression.qualifier) + replaceMany(expression.arguments)
} }
else { else {
@@ -139,7 +140,7 @@ class IneffectiveStatementElimination(private val root: JsFunction) {
} }
is JsNew -> { is JsNew -> {
if (!expression.sideEffects) { if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
replace(expression.constructorExpression) + replaceMany(expression.arguments) replace(expression.constructorExpression) + replaceMany(expression.arguments)
} }
else { 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. // 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. // It's good to eliminate such useless expression.
is JsArrayAccess -> { is JsArrayAccess -> {
if (!expression.sideEffects) { if (expression.sideEffects != SideEffectKind.AFFECTS_STATE) {
replace(expression.arrayExpression) + replace(expression.indexExpression) replace(expression.arrayExpression) + replace(expression.indexExpression)
} }
else { else {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.inline.clean package org.jetbrains.kotlin.js.inline.clean
import com.google.dart.compiler.backend.js.ast.* 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.sideEffects
import com.google.dart.compiler.backend.js.ast.metadata.synthetic import com.google.dart.compiler.backend.js.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.util.collectFreeVariables import org.jetbrains.kotlin.js.inline.util.collectFreeVariables
@@ -180,14 +181,14 @@ internal class TemporaryVariableElimination(function: JsFunction) {
} }
super.visitNameRef(nameRef) super.visitNameRef(nameRef)
if (nameRef.qualifier != null && nameRef.sideEffects) { if (nameRef.qualifier != null && nameRef.sideEffects == SideEffectKind.AFFECTS_STATE) {
sideEffectOccurred = true sideEffectOccurred = true
} }
} }
override fun visitInvocation(invocation: JsInvocation) { override fun visitInvocation(invocation: JsInvocation) {
super.visitInvocation(invocation) super.visitInvocation(invocation)
if (invocation.sideEffects) { if (invocation.sideEffects == SideEffectKind.AFFECTS_STATE) {
sideEffectOccurred = true sideEffectOccurred = true
} }
} }
@@ -242,7 +243,7 @@ internal class TemporaryVariableElimination(function: JsFunction) {
override fun visitArrayAccess(x: JsArrayAccess) { override fun visitArrayAccess(x: JsArrayAccess) {
super.visitArrayAccess(x) super.visitArrayAccess(x)
if (x.sideEffects) { if (x.sideEffects == SideEffectKind.AFFECTS_STATE) {
sideEffectOccurred = true sideEffectOccurred = true
} }
} }
@@ -533,15 +534,21 @@ internal class TemporaryVariableElimination(function: JsFunction) {
private fun isTrivial(expr: JsExpression): Boolean = when (expr) { private fun isTrivial(expr: JsExpression): Boolean = when (expr) {
is JsNameRef -> { is JsNameRef -> {
val name = expr.name val qualifier = expr.qualifier
name in namesToProcess && when (definitions[name]) { if (expr.sideEffects == SideEffectKind.PURE && (qualifier == null || isTrivial(qualifier))) {
null, 0 -> true true
1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false }
else -> false 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 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) is JsArrayAccess -> isTrivial(expr.arrayExpression) && isTrivial(expr.indexExpression)
else -> false else -> false
} }
@@ -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.*
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata 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 com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.any import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.any
@@ -28,7 +29,7 @@ fun JsExpression.canHaveOwnSideEffect(vars: Set<JsName>) = when (this) {
is JsConditional, is JsConditional,
is JsLiteral -> false is JsLiteral -> false
is JsBinaryOperation -> operator.isAssignment is JsBinaryOperation -> operator.isAssignment
is JsNameRef -> name !in vars && sideEffects is JsNameRef -> name !in vars && sideEffects != SideEffectKind.PURE
is HasMetadata -> sideEffects is HasMetadata -> sideEffects != SideEffectKind.PURE
else -> true else -> true
} }
@@ -257,6 +257,18 @@ public class InlineEvaluationOrderTestGenerated extends AbstractInlineEvaluation
doTest(fileName); 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") @TestMetadata("propertyAccessWithSideEffect.kt")
public void testPropertyAccessWithSideEffect() throws Exception { public void testPropertyAccessWithSideEffect() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessWithSideEffect.kt"); String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/inlineEvaluationOrder/cases/propertyAccessWithSideEffect.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.JsExpression
import com.google.dart.compiler.backend.js.ast.JsName 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.HasMetadata
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.sideEffects
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -76,7 +77,7 @@ fun VariableAccessInfo.constructAccessExpression(ref: JsExpression): JsExpressio
return ref return ref
} else { } else {
return if (value !is JsEmptyExpression) { return if (value !is JsEmptyExpression) {
(ref as? HasMetadata)?.let { it.sideEffects = false } (ref as? HasMetadata)?.let { it.sideEffects = SideEffectKind.PURE }
JsAstUtils.assignment(ref, value!!) JsAstUtils.assignment(ref, value!!)
} }
else { else {
@@ -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.reference.CallArgumentTranslator
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils 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.js.translate.utils.PsiUtils
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -59,7 +59,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
if (isNative && hasSpreadOperator) { if (isNative && hasSpreadOperator) {
return nativeSpreadFunWithDispatchOrExtensionReceiver(argumentsInfo, functionName) return nativeSpreadFunWithDispatchOrExtensionReceiver(argumentsInfo, functionName)
} }
return JsInvocation(fqnWithoutSideEffects(functionName, dispatchReceiver), argumentsInfo.translateArguments) return JsInvocation(pureFqn(functionName, dispatchReceiver), argumentsInfo.translateArguments)
} }
fun buildDefaultCallWithoutReceiver(context: TranslationContext, fun buildDefaultCallWithoutReceiver(context: TranslationContext,
@@ -78,7 +78,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
val functionRef = context.aliasOrValue(callableDescriptor) { val functionRef = context.aliasOrValue(callableDescriptor) {
val qualifierForFunction = context.getQualifierForDescriptor(it) val qualifierForFunction = context.getQualifierForDescriptor(it)
fqnWithoutSideEffects(functionName, qualifierForFunction) pureFqn(functionName, qualifierForFunction)
} }
return JsInvocation(functionRef, argumentsInfo.translateArguments) return JsInvocation(functionRef, argumentsInfo.translateArguments)
} }
@@ -101,7 +101,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
val functionRef = context.aliasOrValue(callableDescriptor) { val functionRef = context.aliasOrValue(callableDescriptor) {
val qualifierForFunction = context.getQualifierForDescriptor(it) val qualifierForFunction = context.getQualifierForDescriptor(it)
fqnWithoutSideEffects(functionName, qualifierForFunction) // TODO: remake to call pureFqn(functionName, qualifierForFunction) // TODO: remake to call
} }
val referenceToCall = val referenceToCall =
@@ -238,7 +238,7 @@ object SuperCallCase : FunctionCallCase() {
override fun FunctionCallInfo.dispatchReceiver(): JsExpression { override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
// TODO: spread operator // TODO: spread operator
val prototypeClass = fqnWithoutSideEffects(Namer.getPrototypeName(), calleeOwner) val prototypeClass = pureFqn(Namer.getPrototypeName(), calleeOwner)
val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass)) val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass))
return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(dispatchReceiver!!)) return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(dispatchReceiver!!))
} }
@@ -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.JsExpression
import com.google.dart.compiler.backend.js.ast.JsInvocation 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.JsNameRef
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.sideEffects
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -74,8 +75,8 @@ object DefaultVariableAccessCase : VariableAccessCase() {
override fun VariableAccessInfo.dispatchReceiver(): JsExpression { override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
val accessor = JsNameRef(variableName, dispatchReceiver!!) val accessor = JsNameRef(variableName, dispatchReceiver!!)
val descriptor = callableDescriptor val descriptor = callableDescriptor
if (descriptor is PropertyDescriptor && JsDescriptorUtils.sideEffectsPossible(descriptor)) { if (descriptor is PropertyDescriptor && !JsDescriptorUtils.sideEffectsPossible(descriptor)) {
accessor.sideEffects = false accessor.sideEffects = SideEffectKind.DEPENDS_ON_STATE
} }
return constructAccessExpression(accessor) return constructAccessExpression(accessor)
} }
@@ -17,13 +17,12 @@
package org.jetbrains.kotlin.js.translate.context; package org.jetbrains.kotlin.js.translate.context;
import com.google.dart.compiler.backend.js.ast.*; 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.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind;
import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck; import com.google.dart.compiler.backend.js.ast.metadata.TypeCheck;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
@@ -38,7 +37,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope; 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.JsDescriptorUtils.getModuleName;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
@@ -143,7 +142,7 @@ public final class Namer {
@NotNull @NotNull
public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) { public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) {
return fqnWithoutSideEffects(SUPER_METHOD_NAME, superClassJsName.makeRef()); return pureFqn(SUPER_METHOD_NAME, superClassJsName.makeRef());
} }
@NotNull @NotNull
@@ -182,7 +181,7 @@ public final class Namer {
@NotNull @NotNull
public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) { public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) {
return fqnWithoutSideEffects(getPrototypeName(), classOrTraitExpression); return pureFqn(getPrototypeName(), classOrTraitExpression);
} }
@NotNull @NotNull
@@ -207,12 +206,12 @@ public final class Namer {
@NotNull @NotNull
public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) { public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) {
return fqnWithoutSideEffects(CALL_FUNCTION, functionExpression); return pureFqn(CALL_FUNCTION, functionExpression);
} }
@NotNull @NotNull
public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) { public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) {
return fqnWithoutSideEffects(APPLY_FUNCTION, functionExpression); return pureFqn(APPLY_FUNCTION, functionExpression);
} }
@NotNull @NotNull
@@ -222,7 +221,7 @@ public final class Namer {
@NotNull @NotNull
public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) { public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) {
return fqnWithoutSideEffects(CAPTURED_VAR_FIELD, ref); return pureFqn(CAPTURED_VAR_FIELD, ref);
} }
@NotNull @NotNull
@@ -297,7 +296,6 @@ public final class Namer {
isTypeName = kotlinScope.declareName("isType"); isTypeName = kotlinScope.declareName("isType");
modulesMap = kotlin("modules"); modulesMap = kotlin("modules");
MetadataProperties.setSideEffects((HasMetadata) modulesMap, false);
} }
@NotNull @NotNull
@@ -377,7 +375,7 @@ public final class Namer {
@NotNull @NotNull
public static JsNameRef kotlin(@NotNull JsName name) { public static JsNameRef kotlin(@NotNull JsName name) {
return fqnWithoutSideEffects(name, kotlinObject()); return pureFqn(name, kotlinObject());
} }
@NotNull @NotNull
@@ -387,7 +385,7 @@ public final class Namer {
@NotNull @NotNull
public static JsNameRef kotlinObject() { public static JsNameRef kotlinObject() {
return fqnWithoutSideEffects(KOTLIN_NAME, null); return pureFqn(KOTLIN_NAME, null);
} }
@NotNull @NotNull
@@ -444,14 +442,14 @@ public final class Namer {
JsInvocation invocation = new JsInvocation(kotlin(functionName)); JsInvocation invocation = new JsInvocation(kotlin(functionName));
invocation.getArguments().addAll(arguments); invocation.getArguments().addAll(arguments);
MetadataProperties.setTypeCheck(invocation, metadata); MetadataProperties.setTypeCheck(invocation, metadata);
MetadataProperties.setSideEffects(invocation, false); MetadataProperties.setSideEffects(invocation, SideEffectKind.PURE);
return invocation; return invocation;
} }
@NotNull @NotNull
public JsExpression isInstanceOf(@NotNull JsExpression instance, @NotNull JsExpression type) { public JsExpression isInstanceOf(@NotNull JsExpression instance, @NotNull JsExpression type) {
JsInvocation result = new JsInvocation(kotlin(isTypeName), instance, type); JsInvocation result = new JsInvocation(kotlin(isTypeName), instance, type);
MetadataProperties.setSideEffects(result, false); MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result; return result;
} }
@@ -501,16 +499,16 @@ public final class Namer {
@NotNull @NotNull
public JsExpression getModuleReference(@NotNull JsStringLiteral moduleName) { public JsExpression getModuleReference(@NotNull JsStringLiteral moduleName) {
JsArrayAccess result = new JsArrayAccess(modulesMap, moduleName); JsArrayAccess result = new JsArrayAccess(modulesMap, moduleName);
MetadataProperties.setSideEffects(result, false); MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result; return result;
} }
public static JsNameRef kotlinLong() { public static JsNameRef kotlinLong() {
return fqnWithoutSideEffects("Long", kotlinObject()); return pureFqn("Long", kotlinObject());
} }
@NotNull @NotNull
public static JsNameRef createInlineFunction() { public static JsNameRef createInlineFunction() {
return fqnWithoutSideEffects(DEFINE_INLINE_FUNCTION, kotlinObject()); return pureFqn(DEFINE_INLINE_FUNCTION, kotlinObject());
} }
} }
@@ -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.*;
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata; 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.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind;
import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Factory;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashMap;
@@ -45,7 +46,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*; 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.JsDescriptorUtils.*;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
@@ -196,7 +197,7 @@ public final class StaticContext {
@NotNull @NotNull
public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) { public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) {
JsName packageName = getNameForPackage(packageFqName); JsName packageName = getNameForPackage(packageFqName);
return fqnWithoutSideEffects(packageName, packageFqName.isRoot() ? null : getQualifierForParentPackage(packageFqName.parent())); return pureFqn(packageName, packageFqName.isRoot() ? null : getQualifierForParentPackage(packageFqName.parent()));
} }
@NotNull @NotNull
@@ -225,7 +226,7 @@ public final class StaticContext {
FqName fqName = packageFqName; FqName fqName = packageFqName;
while (true) { while (true) {
JsNameRef ref = fqnWithoutSideEffects(getNameForPackage(fqName), null); JsNameRef ref = pureFqn(getNameForPackage(fqName), null);
if (qualifier == null) { if (qualifier == null) {
result = ref; result = ref;
@@ -640,7 +641,7 @@ public final class StaticContext {
descriptor instanceof PackageFragmentDescriptor || descriptor instanceof PackageFragmentDescriptor ||
descriptor instanceof ClassDescriptor descriptor instanceof ClassDescriptor
) { ) {
MetadataProperties.setSideEffects((HasMetadata) expression, false); MetadataProperties.setSideEffects((HasMetadata) expression, SideEffectKind.PURE);
} }
} }
return expression; return expression;
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.js.translate.declaration package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.* 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 com.intellij.util.SmartList
import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.bridges.Bridge import org.jetbrains.kotlin.backend.common.bridges.Bridge
@@ -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.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.general.Translation 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.JsDescriptorUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference
@@ -168,8 +168,7 @@ private class PropertyTranslator(
val fakeArgumentExpression = val fakeArgumentExpression =
(delegatedCall.valueArgumentsByIndex!![1] as ExpressionValueArgument).valueArgument!!.getArgumentExpression() (delegatedCall.valueArgumentsByIndex!![1] as ExpressionValueArgument).valueArgument!!.getArgumentExpression()
return context.innerContextWithAliasesForExpressions(mapOf( return context.innerContextWithAliasesForExpressions(mapOf(
fakeArgumentExpression to JsNew(fqnWithoutSideEffects("PropertyMetadata", Namer.kotlinObject()), fakeArgumentExpression to JsNew(pureFqn("PropertyMetadata", Namer.kotlinObject()), listOf(propertyNameLiteral))
listOf(propertyNameLiteral))
)) ))
} }
@@ -17,10 +17,7 @@
package org.jetbrains.kotlin.js.translate.expression package org.jetbrains.kotlin.js.translate.expression
import com.google.dart.compiler.backend.js.ast.* 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.*
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 org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.inline.util.getInnerFunction import org.jetbrains.kotlin.js.inline.util.getInnerFunction
import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.TranslationContext
@@ -63,13 +60,13 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
} }
lambda.isLocal = true 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 { fun JsFunction.withCapturedParameters(context: TranslationContext, invokingContext: TranslationContext, descriptor: MemberDescriptor): JsExpression {
val ref = invokingContext.define(descriptor, this).apply { sideEffects = false } val ref = invokingContext.define(descriptor, this).apply { sideEffects = SideEffectKind.PURE }
val invocation = JsInvocation(ref).apply { sideEffects = false } val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
val invocationArguments = invocation.arguments val invocationArguments = invocation.arguments
val functionParameters = this.parameters val functionParameters = this.parameters
@@ -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.BindingUtils.*;
import static org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.setDefaultValueForArguments; 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.js.translate.utils.PsiUtils.getPrimaryConstructorParameters;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType; 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)); initFunction.getParameters().add(0, new JsParameter(outerName));
JsExpression paramRef = fqnWithoutSideEffects(outerName, null); JsExpression paramRef = pureFqn(outerName, null);
JsExpression assignment = JsAstUtils.assignment(fqnWithoutSideEffects(outerName, JsLiteral.THIS), paramRef); JsExpression assignment = JsAstUtils.assignment(pureFqn(outerName, JsLiteral.THIS), paramRef);
initFunction.getBody().getStatements().add(new JsExpressionStatement(assignment)); initFunction.getBody().getStatements().add(new JsExpressionStatement(assignment));
} }
@@ -178,7 +178,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
} }
if (superDescriptor.getContainingDeclaration().isInner() && descriptor.isInner()) { 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)) { if (!DescriptorUtils.isAnonymousObject(descriptor)) {
@@ -25,8 +25,6 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects;
public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic { public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic {
@NotNull @NotNull
@@ -44,6 +42,6 @@ public final class BuiltInFunctionIntrinsic extends FunctionIntrinsic {
@NotNull TranslationContext context @NotNull TranslationContext context
) { ) {
assert receiver != null; assert receiver != null;
return new JsInvocation(fqnWithoutSideEffects(functionName, receiver), arguments); return new JsInvocation(JsAstUtils.pureFqn(functionName, receiver), arguments);
} }
} }
@@ -24,8 +24,6 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects;
//TODO: find should be usages //TODO: find should be usages
public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic { public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic {
@@ -42,6 +40,6 @@ public final class BuiltInPropertyIntrinsic extends FunctionIntrinsic {
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
assert receiver != null; assert receiver != null;
assert arguments.isEmpty() : "Properties can't have arguments."; assert arguments.isEmpty() : "Properties can't have arguments.";
return fqnWithoutSideEffects(propertyName, receiver); return JsAstUtils.pureFqn(propertyName, receiver);
} }
} }
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.dart.compiler.backend.js.ast.JsArrayAccess; 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.JsExpression;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -97,9 +96,7 @@ public final class ArrayFIF extends CompositeFIF {
assert receiver != null; assert receiver != null;
assert arguments.size() == 1 : "Array get expression must have one argument."; assert arguments.size() == 1 : "Array get expression must have one argument.";
JsExpression indexExpression = arguments.get(0); JsExpression indexExpression = arguments.get(0);
JsArrayAccess result = new JsArrayAccess(receiver, indexExpression); return new JsArrayAccess(receiver, indexExpression);
MetadataProperties.setSideEffects(result, false);
return result;
} }
}; };
@@ -43,7 +43,7 @@ public class KotlinFunctionIntrinsic extends FunctionIntrinsic {
@NotNull List<JsExpression> arguments, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context @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)); return new JsInvocation(function, receiver == null ? arguments : TranslationUtils.generateInvocationArguments(receiver, arguments));
} }
} }
@@ -211,7 +211,7 @@ public final class TopLevelFIF extends CompositeFIF {
String mangledName = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getMutableMap(), operationName()); String mangledName = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getMutableMap(), operationName());
return new JsInvocation(JsAstUtils.fqnWithoutSideEffects(mangledName, thisOrReceiver), arguments); return new JsInvocation(JsAstUtils.pureFqn(mangledName, thisOrReceiver), arguments);
} }
} }
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.js.translate.reference package org.jetbrains.kotlin.js.translate.reference
import com.google.dart.compiler.backend.js.ast.* 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 com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.Namer
@@ -143,7 +145,7 @@ class CallArgumentTranslator private constructor(
concatArguments!!.addAll(result) concatArguments!!.addAll(result)
if (!argsBeforeVararg!!.isEmpty()) { if (!argsBeforeVararg!!.isEmpty()) {
concatArguments.add(0, JsArrayLiteral(argsBeforeVararg)) concatArguments.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
} }
result = SmartList(concatArgumentsIfNeeded(concatArguments)) result = SmartList(concatArgumentsIfNeeded(concatArguments))
@@ -212,7 +214,7 @@ class CallArgumentTranslator private constructor(
context: TranslationContext, shouldWrapVarargInArray: Boolean): ArgumentsKind { context: TranslationContext, shouldWrapVarargInArray: Boolean): ArgumentsKind {
if (arguments.isEmpty()) { if (arguments.isEmpty()) {
if (shouldWrapVarargInArray) { if (shouldWrapVarargInArray) {
result.add(JsArrayLiteral(listOf<JsExpression>())) result.add(JsArrayLiteral(listOf<JsExpression>()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
} }
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
} }
@@ -289,7 +291,7 @@ class CallArgumentTranslator private constructor(
if (valueArgument.getSpreadElement() != null) { if (valueArgument.getSpreadElement() != null) {
if (lastArrayContent.size > 0) { if (lastArrayContent.size > 0) {
concatArguments.add(JsArrayLiteral(lastArrayContent)) concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
concatArguments.add(expressionArgument) concatArguments.add(expressionArgument)
lastArrayContent = SmartList<JsExpression>() lastArrayContent = SmartList<JsExpression>()
} }
@@ -302,7 +304,7 @@ class CallArgumentTranslator private constructor(
} }
} }
if (lastArrayContent.size > 0) { if (lastArrayContent.size > 0) {
concatArguments.add(JsArrayLiteral(lastArrayContent)) concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
} }
return concatArguments return concatArguments
@@ -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.*;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; 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 com.intellij.util.SmartList;
import kotlin.Pair; import kotlin.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -32,12 +33,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public final class JsAstUtils { public final class JsAstUtils {
private static final JsNameRef DEFINE_PROPERTY = fqnWithoutSideEffects("defineProperty", null); private static final JsNameRef DEFINE_PROPERTY = pureFqn("defineProperty", null);
public static final JsNameRef CREATE_OBJECT = fqnWithoutSideEffects("create", null); public static final JsNameRef CREATE_OBJECT = pureFqn("create", null);
private static final JsNameRef VALUE = new JsNameRef("value"); private static final JsNameRef VALUE = new JsNameRef("value");
private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(fqnWithoutSideEffects("writable", null), JsLiteral.TRUE); private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(pureFqn("writable", null), JsLiteral.TRUE);
private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(fqnWithoutSideEffects("enumerable", null), JsLiteral.TRUE); private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(pureFqn("enumerable", null), JsLiteral.TRUE);
public static final String LENDS_JS_DOC_TAG = "lends"; public static final String LENDS_JS_DOC_TAG = "lends";
@@ -128,7 +129,7 @@ public final class JsAstUtils {
@NotNull @NotNull
public static JsInvocation invokeMethod(@NotNull JsExpression thisObject, @NotNull String name, @NotNull JsExpression... arguments) { 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 @NotNull
@@ -173,7 +174,7 @@ public final class JsAstUtils {
@NotNull @NotNull
private static JsExpression rangeTo(@NotNull String rangeClassName, @NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) { 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); JsNew numberRangeConstructorInvocation = new JsNew(expr);
setArguments(numberRangeConstructorInvocation, rangeStart, rangeEnd); setArguments(numberRangeConstructorInvocation, rangeStart, rangeEnd);
return numberRangeConstructorInvocation; return numberRangeConstructorInvocation;
@@ -488,16 +489,16 @@ public final class JsAstUtils {
} }
@NotNull @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); JsNameRef result = new JsNameRef(identifier, qualifier);
MetadataProperties.setSideEffects(result, false); MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result; return result;
} }
@NotNull @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); JsNameRef result = new JsNameRef(identifier, qualifier);
MetadataProperties.setSideEffects(result, false); MetadataProperties.setSideEffects(result, SideEffectKind.PURE);
return result; return result;
} }
@@ -148,7 +148,13 @@ public final class JsDescriptorUtils {
} }
public static boolean sideEffectsPossible(@NotNull PropertyDescriptor property) { 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) { public static boolean isSimpleFinalProperty(@NotNull PropertyDescriptor propertyDescriptor) {
@@ -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"
}
@@ -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"
}
@@ -1,7 +1,7 @@
package foo package foo
// CHECK_CONTAINS_NO_CALLS: test // CHECK_CONTAINS_NO_CALLS: test
// CHECK_VARS_COUNT: function=test count=1 // CHECK_VARS_COUNT: function=test count=0
object SumHolder { object SumHolder {
var sum = 0 var sum = 0