diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index b26bfb6dfa1..9e537da079a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -97,8 +97,7 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*; import static org.jetbrains.kotlin.resolve.BindingContext.*; -import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall; -import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure; +import static org.jetbrains.kotlin.resolve.BindingContextUtils.*; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression; @@ -3030,7 +3029,7 @@ public class ExpressionCodegen extends KtVisitor impleme public int indexOfLocalNotDelegated(KtReferenceExpression lhs) { DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, lhs); - if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) { + if (isBoxedLocalCapturedInClosure(bindingContext, declarationDescriptor)) { return -1; } if (declarationDescriptor instanceof LocalVariableDescriptor && ((LocalVariableDescriptor) declarationDescriptor).isDelegated()) { @@ -4192,6 +4191,9 @@ public class ExpressionCodegen extends KtVisitor impleme private void initializeLocalVariableWithFakeDefaultValue(@NotNull KtProperty variableDeclaration) { LocalVariableDescriptor variableDescriptor = (LocalVariableDescriptor) getVariableDescriptorNotNull(variableDeclaration); + // For this kind of variables we generate boxes, i.e. we regard them as + if (isCapturedInClosureWithExactlyOnceEffect(bindingContext, variableDescriptor)) return; + assert !variableDeclaration.isVar() && !variableDeclaration.hasDelegateExpressionOrInitializer() && !variableDescriptor.isLateInit() : variableDeclaration.getText() + " in not variable declaration without initializer"; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index c664baa2390..f5b89d8368e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -73,7 +73,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall; -import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure; +import static org.jetbrains.kotlin.resolve.BindingContextUtils.isBoxedLocalCapturedInClosure; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.DEFAULT_CONSTRUCTOR_MARKER; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; @@ -1869,7 +1869,7 @@ public class KotlinTypeMapper { return null; } - if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) { + if (descriptor instanceof VariableDescriptor && isBoxedLocalCapturedInClosure(bindingContext, descriptor)) { return StackValue.sharedTypeForType(mapType(((VariableDescriptor) descriptor).getType())); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java index 26425a96623..9da2d1f8239 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.resolve; @@ -33,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.TowerLevelsKt; import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeUtils; +import org.jetbrains.kotlin.types.expressions.CaptureKind; import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo; import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt; import org.jetbrains.kotlin.util.slicedMap.MutableSlicedMap; @@ -204,8 +194,15 @@ public class BindingContextUtils { return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null; } - public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) { - return isCapturedInClosure(bindingContext, descriptor) && ((VariableDescriptor) descriptor).isVar(); + public static boolean isCapturedInClosureWithExactlyOnceEffect(BindingContext bindingContext, DeclarationDescriptor descriptor) { + if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false; + VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; + return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) == CaptureKind.EXACTLY_ONCE_EFFECT; + } + + public static boolean isBoxedLocalCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) { + return (isCapturedInClosure(bindingContext, descriptor) && ((VariableDescriptor) descriptor).isVar()) || + isCapturedInClosureWithExactlyOnceEffect(bindingContext, descriptor); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt index 5c00570c924..84feb924b24 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CapturingInClosureChecker.kt @@ -1,28 +1,24 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.contracts.description.CallsEffectDeclaration +import org.jetbrains.kotlin.contracts.description.ContractProviderKey +import org.jetbrains.kotlin.contracts.description.InvocationKind import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression +import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.inline.InlineUtil @@ -43,8 +39,7 @@ class CapturingInClosureChecker : CallChecker { val scopeContainer = scope.ownerDescriptor if (isCapturedVariable(variableParent, scopeContainer)) { if (trace.get(CAPTURED_IN_CLOSURE, variable) != CaptureKind.NOT_INLINE) { - val inline = isCapturedInInline(trace.bindingContext, scopeContainer, variableParent) - trace.record(CAPTURED_IN_CLOSURE, variable, if (inline) CaptureKind.INLINE_ONLY else CaptureKind.NOT_INLINE) + trace.record(CAPTURED_IN_CLOSURE, variable, getCaptureKind(trace.bindingContext, scopeContainer, variableParent)) } } } @@ -61,17 +56,34 @@ class CapturingInClosureChecker : CallChecker { return true } - private fun isCapturedInInline( + private fun getCaptureKind( context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor - ): Boolean { + ): CaptureKind { val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer) - if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false + if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return CaptureKind.NOT_INLINE - if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) { + val exactlyOnceContract = isExactlyOnceContract(context, scopeDeclaration as KtFunction) + if (InlineUtil.isInlinedArgument(scopeDeclaration, context, exactlyOnceContract)) { val scopeContainerParent = scopeContainer.containingDeclaration ?: error("parent is null for $scopeContainer") - return !isCapturedVariable(variableParent, scopeContainerParent) || - isCapturedInInline(context, scopeContainerParent, variableParent) + return if ( + !isCapturedVariable(variableParent, scopeContainerParent) || + getCaptureKind(context, scopeContainerParent, variableParent) == CaptureKind.INLINE_ONLY + ) CaptureKind.INLINE_ONLY else CaptureKind.NOT_INLINE } - return false + if (exactlyOnceContract) return CaptureKind.EXACTLY_ONCE_EFFECT + return CaptureKind.NOT_INLINE + } + + private fun isExactlyOnceContract(bindingContext: BindingContext, argument: KtFunction): Boolean { + val call = KtPsiUtil.getParentCallIfPresent(argument) ?: return false + val resolvedCall = call.getResolvedCall(bindingContext) ?: return false + val descriptor = resolvedCall.getResultingDescriptor() + val valueArgument = resolvedCall.call.getValueArgumentForExpression(argument) ?: return false + val mapping = resolvedCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return false + val parameter = mapping.valueParameter + val contractDescription = descriptor.getUserData(ContractProviderKey)?.getContractDescription() ?: return false + val effect = contractDescription.effects.filterIsInstance() + .find { it.variableReference.descriptor == parameter } ?: return false + return effect.kind == InvocationKind.EXACTLY_ONCE } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/CaptureKind.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/CaptureKind.java index 2fe819cdf01..ebf51a06e22 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/CaptureKind.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/CaptureKind.java @@ -1,22 +1,12 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.types.expressions; public enum CaptureKind { NOT_INLINE, - INLINE_ONLY + INLINE_ONLY, + EXACTLY_ONCE_EFFECT } diff --git a/compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt b/compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt new file mode 100644 index 00000000000..2113228b7b5 --- /dev/null +++ b/compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt @@ -0,0 +1,21 @@ +// !LANGUAGE: +AllowContractsForCustomFunctions +UseCallsInPlaceEffect +ReadDeserializedContracts +// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts +// IGNORE_BACKEND: JVM_IR, NATIVE, JS_IR + +import kotlin.contracts.* + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +public fun myrun(block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() +} + +fun box(): String { + val x: Long + myrun { + x = 1L + } + return if (x != 1L) "FAIL" else "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt b/compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt new file mode 100644 index 00000000000..533c379aa02 --- /dev/null +++ b/compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt @@ -0,0 +1,27 @@ +// !LANGUAGE: +AllowContractsForCustomFunctions +UseCallsInPlaceEffect +ReadDeserializedContracts +// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts +// IGNORE_BACKEND: JVM_IR, NATIVE, JS_IR +// FILE: 1.kt +package test + +import kotlin.contracts.* + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +public inline fun myrun(crossinline block: () -> Unit): Unit { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + val l = { block() } + l() +} + +// FILE: 2.kt +import test.* + +fun box(): String { + val x: Long + myrun { + x = 42L + } + return if (x != 42L) "FAIL" else "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt b/compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt new file mode 100644 index 00000000000..8489cd65f69 --- /dev/null +++ b/compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt @@ -0,0 +1,27 @@ +// !LANGUAGE: +AllowContractsForCustomFunctions +UseCallsInPlaceEffect +ReadDeserializedContracts +// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts +// IGNORE_BACKEND: JVM_IR, NATIVE, JS_IR +// NO_CHECK_LAMBDA_INLINING +// FILE: 1.kt +package test + +import kotlin.contracts.* + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +public inline fun myrun(noinline block: () -> Unit): Unit { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() +} + +// FILE: 2.kt +import test.* + +fun box(): String { + val x: Long + myrun { + x = 42L + } + return if (x != 42L) "FAIL" else "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/localInitializationLVT/contract.kt b/compiler/testData/codegen/bytecodeText/localInitializationLVT/contract.kt index f95119d5168..29e3d3f3e4b 100644 --- a/compiler/testData/codegen/bytecodeText/localInitializationLVT/contract.kt +++ b/compiler/testData/codegen/bytecodeText/localInitializationLVT/contract.kt @@ -21,5 +21,5 @@ fun doIt(block: () -> Unit) { block() } -// 2 FCONST 0 -// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref$CharRef; L1 L10 0 \ No newline at end of file +// 0 ISTORE 0 +// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef; L1 L3 0 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 52860956ffc..2cab9d5497d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4473,6 +4473,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/contracts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Contracts extends AbstractBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInContracts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/contracts"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("exactlyOnceNotInline.kt") + public void testExactlyOnceNotInline() throws Exception { + runTest("compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/controlStructures") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 2e8ecccd8bb..860cb2ed233 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -1024,6 +1024,16 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTest("compiler/testData/codegen/boxInline/contracts/definiteValInitialization.kt"); } + @TestMetadata("exactlyOnceCrossinline.kt") + public void testExactlyOnceCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt"); + } + + @TestMetadata("exactlyOnceNoinline.kt") + public void testExactlyOnceNoinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt"); + } + @TestMetadata("nonLocalReturn.kt") public void testNonLocalReturn() throws Exception { runTest("compiler/testData/codegen/boxInline/contracts/nonLocalReturn.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 2a2f3182389..d05222ddade 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1024,6 +1024,16 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTest("compiler/testData/codegen/boxInline/contracts/definiteValInitialization.kt"); } + @TestMetadata("exactlyOnceCrossinline.kt") + public void testExactlyOnceCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt"); + } + + @TestMetadata("exactlyOnceNoinline.kt") + public void testExactlyOnceNoinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt"); + } + @TestMetadata("nonLocalReturn.kt") public void testNonLocalReturn() throws Exception { runTest("compiler/testData/codegen/boxInline/contracts/nonLocalReturn.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 358c1464229..bd4fe484311 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -4473,6 +4473,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/contracts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Contracts extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInContracts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/contracts"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("exactlyOnceNotInline.kt") + public void testExactlyOnceNotInline() throws Exception { + runTest("compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/controlStructures") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 749234abd1e..7048eabee10 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -4473,6 +4473,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @TestMetadata("compiler/testData/codegen/box/contracts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Contracts extends AbstractIrBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInContracts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/contracts"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); + } + + @TestMetadata("exactlyOnceNotInline.kt") + public void testExactlyOnceNotInline() throws Exception { + runTest("compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/controlStructures") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 2363ae1ee46..08aa3f25097 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -1024,6 +1024,16 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTest("compiler/testData/codegen/boxInline/contracts/definiteValInitialization.kt"); } + @TestMetadata("exactlyOnceCrossinline.kt") + public void testExactlyOnceCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt"); + } + + @TestMetadata("exactlyOnceNoinline.kt") + public void testExactlyOnceNoinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt"); + } + @TestMetadata("nonLocalReturn.kt") public void testNonLocalReturn() throws Exception { runTest("compiler/testData/codegen/boxInline/contracts/nonLocalReturn.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index 531eb8c5eae..82916139ad6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -3663,6 +3663,24 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/contracts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Contracts extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInContracts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/contracts"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); + } + + @TestMetadata("exactlyOnceNotInline.kt") + public void testExactlyOnceNotInline() throws Exception { + runTest("compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/controlStructures") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsInlineContractsTestsGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsInlineContractsTestsGenerated.java index fe6f93a99f4..08b0f905b9e 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsInlineContractsTestsGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsInlineContractsTestsGenerated.java @@ -64,6 +64,16 @@ public class IrJsInlineContractsTestsGenerated extends AbstractIrJsInlineContrac runTest("compiler/testData/codegen/boxInline/contracts/definiteValInitialization.kt"); } + @TestMetadata("exactlyOnceCrossinline.kt") + public void testExactlyOnceCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt"); + } + + @TestMetadata("exactlyOnceNoinline.kt") + public void testExactlyOnceNoinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt"); + } + @TestMetadata("nonLocalReturn.kt") public void testNonLocalReturn() throws Exception { runTest("compiler/testData/codegen/boxInline/contracts/nonLocalReturn.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index c73788fd2ca..b96e6f291b9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -3673,6 +3673,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/contracts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Contracts extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInContracts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/contracts"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("exactlyOnceNotInline.kt") + public void testExactlyOnceNotInline() throws Exception { + runTest("compiler/testData/codegen/box/contracts/exactlyOnceNotInline.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/controlStructures") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsInlineContractsTestsGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsInlineContractsTestsGenerated.java index 3a16587e562..ebbfaeab013 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsInlineContractsTestsGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsInlineContractsTestsGenerated.java @@ -64,6 +64,16 @@ public class JsInlineContractsTestsGenerated extends AbstractJsInlineContractsTe runTest("compiler/testData/codegen/boxInline/contracts/definiteValInitialization.kt"); } + @TestMetadata("exactlyOnceCrossinline.kt") + public void testExactlyOnceCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceCrossinline.kt"); + } + + @TestMetadata("exactlyOnceNoinline.kt") + public void testExactlyOnceNoinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/contracts/exactlyOnceNoinline.kt"); + } + @TestMetadata("nonLocalReturn.kt") public void testNonLocalReturn() throws Exception { runTest("compiler/testData/codegen/boxInline/contracts/nonLocalReturn.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java index 1c5b8516369..796fe587330 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/DestructuringDeclarationTranslator.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.js.translate.expression; @@ -40,7 +29,7 @@ import java.util.List; import static org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor; import static org.jetbrains.kotlin.js.translate.utils.InlineUtils.setInlineCallMetadata; -import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure; +import static org.jetbrains.kotlin.resolve.BindingContextUtils.isBoxedLocalCapturedInClosure; public class DestructuringDeclarationTranslator extends AbstractTranslator { @@ -87,7 +76,7 @@ public class DestructuringDeclarationTranslator extends AbstractTranslator { entryInitializer = TranslationUtils.coerce(context(), entryInitializer, descriptor.getType()); JsName name = context().getNameForDescriptor(descriptor); - if (isVarCapturedInClosure(context().bindingContext(), descriptor)) { + if (isBoxedLocalCapturedInClosure(context().bindingContext(), descriptor)) { JsNameRef alias = getCapturedVarAccessor(name.makeRef()); entryInitializer = JsAstUtils.wrapValue(alias, entryInitializer); }