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:
+91
@@ -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 }
|
||||
}
|
||||
}
|
||||
+21
@@ -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
|
||||
}
|
||||
+27
@@ -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()
|
||||
}
|
||||
|
||||
+7
@@ -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
|
||||
+67
@@ -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 }
|
||||
}
|
||||
}
|
||||
+22
@@ -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
|
||||
}
|
||||
+41
@@ -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()
|
||||
}
|
||||
+9
@@ -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
|
||||
+50
@@ -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()
|
||||
}
|
||||
+10
@@ -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
|
||||
+27
@@ -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 }
|
||||
}
|
||||
+8
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user