Effects: add diagnostic tests on contracts

- Make AbstractDiagnosticsTest dump function contracts
- Add diagnostics tests on parsing contracts
- Add diagnostics tests on smartcats in presence of functions with
contracts
- Add diagnostics tests on initialization and flow in presence of
in-place called lambdas

==========
Introduction of EffectSystem: 16/18
This commit is contained in:
Dmitry Savvinov
2017-10-03 15:02:51 +03:00
parent f487525a1d
commit 4434db4d69
120 changed files with 4179 additions and 1 deletions
@@ -0,0 +1,50 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun getBoolean(): Boolean = false
fun test() {
val x: Int
if (getBoolean())
myRun {
while (getBoolean()) {
do {
myRun {
if (getBoolean()) {
x = 42 // No reassignment because of break
}
else {
x = 43 // No reassignment because of break
}
}
break
} while (<!UNREACHABLE_CODE!>getBoolean()<!>)
// Loop executed exectly once, initializing x
myRun { x.inc() }
myRun { <!VAL_REASSIGNMENT!>x<!> = 42 }
break
}
// x is I?D here because loop could've been execited
// VAL_REASSIGNMENT isn't reported because of repeating diagnostic
x = 42
// x is ID now
}
else
myRun {
x = 42
}
// x is ID because both branches are ID
x.inc()
}
@@ -0,0 +1,7 @@
package
public fun getBoolean(): kotlin.Boolean
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun test(): kotlin.Unit
@@ -0,0 +1,97 @@
== myRun ==
fun <T> myRun(@CalledInPlace block: () -> T): T = block()
---------------------
L0:
1 <START> INIT: in: {} out: {}
v(@CalledInPlace block: () -> T) INIT: in: {} out: {block=D}
magic[FAKE_INITIALIZER](@CalledInPlace block: () -> T) -> <v0> INIT: in: {block=D} out: {block=D}
w(block|<v0>) INIT: in: {block=D} out: {block=ID} USE: in: {block=READ} out: {block=READ}
r(block) -> <v1> INIT: in: {block=ID} out: {block=ID} USE: in: {} out: {block=READ}
mark(block())
call(block(), invoke|<v1>) -> <v2>
ret(*|<v2>) L1
L1:
<END>
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {block=I?} out: {block=I?} USE: in: {} out: {}
=====================
== functionWithExpressionBody ==
fun functionWithExpressionBody(x: Int) = myRun {
if (x == 0) return true
if (x == 1) return false
return functionWithExpressionBody(x - 2)
}
---------------------
L0:
1 <START> INIT: in: {} out: {}
v(x: Int) INIT: in: {} out: {x=D}
magic[FAKE_INITIALIZER](x: Int) -> <v0> INIT: in: {x=D} out: {x=D}
w(x|<v0>) INIT: in: {x=D} out: {x=ID}
mark({ if (x == 0) return true if (x == 1) return false return functionWithExpressionBody(x - 2) }) INIT: in: {x=ID} out: {x=ID}
jmp?(L2)
d({ if (x == 0) return true if (x == 1) return false return functionWithExpressionBody(x - 2) }) INIT: in: {} out: {} USE: in: {x=READ} out: {x=READ}
L2 [after local declaration]:
r({ if (x == 0) return true if (x == 1) return false return functionWithExpressionBody(x - 2) }) -> <v1> INIT: in: {x=ID} out: {x=ID}
mark(myRun { if (x == 0) return true if (x == 1) return false return functionWithExpressionBody(x - 2) })
call(myRun { if (x == 0) return true if (x == 1) return false return functionWithExpressionBody(x - 2) }, myRun|<v1>) -> <v2>
ret(*|<v2>) L1
L1:
<END>
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {x=I?} out: {x=I?} USE: in: {} out: {}
=====================
== anonymous_0 ==
{
if (x == 0) return true
if (x == 1) return false
return functionWithExpressionBody(x - 2)
}
---------------------
L3:
2 <START> INIT: in: {x=ID} out: {x=ID}
3 mark(if (x == 0) return true if (x == 1) return false return functionWithExpressionBody(x - 2))
mark(if (x == 0) return true)
r(x) -> <v0>
r(0) -> <v1>
mark(x == 0)
call(x == 0, equals|<v0>, <v1>) -> <v2>
jf(L5|<v2>) USE: in: {x=READ} out: {x=READ}
r(true) -> <v3>
ret(*|<v3>) L1 USE: in: {} out: {}
- jmp(L6)
L5 [else branch]:
read (Unit) INIT: in: {x=ID} out: {x=ID}
L6 ['if' expression result]:
merge(if (x == 0) return true|!<v4>) -> <v5>
mark(if (x == 1) return false)
r(x) -> <v6>
r(1) -> <v7>
mark(x == 1)
call(x == 1, equals|<v6>, <v7>) -> <v8>
jf(L7|<v8>) USE: in: {x=READ} out: {x=READ}
r(false) -> <v9>
ret(*|<v9>) L1 USE: in: {} out: {}
- jmp(L8)
L7 [else branch]:
read (Unit) INIT: in: {x=ID} out: {x=ID}
L8 ['if' expression result]:
merge(if (x == 1) return false|!<v10>) -> <v11> USE: in: {x=READ} out: {x=READ}
r(x) -> <v12> USE: in: {} out: {x=READ}
r(2) -> <v13>
mark(x - 2)
call(x - 2, minus|<v12>, <v13>) -> <v14>
mark(functionWithExpressionBody(x - 2))
call(functionWithExpressionBody(x - 2), functionWithExpressionBody|<v14>) -> <v15>
ret(*|<v15>) L1 USE: in: {} out: {}
- 2 ret(*|!<v16>) L4
L4:
<END> INIT: in: {} out: {}
error:
<ERROR>
sink:
<SINK> USE: in: {} out: {}
=====================
@@ -0,0 +1,17 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun functionWithExpressionBody(x: Int): Boolean = myRun {
if (x == 0) return true
if (x == 1) return false
return functionWithExpressionBody(x - 2)
}
@@ -0,0 +1,5 @@
package
public fun functionWithExpressionBody(/*0*/ x: kotlin.Int): kotlin.Boolean
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
@@ -0,0 +1,19 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun functionWithSideEffects(x: Int): Int = x + 1 // ...and some other useful side-effects
fun log(<!UNUSED_PARAMETER!>s<!>: String) = Unit // some logging or println or whatever returning Unit
fun implicitCastWithIf(s: String) {
myRun { if (s == "") functionWithSideEffects(42) else log(s) }
}
@@ -0,0 +1,7 @@
package
public fun functionWithSideEffects(/*0*/ x: kotlin.Int): kotlin.Int
public fun implicitCastWithIf(/*0*/ s: kotlin.String): kotlin.Unit
public fun log(/*0*/ s: kotlin.String): kotlin.Unit
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
@@ -0,0 +1,16 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun myRun(block: () -> Unit): Unit {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
fun test() {
myRun { throw java.lang.IllegalArgumentException() }
<!UNREACHABLE_CODE!>val x: Int = 42<!>
}
@@ -0,0 +1,6 @@
package
public inline fun myRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
public fun test(): kotlin.Unit
@@ -0,0 +1,22 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun myRun(block: () -> Unit): Unit {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
inline fun unknownRun(block: () -> Unit) { block() }
fun foo() {
val x: Int
myRun {
unknownRun { println("shouldn't change anything") }
x = 42
}
println(x)
}
@@ -0,0 +1,7 @@
package
public fun foo(): kotlin.Unit
public inline fun myRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
public inline fun unknownRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
@@ -0,0 +1,85 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
inline fun <T, R> T.myLet(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
inline fun unknownRun(block: () -> Unit) = block()
fun getBool(): Boolean = false
fun threeLevelsReturnNoInitialization(x: Int?): Int? {
// Inner always jumps to outer
// And middle always calls inner
// So, in fact, middle never finished normally
// Hence 'y = 54' in middle is unreachable, and middle doesn't performs definite initalization
// Hence, outer doesn't performs definite initialization
val y: Int
myRun outer@ {
myRun middle@ {
x.myLet inner@ {
if (it == null) {
y = 42
return@outer Unit
}
else {
return@outer Unit
}
}
}
// Possible to report unreachable here
<!UNREACHABLE_CODE!>y = 54<!>
}
return <!UNINITIALIZED_VARIABLE!>y<!>.inc()
}
fun threeLevelsReturnWithInitialization(x: Int?): Int? {
val y: Int
myRun outer@ {
myRun middle@ {
x.myLet inner@ {
if (it == null) {
y = 42
return@outer Unit
}
else {
y = 34
return@outer Unit
}
}
}
}
return y.inc()
}
fun threeLevelsReturnWithUnknown(x: Int?): Int? {
val y: Int
myRun outer@ {
unknownRun middle@ {
x.myLet inner@ {
if (it == null) {
<!CAPTURED_VAL_INITIALIZATION!>y<!> = 42
return@outer Unit
}
else {
y = 34
return@outer Unit
}
}
}
}
return <!UNINITIALIZED_VARIABLE!>y<!>.inc()
}
@@ -0,0 +1,13 @@
package
public fun getBool(): kotlin.Boolean
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun threeLevelsReturnNoInitialization(/*0*/ x: kotlin.Int?): kotlin.Int?
public fun threeLevelsReturnWithInitialization(/*0*/ x: kotlin.Int?): kotlin.Int?
public fun threeLevelsReturnWithUnknown(/*0*/ x: kotlin.Int?): kotlin.Int?
public inline fun unknownRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
public inline fun </*0*/ T, /*1*/ R> T.myLet(/*0*/ block: (T) -> R): R
CallsInPlace(block, EXACTLY_ONCE)
@@ -0,0 +1,97 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -INVISIBLE_MEMBER -INVISIBLE_REFERENCE
// !LANGUAGE: +CallsInPlaceEffect
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()
}
@@ -0,0 +1,11 @@
package
public fun innerComputation(): kotlin.Int
public fun innerFinallyInitializes(): kotlin.Unit
public fun innerFinallyInitializesOuterRethrows(): kotlin.Unit
public fun log(): kotlin.Unit
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun outerComputation(): kotlin.Int
public fun outerFinallyInitializes(): kotlin.Unit
@@ -0,0 +1,46 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
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 innerTryCatchInitializes() {
val x: Int
try {
myRun {
try {
x = innerComputation()
x.inc()
}
catch (e: java.lang.Exception) {
// Potential reassignment because x.inc() could threw
<!VAL_REASSIGNMENT!>x<!> = 42
x.inc()
}
}
// Can get here only when inlined lambda exited properly, i.e. x is initialized
x.inc()
outerComputation()
} catch (e: java.lang.Exception) {
// Can get here if innerComputation() threw an exception that wasn't catched by the inner catch (x is not initialized)
// OR if outerComputation() threw an exception (x is initialized because we reach outer computation only when inner finished ok)
// So, x=I? here
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
// Potential reasignment
x = 42
}
// Here x=I because outer try-catch either exited normally (x=I) or catched exception (x=I, with reassingment, though)
x.inc()
}
@@ -0,0 +1,8 @@
package
public fun innerComputation(): kotlin.Int
public fun innerTryCatchInitializes(): kotlin.Unit
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun outerComputation(): kotlin.Int
@@ -0,0 +1,17 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun <T, R> T.myLet(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
fun nonLocalReturnWithElvis(x: Int?): Int? {
x?.myLet { return 42 }
return x?.inc()
}
@@ -0,0 +1,5 @@
package
public fun nonLocalReturnWithElvis(/*0*/ x: kotlin.Int?): kotlin.Int?
public inline fun </*0*/ T, /*1*/ R> T.myLet(/*0*/ block: (T) -> R): R
CallsInPlace(block, EXACTLY_ONCE)
@@ -0,0 +1,33 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun myRun(block: () -> Unit): Unit {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun getBool(): Boolean = false
fun withLabeledReturn() {
val y: Int
val x = myRun outer@ {
myRun { return@outer Unit }
<!UNREACHABLE_CODE!>y = 42<!>
}
println(<!UNINITIALIZED_VARIABLE!>y<!>)
println(x)
}
fun withLabeledReturn2(y: Int) {
myRun outer@ {
myRun { return@outer Unit }
<!UNREACHABLE_CODE!>println(y)<!>
}
println(y)
}
@@ -0,0 +1,8 @@
package
public fun getBool(): kotlin.Boolean
public inline fun myRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
public fun withLabeledReturn(): kotlin.Unit
public fun withLabeledReturn2(/*0*/ y: kotlin.Int): kotlin.Unit
@@ -0,0 +1,78 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun exitOnlyThroughLocalReturns(b: Boolean) {
var x: Int
var s: String
myRun {
if (b) {
x = 42
return@myRun
}
if (!b) {
s = "hello"
x = 42
return@myRun
}
else {
s = "world"
x = 239
}
}
x.inc()
<!UNINITIALIZED_VARIABLE!>s<!>.length
}
fun exitOnlyThroughNonLocalReturns(b: Boolean?) {
var x: Int
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>s<!>: String
myRun {
if (b == null) {
x = 42
return
}
if (<!DEBUG_INFO_SMARTCAST!>b<!>.not()) {
x = 54
}
if (<!UNINITIALIZED_VARIABLE!>x<!> == 42) {
return
}
else {
x = 42
s = "hello"
return
}
}
<!UNREACHABLE_CODE!>x.inc()<!>
<!UNREACHABLE_CODE!>s.length<!>
}
fun nonLocalReturnAndOrdinaryExit(b: Boolean) {
var x: Int
var s: String
myRun {
if (b) {
x = 42
return
}
x = 54
s = "hello"
}
x.inc()
s.length
}
@@ -0,0 +1,8 @@
package
public fun exitOnlyThroughLocalReturns(/*0*/ b: kotlin.Boolean): kotlin.Unit
public fun exitOnlyThroughNonLocalReturns(/*0*/ b: kotlin.Boolean?): kotlin.Unit
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun nonLocalReturnAndOrdinaryExit(/*0*/ b: kotlin.Boolean): kotlin.Unit
@@ -0,0 +1,47 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun myRun(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
inline fun <T> unknownRun(block: () -> T): T = block()
fun throwIfNotCalled() {
val x: Int
myRun outer@ {
unknownRun {
myRun {
<!CAPTURED_VAL_INITIALIZATION!>x<!> = 42
return@outer
}
}
throw java.lang.IllegalArgumentException()
}
// x *is* initialized here, because if myRun was never called -> exception
// were thrown and control flow wouldn't be here
println(x)
}
fun catchThrowIfNotCalled() {
val x: Int
try {
myRun outer@ {
unknownRun {
myRun {
<!CAPTURED_VAL_INITIALIZATION!>x<!> = 42
return@outer
}
}
throw java.lang.IllegalArgumentException()
}
} catch (ignored: java.lang.IllegalArgumentException) { }
// x *isn't* initialized here!
println(<!UNINITIALIZED_VARIABLE!>x<!>)
}
@@ -0,0 +1,8 @@
package
public fun catchThrowIfNotCalled(): kotlin.Unit
public inline fun myRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
public fun throwIfNotCalled(): kotlin.Unit
public inline fun </*0*/ T> unknownRun(/*0*/ block: () -> T): T
@@ -0,0 +1,57 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun someComputation(): Int = 42
fun tryCatchInlined() {
val x: Int
myRun {
try {
x = someComputation()
x.inc()
}
catch (e: java.lang.Exception) {
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
}
<!VAL_REASSIGNMENT!>x<!> = 42
x.inc()
}
fun possibleReassignmentInTryCatch() {
val x: Int
myRun {
try {
x = someComputation()
x.inc()
}
catch (e: java.lang.Exception) {
<!VAL_REASSIGNMENT!>x<!> = 42
x.inc()
}
x.inc()
}
x.inc()
}
fun tryCatchOuter() {
val x: Int
try {
myRun { x = someComputation() }
x.inc()
}
catch (e: java.lang.Exception) {
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
}
@@ -0,0 +1,9 @@
package
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun possibleReassignmentInTryCatch(): kotlin.Unit
public fun someComputation(): kotlin.Int
public fun tryCatchInlined(): kotlin.Unit
public fun tryCatchOuter(): kotlin.Unit
@@ -0,0 +1,33 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER -UNUSED_PARAMETER
import kotlin.internal.contracts.*
inline fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun someComputation(): Int = 42
fun report(x: Int) = Unit
fun innerTryCatchFinally() {
val x: Int
myRun {
try {
x = someComputation()
report(x)
} catch (e: java.lang.Exception) {
<!VAL_REASSIGNMENT!>x<!> = 42
report(x)
} finally {
x = 0
}
}
x.inc()
}
@@ -0,0 +1,8 @@
package
public fun innerTryCatchFinally(): kotlin.Unit
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun report(/*0*/ x: kotlin.Int): kotlin.Unit
public fun someComputation(): kotlin.Int
@@ -0,0 +1,18 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun foo(x: Int): Int = x + 1
fun typeMismatchInLambda(y: String): Int {
val x = myRun { foo(<!TYPE_MISMATCH!>y<!>) }
return x
}
@@ -0,0 +1,7 @@
package
public fun foo(/*0*/ x: kotlin.Int): kotlin.Int
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun typeMismatchInLambda(/*0*/ y: kotlin.String): kotlin.Int
@@ -0,0 +1,16 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
inline fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun throwInLambda(): Int {
<!UNREACHABLE_CODE!>val <!UNUSED_VARIABLE!>x<!> =<!> myRun { throw java.lang.IllegalArgumentException(); <!UNREACHABLE_CODE!>42<!> }
<!UNREACHABLE_CODE!>return x<!>
}
@@ -0,0 +1,6 @@
package
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun throwInLambda(): kotlin.Int
@@ -0,0 +1,74 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> runTwice(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
block()
return block();
};
fun <T> runOnce(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block();
};
fun valueReassignment() {
val x: Int
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
runTwice { <!VAL_REASSIGNMENT!>x<!> = 42 }
x.inc()
}
fun shadowing() {
val x: Int
runTwice { val <!NAME_SHADOWING!>x<!>: Int; x = 42; x.inc() }
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun branchingFlow(a: Any?) {
val x: Int
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
if (a is String) {
runTwice { <!VAL_REASSIGNMENT!>x<!> = 42 }
}
else {
x = 43
}
x.inc()
}
fun branchingFlowWithMissingBranches(a: Any?) {
val x: Int
if (a is String) {
runTwice { <!VAL_REASSIGNMENT!>x<!> = 42 }
}
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun repeatingFlow(n: Int) {
val x: Int
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
for (i in 1..n) {
runTwice { <!VAL_REASSIGNMENT!>x<!> = 42 }
}
x.inc()
}
fun repeatingFlow2(n: Int) {
val x: Int
for (i in 1..n) {
runTwice { <!VAL_REASSIGNMENT!>x<!> = 42 }
}
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
@@ -0,0 +1,14 @@
package
public fun branchingFlow(/*0*/ a: kotlin.Any?): kotlin.Unit
public fun branchingFlowWithMissingBranches(/*0*/ a: kotlin.Any?): kotlin.Unit
public fun repeatingFlow(/*0*/ n: kotlin.Int): kotlin.Unit
public fun repeatingFlow2(/*0*/ n: kotlin.Int): kotlin.Unit
public fun </*0*/ T> runOnce(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun </*0*/ T> runTwice(/*0*/ block: () -> T): T
CallsInPlace(block, AT_LEAST_ONCE)
public fun shadowing(): kotlin.Unit
public fun valueReassignment(): kotlin.Unit
@@ -0,0 +1,30 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> runTwice(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
block()
return block();
};
fun testInitialization() {
var x: Int
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
runTwice { x = 42 }
x.inc()
x = 43
x.inc()
}
fun repeatingFlow(n: Int) {
var x: Int
for (i in 1..n) {
runTwice { x = 42 }
}
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
@@ -0,0 +1,7 @@
package
public fun repeatingFlow(/*0*/ n: kotlin.Int): kotlin.Unit
public fun </*0*/ T> runTwice(/*0*/ block: () -> T): T
CallsInPlace(block, AT_LEAST_ONCE)
public fun testInitialization(): kotlin.Unit
@@ -0,0 +1,28 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> runTwice(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
block()
return block();
};
fun <T> funWithUnknownInvocations(block: () -> T) = block()
fun indefiniteFlow() {
var x: Int
funWithUnknownInvocations { runTwice { x = 42 } }
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun shadowing() {
var x: Int
runTwice { val <!NAME_SHADOWING!>x<!>: Int; x = 42; x.inc() }
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
@@ -0,0 +1,8 @@
package
public fun </*0*/ T> funWithUnknownInvocations(/*0*/ block: () -> T): T
public fun indefiniteFlow(): kotlin.Unit
public fun </*0*/ T> runTwice(/*0*/ block: () -> T): T
CallsInPlace(block, AT_LEAST_ONCE)
public fun shadowing(): kotlin.Unit
@@ -0,0 +1,91 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun initialization() {
val x: Int
myRun {
x = 42
42
}
x.inc()
}
fun shadowing() {
val x = 42
myRun {
val <!NAME_SHADOWING!>x<!> = 43
x.inc()
}
x.inc()
}
fun nestedDefiniteAssignment() {
val x: Int
myRun {
val y = "Hello"
myRun {
x = 42
}
y.length
}
x.inc()
}
fun deeplyNestedDefiniteAssignment() {
val x: Int
myRun {
val y: String
myRun {
val z: String
myRun {
z = "Hello"
y = "World"
x = 42
}
z.length
}
y.length
}
x.inc()
}
fun branchingFlow(a: Any?) {
val x: Int
if (a is String) {
myRun { x = 42 }
}
else {
myRun { x = 43 }
}
x.inc()
}
fun returningValue() {
val x: Int
val hello = myRun { x = 42; "hello" }
x.inc()
hello.length
}
fun unknownRun(block: () -> Unit) = block()
class DefiniteInitializationInInitSection {
val x: Int
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val y: Int<!>
init {
myRun { x = 42 }
unknownRun { <!CAPTURED_MEMBER_VAL_INITIALIZATION!>y<!> = 239 }
}
}
@@ -0,0 +1,21 @@
package
public fun branchingFlow(/*0*/ a: kotlin.Any?): kotlin.Unit
public fun deeplyNestedDefiniteAssignment(): kotlin.Unit
public fun initialization(): kotlin.Unit
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun nestedDefiniteAssignment(): kotlin.Unit
public fun returningValue(): kotlin.Unit
public fun shadowing(): kotlin.Unit
public fun unknownRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
public final class DefiniteInitializationInInitSection {
public constructor DefiniteInitializationInInitSection()
public final val x: kotlin.Int
public final val y: kotlin.Int
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
}
@@ -0,0 +1,27 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun reassignmentInUsualFlow() {
val x: Int
myRun { x = 42 }
<!VAL_REASSIGNMENT!>x<!> = 43
x.inc()
}
fun reassignment() {
val x = 42
myRun {
<!VAL_REASSIGNMENT!>x<!> = 43
}
x.inc()
}
@@ -0,0 +1,7 @@
package
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun reassignment(): kotlin.Unit
public fun reassignmentInUsualFlow(): kotlin.Unit
@@ -0,0 +1,67 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun myRepeat(n: Int, action: () -> Unit) {
contract {
callsInPlace(action)
}
for (i in 1..n) action()
}
fun branchingIndetermineFlow(a: Any?) {
val x: Int
if (a is String) {
myRepeat(<!DEBUG_INFO_SMARTCAST!>a<!>.length) {
// Val reassignment because we know that repeat's lambda called in-place
myRun { <!VAL_REASSIGNMENT!>x<!> = 42 }
}
}
else {
myRun { x = 43 }
}
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun nonAnonymousLambdas() {
val x: Int
val initializer = { <!CAPTURED_VAL_INITIALIZATION!>x<!> = 42 }
myRun(initializer)
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun multipleAssignments() {
val x: Int
myRepeat(42) {
// Val reassignment because we know that repeat's lambda called in-place
myRun { <!VAL_REASSIGNMENT!>x<!> = 42 }
}
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun funWithUnknownInvocations(block: () -> Unit) = block()
fun nestedIndefiniteAssignment() {
val x: Int
// Captured val initialization reported, because we don't know anything about funWithUnknownInvocations
funWithUnknownInvocations { myRun { <!CAPTURED_VAL_INITIALIZATION!>x<!> = 42 } }
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
class InitializationForbiddenInNonInitSection {
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val x: Int<!>
fun setup() {
myRun { <!VAL_REASSIGNMENT!>x<!> = 42 }
}
}
@@ -0,0 +1,22 @@
package
public fun branchingIndetermineFlow(/*0*/ a: kotlin.Any?): kotlin.Unit
public fun funWithUnknownInvocations(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
public fun multipleAssignments(): kotlin.Unit
public fun myRepeat(/*0*/ n: kotlin.Int, /*1*/ action: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(action, UNKNOWN)
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun nestedIndefiniteAssignment(): kotlin.Unit
public fun nonAnonymousLambdas(): kotlin.Unit
public final class InitializationForbiddenInNonInitSection {
public constructor InitializationForbiddenInNonInitSection()
public final val x: kotlin.Int
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 final fun setup(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,41 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun definiteVarInitialization() {
var x: Int
myRun { x = 42 }
x.inc()
}
fun definiteVarReassignment() {
var x: Int
myRun { x = 42 }
x.inc()
myRun { x = 43 }
x.inc()
x = 44
x.inc()
}
fun nestedVarInitialization() {
var x: Int
myRun { myRun { myRun { x = 42 } } }
x.inc()
myRun { myRun { myRun { x = 42 } } }
}
fun notAnExpression() {
var x: Int = 0
myRun { if (true) x = 42 }
x.inc()
}
@@ -0,0 +1,9 @@
package
public fun definiteVarInitialization(): kotlin.Unit
public fun definiteVarReassignment(): kotlin.Unit
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun nestedVarInitialization(): kotlin.Unit
public fun notAnExpression(): kotlin.Unit
@@ -0,0 +1,50 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> myRun(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
fun indefiniteVarReassignment(n: Int) {
var x: Int
repeat(n) {
myRun { x = 42 }
}
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun nonAnonymousLambdas() {
// Named lambdas are not inlined, even in theory it could be done for some simple cases as this one
var x: Int
val initializer = { x = 42 }
myRun(initializer)
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun branchingIndetermineFlow(a: Any) {
var x: Int
if (a is String) {
repeat(<!DEBUG_INFO_SMARTCAST!>a<!>.length) {
myRun { x = 42 }
}
}
else {
myRun { x = 43 }
}
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun funWithUnknownInvocations(block: () -> Unit) = block()
fun nestedIndefiniteAssignment() {
val x: Int
funWithUnknownInvocations { myRun { <!CAPTURED_VAL_INITIALIZATION!>x<!> = 42 } }
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
@@ -0,0 +1,10 @@
package
public fun branchingIndetermineFlow(/*0*/ a: kotlin.Any): kotlin.Unit
public fun funWithUnknownInvocations(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
public fun indefiniteVarReassignment(/*0*/ n: kotlin.Int): kotlin.Unit
public fun </*0*/ T> myRun(/*0*/ block: () -> T): T
CallsInPlace(block, EXACTLY_ONCE)
public fun nestedIndefiniteAssignment(): kotlin.Unit
public fun nonAnonymousLambdas(): kotlin.Unit
@@ -0,0 +1,27 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T, R> T.myLet(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
fun initializationWithReceiver(y: String) {
val x: Int
y.myLet { x = 42 }
x.inc()
}
fun initializationWithSafeCall(y: String?) {
val x: Int
y?.myLet { x = 42 }
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
fun sanityCheck(x: Int, y: String): Int {
y.let { return x }
}
@@ -0,0 +1,8 @@
package
public fun initializationWithReceiver(/*0*/ y: kotlin.String): kotlin.Unit
public fun initializationWithSafeCall(/*0*/ y: kotlin.String?): kotlin.Unit
public fun sanityCheck(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String): kotlin.Int
public fun </*0*/ T, /*1*/ R> T.myLet(/*0*/ block: (T) -> R): R
CallsInPlace(block, EXACTLY_ONCE)
@@ -0,0 +1,17 @@
// !LANGUAGE: +CallsInPlaceEffect
// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER
import kotlin.internal.contracts.*
fun <T> inPlace(block: () -> T): T {
contract {
callsInPlace(block)
}
return block()
}
fun reassignmentAndNoInitializaiton() {
val x: Int
inPlace { <!VAL_REASSIGNMENT!>x<!> = 42 }
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
}
@@ -0,0 +1,6 @@
package
public fun </*0*/ T> inPlace(/*0*/ block: () -> T): T
CallsInPlace(block, UNKNOWN)
public fun reassignmentAndNoInitializaiton(): kotlin.Unit