Check whether the field is indeed being initialized
in checkFieldInExactlyOnceLambdaInitialization #KT-40691 Fixed
This commit is contained in:
Generated
+5
@@ -5131,6 +5131,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/contracts/exception.kt");
|
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")
|
@TestMetadata("forLoop.kt")
|
||||||
public void testForLoop() throws Exception {
|
public void testForLoop() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
||||||
|
|||||||
+4
-2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.CAPTURED_VAL_INITIALIZATION
|
import org.jetbrains.kotlin.diagnostics.Errors.CAPTURED_VAL_INITIALIZATION
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE
|
import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
@@ -54,9 +55,10 @@ class CapturingInClosureChecker : CallChecker {
|
|||||||
variable: VariableDescriptor,
|
variable: VariableDescriptor,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
scopeContainer: DeclarationDescriptor,
|
scopeContainer: DeclarationDescriptor,
|
||||||
reportOn: PsiElement
|
nameElement: PsiElement
|
||||||
) {
|
) {
|
||||||
if (variable !is PropertyDescriptor || scopeContainer !is AnonymousFunctionDescriptor || variable.isVar) return
|
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
|
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer) as? KtFunction ?: return
|
||||||
if (scopeContainer.containingDeclaration !is ConstructorDescriptor) return
|
if (scopeContainer.containingDeclaration !is ConstructorDescriptor) return
|
||||||
if (!isExactlyOnceContract(trace.bindingContext, scopeDeclaration)) return
|
if (!isExactlyOnceContract(trace.bindingContext, scopeDeclaration)) return
|
||||||
@@ -64,7 +66,7 @@ class CapturingInClosureChecker : CallChecker {
|
|||||||
val (callee, param) = getCalleeDescriptorAndParameter(trace.bindingContext, scopeDeclaration) ?: return
|
val (callee, param) = getCalleeDescriptorAndParameter(trace.bindingContext, scopeDeclaration) ?: return
|
||||||
if (callee !is FunctionDescriptor) return
|
if (callee !is FunctionDescriptor) return
|
||||||
if (!callee.isInline || (param.isCrossinline || !InlineUtil.isInlineParameter(param))) {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
+71
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+71
@@ -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 {
|
||||||
|
<!VAL_REASSIGNMENT!>a<!> += "allowed"
|
||||||
|
}
|
||||||
|
crossinlineMe {
|
||||||
|
<!CAPTURED_VAL_INITIALIZATION, VAL_REASSIGNMENT!>b<!> += "not allowed"
|
||||||
|
}
|
||||||
|
noinlineMe {
|
||||||
|
<!CAPTURED_VAL_INITIALIZATION, VAL_REASSIGNMENT!>c<!> += "not allowed"
|
||||||
|
}
|
||||||
|
notinline {
|
||||||
|
<!CAPTURED_VAL_INITIALIZATION, VAL_REASSIGNMENT!>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 <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>blackhole<!>: String
|
||||||
|
inlineMe {
|
||||||
|
blackhole = a
|
||||||
|
}
|
||||||
|
crossinlineMe {
|
||||||
|
blackhole = b
|
||||||
|
}
|
||||||
|
noinlineMe {
|
||||||
|
blackhole = c
|
||||||
|
}
|
||||||
|
notinline {
|
||||||
|
blackhole = d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+33
@@ -22,3 +22,36 @@ package
|
|||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
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
|
||||||
|
}
|
||||||
|
|||||||
+5
@@ -5161,6 +5161,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/contracts/exception.kt");
|
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")
|
@TestMetadata("forLoop.kt")
|
||||||
public void testForLoop() throws Exception {
|
public void testForLoop() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
||||||
|
|||||||
+5
@@ -5161,6 +5161,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/contracts/exception.kt");
|
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")
|
@TestMetadata("forLoop.kt")
|
||||||
public void testForLoop() throws Exception {
|
public void testForLoop() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
||||||
|
|||||||
+5
@@ -5131,6 +5131,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/contracts/exception.kt");
|
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")
|
@TestMetadata("forLoop.kt")
|
||||||
public void testForLoop() throws Exception {
|
public void testForLoop() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
||||||
|
|||||||
Generated
+5
@@ -4166,6 +4166,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
runTest("compiler/testData/codegen/box/contracts/exception.kt");
|
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")
|
@TestMetadata("forLoop.kt")
|
||||||
public void testForLoop() throws Exception {
|
public void testForLoop() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
||||||
|
|||||||
Generated
+5
@@ -4166,6 +4166,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/contracts/exception.kt");
|
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")
|
@TestMetadata("forLoop.kt")
|
||||||
public void testForLoop() throws Exception {
|
public void testForLoop() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
||||||
|
|||||||
+5
@@ -4166,6 +4166,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/contracts/exception.kt");
|
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")
|
@TestMetadata("forLoop.kt")
|
||||||
public void testForLoop() throws Exception {
|
public void testForLoop() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
runTest("compiler/testData/codegen/box/contracts/forLoop.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user