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:
+50
@@ -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()
|
||||
}
|
||||
+7
@@ -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
|
||||
+97
@@ -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: {}
|
||||
=====================
|
||||
Vendored
+17
@@ -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)
|
||||
}
|
||||
Vendored
+5
@@ -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)
|
||||
+19
@@ -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) }
|
||||
}
|
||||
+7
@@ -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)
|
||||
+16
@@ -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<!>
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package
|
||||
|
||||
public inline fun myRun(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
|
||||
CallsInPlace(block, EXACTLY_ONCE)
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
+22
@@ -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)
|
||||
}
|
||||
+7
@@ -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
|
||||
Vendored
+85
@@ -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()
|
||||
}
|
||||
Vendored
+13
@@ -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)
|
||||
|
||||
+97
@@ -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()
|
||||
}
|
||||
+11
@@ -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
|
||||
Vendored
+46
@@ -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()
|
||||
}
|
||||
compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchs.txt
Vendored
+8
@@ -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
|
||||
Vendored
+17
@@ -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()
|
||||
}
|
||||
Vendored
+5
@@ -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)
|
||||
+33
@@ -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)
|
||||
}
|
||||
+8
@@ -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
|
||||
+78
@@ -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
|
||||
}
|
||||
+8
@@ -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
|
||||
compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/throwIfNotCalled.kt
Vendored
+47
@@ -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<!>)
|
||||
}
|
||||
+8
@@ -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
|
||||
Vendored
+57
@@ -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()
|
||||
}
|
||||
}
|
||||
Vendored
+9
@@ -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
|
||||
Vendored
+33
@@ -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()
|
||||
}
|
||||
compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/tryCatchFinally.txt
Vendored
+8
@@ -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
|
||||
Vendored
+18
@@ -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
|
||||
}
|
||||
Vendored
+7
@@ -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
|
||||
Vendored
+16
@@ -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<!>
|
||||
}
|
||||
compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/unreachableCode.txt
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
package
|
||||
|
||||
public inline fun </*0*/ T> myRun(/*0*/ block: () -> T): T
|
||||
CallsInPlace(block, EXACTLY_ONCE)
|
||||
|
||||
public fun throwInLambda(): kotlin.Int
|
||||
Reference in New Issue
Block a user