| // !LANGUAGE: +AllowContractsForCustomFunctions +UseCallsInPlaceEffect |
| // !OPT_IN: kotlin.contracts.ExperimentalContracts |
| |
| import kotlin.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 |
| x = 42 |
| } |
| |
| // Definite reassignment here, cause can get here only if myRun finished |
| x = outerComputation() |
| } catch (e: java.lang.Exception) { |
| // can catch exception thrown by the inner, so x can be not initialized |
| log() |
| } finally { |
| // Possible reassignment (e.g. if everything finished) |
| x = 42 |
| } |
| |
| // Properly initialized |
| x.inc() |
| } |
| |
| fun innerFinalltInitializes() { |
| 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 non-initialized (e.g. if x.inc() threw an exception) |
| x.inc() |
| } |