JS/Inlining: change sideEffects metadata to take three values: producing side effect, dependding on side effect and purity
This commit is contained in:
+7
-1
@@ -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
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
+6
-5
@@ -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 {
|
||||
|
||||
+16
-9
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<JsName>) = 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
|
||||
}
|
||||
|
||||
+12
@@ -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");
|
||||
|
||||
+2
-1
@@ -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 {
|
||||
|
||||
+5
-5
@@ -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!!))
|
||||
}
|
||||
|
||||
+3
-2
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-3
@@ -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))
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -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
|
||||
|
||||
+4
-4
@@ -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)) {
|
||||
|
||||
+1
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class KotlinFunctionIntrinsic extends FunctionIntrinsic {
|
||||
@NotNull List<JsExpression> 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));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -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<JsExpression>()))
|
||||
result.add(JsArrayLiteral(listOf<JsExpression>()).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<JsExpression>()
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+16
@@ -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"
|
||||
}
|
||||
+21
@@ -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
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_VARS_COUNT: function=test count=1
|
||||
// CHECK_VARS_COUNT: function=test count=0
|
||||
|
||||
object SumHolder {
|
||||
var sum = 0
|
||||
|
||||
Reference in New Issue
Block a user