diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 39d85225c3e..beb96dd2ccc 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -5131,6 +5131,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/contracts/exception.kt"); } + @TestMetadata("fieldReadInConstructor.kt") + public void testFieldReadInConstructor() throws Exception { + runTest("compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt"); + } + @TestMetadata("forLoop.kt") public void testForLoop() throws Exception { runTest("compiler/testData/codegen/box/contracts/forLoop.kt"); 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 abdf73ea342..bdd59242ab6 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 @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.diagnostics.Errors.CAPTURED_VAL_INITIALIZATION import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE import org.jetbrains.kotlin.resolve.BindingTrace @@ -54,9 +55,10 @@ class CapturingInClosureChecker : CallChecker { variable: VariableDescriptor, trace: BindingTrace, scopeContainer: DeclarationDescriptor, - reportOn: PsiElement + nameElement: PsiElement ) { if (variable !is PropertyDescriptor || scopeContainer !is AnonymousFunctionDescriptor || variable.isVar) return + if ((nameElement as KtExpression).getAssignmentByLHS() == null) return val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer) as? KtFunction ?: return if (scopeContainer.containingDeclaration !is ConstructorDescriptor) return if (!isExactlyOnceContract(trace.bindingContext, scopeDeclaration)) return @@ -64,7 +66,7 @@ class CapturingInClosureChecker : CallChecker { val (callee, param) = getCalleeDescriptorAndParameter(trace.bindingContext, scopeDeclaration) ?: return if (callee !is FunctionDescriptor) return if (!callee.isInline || (param.isCrossinline || !InlineUtil.isInlineParameter(param))) { - trace.report(CAPTURED_VAL_INITIALIZATION.on(reportOn as KtExpression, variable)) + trace.report(CAPTURED_VAL_INITIALIZATION.on(nameElement, variable)) } } diff --git a/compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt b/compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt new file mode 100644 index 00000000000..3c420e152d6 --- /dev/null +++ b/compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt @@ -0,0 +1,28 @@ +// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts +// IGNORE_BACKEND: NATIVE +// WITH_RUNTIME +// KJS_WITH_FULL_RUNTIME + +import kotlin.contracts.* + +class A { + val value = "Some value" + + init { + foo { + println(value) + } + } +} + +fun foo(block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() +} + +fun box(): String { + A() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt index 7790af334c6..660fd70123b 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt @@ -58,3 +58,74 @@ class Test { } } } + +@kotlin.contracts.ExperimentalContracts +class Test1 { + val a: String = "" + val b: String = "" + val c: String = "" + val d: String = "" + + init { + inlineMe { + a += "allowed" + } + crossinlineMe { + b += "not allowed" + } + noinlineMe { + c += "not allowed" + } + notinline { + d += "not allowed" + } + } +} + +@kotlin.contracts.ExperimentalContracts +class Test2 { + val a: String = "" + val b: String = "" + val c: String = "" + val d: String = "" + + init { + var blackhole = "" + inlineMe { + blackhole += a + } + crossinlineMe { + blackhole += b + } + noinlineMe { + blackhole += c + } + notinline { + blackhole += d + } + } +} + +@kotlin.contracts.ExperimentalContracts +class Test4 { + val a: String = "" + val b: String = "" + val c: String = "" + val d: String = "" + + init { + var blackhole: String + inlineMe { + blackhole = a + } + crossinlineMe { + blackhole = b + } + noinlineMe { + blackhole = c + } + notinline { + blackhole = d + } + } +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt index f6218f49d64..75cf936f0a9 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt @@ -58,3 +58,74 @@ class Test { } } } + +@kotlin.contracts.ExperimentalContracts +class Test1 { + val a: String = "" + val b: String = "" + val c: String = "" + val d: String = "" + + init { + inlineMe { + a += "allowed" + } + crossinlineMe { + b += "not allowed" + } + noinlineMe { + c += "not allowed" + } + notinline { + d += "not allowed" + } + } +} + +@kotlin.contracts.ExperimentalContracts +class Test2 { + val a: String = "" + val b: String = "" + val c: String = "" + val d: String = "" + + init { + var blackhole = "" + inlineMe { + blackhole += a + } + crossinlineMe { + blackhole += b + } + noinlineMe { + blackhole += c + } + notinline { + blackhole += d + } + } +} + +@kotlin.contracts.ExperimentalContracts +class Test4 { + val a: String = "" + val b: String = "" + val c: String = "" + val d: String = "" + + init { + var blackhole: String + inlineMe { + blackhole = a + } + crossinlineMe { + blackhole = b + } + noinlineMe { + blackhole = c + } + notinline { + blackhole = d + } + } +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt index 7f702e58029..7add69b5e5d 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt @@ -22,3 +22,36 @@ package public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + +@kotlin.contracts.ExperimentalContracts public final class Test1 { + public constructor Test1() + public final val a: kotlin.String = "" + public final val b: kotlin.String = "" + public final val c: kotlin.String = "" + public final val d: kotlin.String = "" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@kotlin.contracts.ExperimentalContracts public final class Test2 { + public constructor Test2() + public final val a: kotlin.String = "" + public final val b: kotlin.String = "" + public final val c: kotlin.String = "" + public final val d: kotlin.String = "" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@kotlin.contracts.ExperimentalContracts public final class Test4 { + public constructor Test4() + public final val a: kotlin.String = "" + public final val b: kotlin.String = "" + public final val c: kotlin.String = "" + public final val d: kotlin.String = "" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 43b704208e1..587ded0d4c5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5161,6 +5161,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/contracts/exception.kt"); } + @TestMetadata("fieldReadInConstructor.kt") + public void testFieldReadInConstructor() throws Exception { + runTest("compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt"); + } + @TestMetadata("forLoop.kt") public void testForLoop() throws Exception { runTest("compiler/testData/codegen/box/contracts/forLoop.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index adbfb1c1d5b..b03b515865d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -5161,6 +5161,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/contracts/exception.kt"); } + @TestMetadata("fieldReadInConstructor.kt") + public void testFieldReadInConstructor() throws Exception { + runTest("compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt"); + } + @TestMetadata("forLoop.kt") public void testForLoop() throws Exception { runTest("compiler/testData/codegen/box/contracts/forLoop.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 53d01b62b64..804d0c9e38c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -5131,6 +5131,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/contracts/exception.kt"); } + @TestMetadata("fieldReadInConstructor.kt") + public void testFieldReadInConstructor() throws Exception { + runTest("compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt"); + } + @TestMetadata("forLoop.kt") public void testForLoop() throws Exception { runTest("compiler/testData/codegen/box/contracts/forLoop.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 8bec27c0f6e..f6734fee0a3 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -4166,6 +4166,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/contracts/exception.kt"); } + @TestMetadata("fieldReadInConstructor.kt") + public void testFieldReadInConstructor() throws Exception { + runTest("compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt"); + } + @TestMetadata("forLoop.kt") public void testForLoop() throws Exception { runTest("compiler/testData/codegen/box/contracts/forLoop.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index b218a530ee3..3949f5b3dcb 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -4166,6 +4166,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/contracts/exception.kt"); } + @TestMetadata("fieldReadInConstructor.kt") + public void testFieldReadInConstructor() throws Exception { + runTest("compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt"); + } + @TestMetadata("forLoop.kt") public void testForLoop() throws Exception { runTest("compiler/testData/codegen/box/contracts/forLoop.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 311a975cd91..023d525705b 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 @@ -4166,6 +4166,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/contracts/exception.kt"); } + @TestMetadata("fieldReadInConstructor.kt") + public void testFieldReadInConstructor() throws Exception { + runTest("compiler/testData/codegen/box/contracts/fieldReadInConstructor.kt"); + } + @TestMetadata("forLoop.kt") public void testForLoop() throws Exception { runTest("compiler/testData/codegen/box/contracts/forLoop.kt");