b29a6e48fb
- Introduce new language feature 'ReadDeserializedContracts', which allows to deserialize contracts from metadata. - Introduce new language feature 'AllowContractsForCustomFunctions', which allows reading contracts from sources. - Use new features instead of combination 'CallsInPlaceEffect || ReturnsEffect' - Rename 'CallsInPlaceEffect' -> 'UseCallsInPlaceEffect', 'ReturnsEffect' -> 'UseReturnsEffect'. As names suggest, they control if it is allowed to use corresponding effect in analysis. We have to introduce separate 'ReadDeserializedContracts' to enable contracts only in some modules of the project, because libraries are read with project-wide settings (see KT-20692).
97 lines
2.3 KiB
Kotlin
Vendored
97 lines
2.3 KiB
Kotlin
Vendored
// !DIAGNOSTICS: -UNUSED_PARAMETER -INVISIBLE_MEMBER -INVISIBLE_REFERENCE
|
|
// !LANGUAGE: +AllowContractsForCustomFunctions +UseCallsInPlaceEffect
|
|
|
|
import kotlin.internal.contracts.*
|
|
|
|
inline fun <T> myRun(block: () -> T): T {
|
|
contract {
|
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
|
}
|
|
return block()
|
|
}
|
|
|
|
fun innerComputation(): Int = 42
|
|
fun outerComputation(): Int = 52
|
|
|
|
fun log() = Unit
|
|
|
|
fun outerFinallyInitializes() {
|
|
val x: Int
|
|
|
|
try {
|
|
myRun {
|
|
try {
|
|
x = innerComputation()
|
|
} catch (e: java.lang.Exception) {
|
|
log()
|
|
}
|
|
// possible reassignment if innerComputation finished
|
|
<!VAL_REASSIGNMENT!>x<!> = 42
|
|
// x is ID here
|
|
}
|
|
|
|
// Definite reassignment here, cause can get here only if myRun finished
|
|
// Not reported because of repeating diagnostic
|
|
x = outerComputation()
|
|
} catch (e: java.lang.Exception) {
|
|
// can catch exception thrown by the inner, so x can be not initalized
|
|
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
|
|
log()
|
|
} finally {
|
|
// Possible reassignment (e.g. if everything finished)
|
|
// Not reported because of repeating diagnostic
|
|
x = 42
|
|
}
|
|
|
|
// Properly initialized
|
|
x.inc()
|
|
}
|
|
|
|
fun innerFinallyInitializes() {
|
|
val x: Int
|
|
try {
|
|
myRun {
|
|
try {
|
|
innerComputation()
|
|
} catch (e: java.lang.Exception) {
|
|
log()
|
|
} finally {
|
|
x = 42
|
|
}
|
|
}
|
|
|
|
// Properly initialized
|
|
x.inc()
|
|
} catch (e: java.lang.Exception) {
|
|
log()
|
|
}
|
|
|
|
// Still can be unitialized because we don't know what can happen in try-block
|
|
// (e.g., OutOfMemory exception could've happened even before myRun was executed)
|
|
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
|
|
}
|
|
|
|
|
|
fun innerFinallyInitializesOuterRethrows() {
|
|
val x: Int
|
|
try {
|
|
myRun {
|
|
try {
|
|
innerComputation()
|
|
} catch (e: java.lang.Exception) {
|
|
log()
|
|
} finally {
|
|
x = 42
|
|
}
|
|
}
|
|
|
|
// Properly initialized
|
|
x.inc()
|
|
} catch (e: java.lang.Exception) {
|
|
log()
|
|
throw e
|
|
}
|
|
|
|
// Guaranteed to be initialized because all catch-clauses are rethrowing
|
|
x.inc()
|
|
} |