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,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)