// !DUMP_CFG // !OPT_IN: kotlin.contracts.ExperimentalContracts import kotlin.contracts.* fun unknown(x: () -> T): T { contract { callsInPlace(x, InvocationKind.UNKNOWN) } return x() } fun atLeastOnce(x: () -> T): T { contract { callsInPlace(x, InvocationKind.AT_LEAST_ONCE) } return x() } fun exactlyOnce(x: () -> T): T { contract { callsInPlace(x, InvocationKind.EXACTLY_ONCE) } return x() } fun atMostOnce(x: () -> T): T { contract { callsInPlace(x, InvocationKind.AT_MOST_ONCE) } return x() } fun noContract(x: () -> T): T = x() fun select(vararg x: K): K = x[0] fun id(x: T): T = x fun materialize(): K = null!! fun basic(x: Any?) { exactlyOnce { x as Int } x.inc() // Bad: KT-37838 -> OK } fun completedCallExactlyOnce(x: Any?, y: Any?) { select( // The value of the type argument is known, so the call is complete and the data can flow. id(exactlyOnce { y.inc(); x as Int }), y as Int, exactlyOnce { x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: KT-37838 -> OK y.inc() // OK } fun completedCallAtLeastOnce(x: Any?, y: Any?) { select( id(atLeastOnce { y.inc(); x as Int }), y as Int, atLeastOnce { x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: KT-37838 -> OK y.inc() // OK } fun completedCallAtMostOnce(x: Any?, y: Any?) { select( id(atMostOnce { y.inc(); x as Int }), y as Int, atMostOnce { x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: x as Int might not have executed y.inc() // OK } fun completedCallUnknown(x: Any?, y: Any?) { select( id(unknown { y.inc(); x as Int }), y as Int, unknown { x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: x as Int might not have executed y.inc() // OK } fun completedCallNoContract(x: Any, y: Any) { select( id(noContract { y.inc(); x as Int }), y as Int, noContract { x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: x as Int might not have executed y.inc() // OK } fun incompleteCallExactlyOnce(x: Any, y: Any) { select( // The type argument is uninferred, so the two lambdas are concurrent by data flow. id(exactlyOnce { x as Int; y.inc(); x.inc(); materialize() }), exactlyOnce { y as Int; x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: KT-37838 -> OK y.inc() // Bad: KT-37838 -> OK } fun incompleteCallAtLeastOnce(x: Any, y: Any) { select( id(atLeastOnce { x as Int; y.inc(); x.inc(); materialize() }), atLeastOnce { y as Int; x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: KT-37838 -> OK y.inc() // Bad: KT-37838 -> OK } fun incompleteCallAtMostOnce(x: Any, y: Any) { select( id(atMostOnce { x as Int; y.inc(); x.inc(); materialize() }), atMostOnce { y as Int; x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: x as Int might not have executed y.inc() // Bad: y as Int might not have executed } fun incompleteCallUnknown(x: Any, y: Any) { select( id(unknown { x as Int; y.inc(); x.inc(); materialize() }), unknown { y as Int; x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: x as Int might not have executed y.inc() // Bad: y as Int might not have executed } fun incompleteCallNoContract(x: Any, y: Any) { select( id(noContract { x as Int; y.inc(); x.inc(); materialize() }), noContract { y as Int; x.inc(); y.inc(); 1 } ).inc() // OK x.inc() // Bad: x as Int might not have executed y.inc() // Bad: y as Int might not have executed } fun expectedType() { val x: Int = select(run { materialize() }, run { materialize() }) x.inc() } fun expectedTypeNested() { val x: Int = id(noContract { run { materialize() } }) x.inc() }