From d7b9920ebab7f3fcc16af180e2d72b86959975cf Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Mon, 12 Oct 2020 00:39:08 +0200 Subject: [PATCH] Treat field initializer as class initializer when checking for allowance of other field initialization in lambda with EXACTLY_ONCE contract. #KT-40948 Fixed --- .../checkers/CapturingInClosureChecker.kt | 4 +++- .../fieldInitialization.fir.kt | 21 +++++++++++++++++++ .../fieldInitialization.kt | 21 +++++++++++++++++++ .../fieldInitialization.txt | 15 +++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) 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 b5d59f36144..f4d9087e6df 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 @@ -60,7 +60,9 @@ class CapturingInClosureChecker : CallChecker { if (variable !is PropertyDescriptor || scopeContainer !is AnonymousFunctionDescriptor || variable.isVar) return if (!isLhsOfAssignment(nameElement as KtExpression)) return val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer) as? KtFunction ?: return - if (scopeContainer.containingDeclaration !is ConstructorDescriptor) return + if (scopeContainer.containingDeclaration !is ConstructorDescriptor && + scopeContainer.containingDeclaration !is PropertyDescriptor + ) return if (!isExactlyOnceContract(trace.bindingContext, scopeDeclaration)) return if (trace.bindingContext[CAPTURED_IN_CLOSURE, variable] == CaptureKind.NOT_INLINE) return val (callee, param) = getCalleeDescriptorAndParameter(trace.bindingContext, scopeDeclaration) ?: return diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt index ad7a24da406..0d3c1062a2e 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.fir.kt @@ -129,3 +129,24 @@ class Test4 { } } } + +@kotlin.contracts.ExperimentalContracts +class Test5 { + val a: String + val b: String + val c: String + val d: String + + val aInit = inlineMe { + a = "OK" + } + val bInit = crossinlineMe { + b = "OK" + } + val cInit = noinlineMe { + c = "OK" + } + val dInit = notinline { + d = "OK" + } +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt index bbfb38b0017..1c7677ec5a4 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.kt @@ -129,3 +129,24 @@ class Test4 { } } } + +@kotlin.contracts.ExperimentalContracts +class Test5 { + val a: String + val b: String + val c: String + val d: String + + val aInit = inlineMe { + a = "OK" + } + val bInit = crossinlineMe { + b = "OK" + } + val cInit = noinlineMe { + c = "OK" + } + val dInit = notinline { + d = "OK" + } +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt index 7add69b5e5d..012c3fbc21e 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/fieldInitialization.txt @@ -55,3 +55,18 @@ 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 Test5 { + public constructor Test5() + public final val a: kotlin.String + public final val aInit: kotlin.Unit + public final val b: kotlin.String + public final val bInit: kotlin.Unit + public final val c: kotlin.String + public final val cInit: kotlin.Unit + public final val d: kotlin.String + public final val dInit: kotlin.Unit + 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 +}