diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java index 47e4a7eca1e..26425a96623 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java @@ -198,10 +198,14 @@ public class BindingContextUtils { return expression instanceof KtReferenceExpression; } - public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) { + public static boolean isCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) { if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false; VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; - return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar(); + return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null; + } + + public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) { + return isCapturedInClosure(bindingContext, descriptor) && ((VariableDescriptor) descriptor).isVar(); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueKindUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueKindUtils.kt index e55a6d3adab..bafb502e184 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueKindUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueKindUtils.kt @@ -86,7 +86,7 @@ internal fun VariableDescriptor.variableKind( } -private fun hasNoWritersInClosures( +fun hasNoWritersInClosures( variableContainingDeclaration: DeclarationDescriptor, writers: Set, bindingContext: BindingContext 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 ed89ce13db0..f4aa9f0ae37 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 @@ -16,23 +16,22 @@ package org.jetbrains.kotlin.js.translate.callTranslator -import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind -import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.js.backend.ast.* +import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind +import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor import org.jetbrains.kotlin.js.translate.declaration.contextWithPropertyMetadataCreationIntrinsified import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.reference.buildReifiedTypeArgs +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils 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 import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import java.util.* @@ -87,7 +86,7 @@ object DefaultVariableAccessCase : VariableAccessCase() { } val functionRef = ReferenceTranslator.translateAsValueReference(callableDescriptor, context) - val ref = if (isVarCapturedInClosure(context.bindingContext(), callableDescriptor)) { + val ref = if (context.isBoxedLocalCapturedInClosure(callableDescriptor)) { getCapturedVarAccessor(functionRef) } else { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 5eb83d4b406..54a55319ab6 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor; import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; @@ -41,6 +42,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.kotlin.serialization.js.ModuleKind; +import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor; import java.util.*; @@ -50,6 +52,8 @@ import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameFo import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn; +import static org.jetbrains.kotlin.resolve.BindingContextUtils.isCapturedInClosure; +import static org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueKindUtilsKt.hasNoWritersInClosures; /** * All the info about the state of the translation process. @@ -793,6 +797,25 @@ public class TranslationContext { return staticContext.getDeferredCallSites().containsKey(classDescriptor); } + private boolean isValWithWriterInDifferentScope(VariableDescriptor descriptor) { + //TODO: Simplify this code once KT-17694 is fixed + if (!(descriptor instanceof LocalVariableDescriptor)) { + return false; + } + PreliminaryDeclarationVisitor preliminaryVisitor = + PreliminaryDeclarationVisitor.Companion.getVisitorByVariable(descriptor, bindingContext()); + return (preliminaryVisitor == null || + !hasNoWritersInClosures(descriptor.getContainingDeclaration(), preliminaryVisitor.writers(descriptor), bindingContext())); + } + + public boolean isBoxedLocalCapturedInClosure(CallableDescriptor descriptor) { + if (isCapturedInClosure(bindingContext(), descriptor)) { + VariableDescriptor localVariable = (VariableDescriptor) descriptor; + return localVariable.isVar() || isValWithWriterInDifferentScope(localVariable); + } + return false; + } + public void deferConstructorCall(@NotNull ClassConstructorDescriptor constructor, @NotNull List invocationArgs) { ClassDescriptor classDescriptor = constructor.getContainingDeclaration(); List callSites = staticContext.getDeferredCallSites().get(classDescriptor); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index 74bc5e8116a..46c91680079 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -74,7 +74,6 @@ import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*; import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration; import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateInitializerForProperty; import static org.jetbrains.kotlin.resolve.BindingContext.*; -import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure; import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt.getResolvedCallWithAssert; import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getAnnotationClass; import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression; @@ -244,7 +243,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { initializer = PropertyTranslatorKt.translateDelegateOrInitializerExpression(context, expression); assert initializer != null : "Initializer must be non-null for property with delegate"; } - else if (isVarCapturedInClosure(context.bindingContext(), descriptor)) { + else if (context.isBoxedLocalCapturedInClosure(descriptor)) { JsNameRef alias = getCapturedVarAccessor(name.makeRef()); initializer = JsAstUtils.wrapValue(alias, initializer == null ? new JsNullLiteral() : initializer); }