Forbid val field initialization inside EXACLTY_ONCE lambda

unless the lambda is inline. This way, final field will remain final.
This commit is contained in:
Ilmir Usmanov
2020-06-03 18:32:43 +02:00
parent 6d6a228057
commit 8cc5f2abfb
18 changed files with 177 additions and 76 deletions
@@ -0,0 +1,60 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseCallsInPlaceEffect
// !USE_EXPERIMENTAL: kotlin.internal.ContractsDsl
import kotlin.contracts.*
@kotlin.contracts.ExperimentalContracts
inline fun inlineMe(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@kotlin.contracts.ExperimentalContracts
inline fun crossinlineMe(crossinline block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@Suppress("NOTHING_TO_INLINE")
@kotlin.contracts.ExperimentalContracts
inline fun noinlineMe(noinline block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@kotlin.contracts.ExperimentalContracts
fun notinline(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@kotlin.contracts.ExperimentalContracts
class Test {
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"
}
}
}
@@ -0,0 +1,60 @@
// !LANGUAGE: +AllowContractsForCustomFunctions +UseCallsInPlaceEffect
// !USE_EXPERIMENTAL: kotlin.internal.ContractsDsl
import kotlin.contracts.*
@kotlin.contracts.ExperimentalContracts
inline fun inlineMe(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@kotlin.contracts.ExperimentalContracts
inline fun crossinlineMe(crossinline block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@Suppress("NOTHING_TO_INLINE")
@kotlin.contracts.ExperimentalContracts
inline fun noinlineMe(noinline block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@kotlin.contracts.ExperimentalContracts
fun notinline(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
@kotlin.contracts.ExperimentalContracts
class Test {
val a: String
val b: String
val c: String
val d: String
init {
inlineMe {
a = "allowed"
}
crossinlineMe {
<!CAPTURED_VAL_INITIALIZATION!>b<!> = "not allowed"
}
noinlineMe {
<!CAPTURED_VAL_INITIALIZATION!>c<!> = "not allowed"
}
notinline {
<!CAPTURED_VAL_INITIALIZATION!>d<!> = "not allowed"
}
}
}
@@ -0,0 +1,24 @@
package
@kotlin.contracts.ExperimentalContracts public inline fun crossinlineMe(/*0*/ crossinline block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
@kotlin.contracts.ExperimentalContracts public inline fun inlineMe(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
@kotlin.Suppress(names = {"NOTHING_TO_INLINE"}) @kotlin.contracts.ExperimentalContracts public inline fun noinlineMe(/*0*/ noinline block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
@kotlin.contracts.ExperimentalContracts public fun notinline(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
@kotlin.contracts.ExperimentalContracts public final class Test {
public constructor Test()
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
}