diff --git a/build.xml b/build.xml index 0ee4aea0164..585da896cb8 100644 --- a/build.xml +++ b/build.xml @@ -1022,6 +1022,9 @@ + + + diff --git a/libraries/kotlin.test/common/src/main/kotlin/kotlin/test/Assertions.kt b/libraries/kotlin.test/common/src/main/kotlin/kotlin/test/Assertions.kt index 3c104fb9126..b942ff92627 100644 --- a/libraries/kotlin.test/common/src/main/kotlin/kotlin/test/Assertions.kt +++ b/libraries/kotlin.test/common/src/main/kotlin/kotlin/test/Assertions.kt @@ -24,6 +24,7 @@ package kotlin.test import kotlin.internal.* +import kotlin.internal.contracts.* import kotlin.reflect.KClass /** @@ -40,6 +41,7 @@ fun assertTrue(message: String? = null, block: () -> Boolean): Unit = assertTrue /** Asserts that the expression is `true` with an optional [message]. */ fun assertTrue(actual: Boolean, message: String? = null) { + contract { returns() implies actual } return asserter.assertTrue(message ?: "Expected value to be true.", actual) } @@ -48,6 +50,7 @@ fun assertFalse(message: String? = null, block: () -> Boolean): Unit = assertFal /** Asserts that the expression is `false` with an optional [message]. */ fun assertFalse(actual: Boolean, message: String? = null) { + contract { returns() implies (!actual) } return asserter.assertTrue(message ?: "Expected value to be false.", !actual) } @@ -63,12 +66,14 @@ fun <@OnlyInputTypes T> assertNotEquals(illegal: T, actual: T, message: String? /** Asserts that the [actual] value is not `null`, with an optional [message]. */ fun assertNotNull(actual: T?, message: String? = null): T { + contract { returns() implies (actual != null) } asserter.assertNotNull(message, actual) return actual!! } /** Asserts that the [actual] value is not `null`, with an optional [message] and a function [block] to process the not-null value. */ fun assertNotNull(actual: T?, message: String? = null, block: (T) -> R) { + contract { returns() implies (actual != null) } asserter.assertNotNull(message, actual) if (actual != null) { block(actual) diff --git a/libraries/stdlib/src/kotlin/text/Strings.kt b/libraries/stdlib/src/kotlin/text/Strings.kt index 1b8d1f57d34..2a94223f400 100644 --- a/libraries/stdlib/src/kotlin/text/Strings.kt +++ b/libraries/stdlib/src/kotlin/text/Strings.kt @@ -21,6 +21,7 @@ package kotlin.text import kotlin.comparisons.* +import kotlin.internal.contracts.* /** @@ -225,7 +226,13 @@ public fun String.padEnd(length: Int, padChar: Char = ' '): String * Returns `true` if this nullable char sequence is either `null` or empty. */ @kotlin.internal.InlineOnly -public inline fun CharSequence?.isNullOrEmpty(): Boolean = this == null || this.length == 0 +public inline fun CharSequence?.isNullOrEmpty(): Boolean { + contract { + returns(false) implies (this@isNullOrEmpty != null) + } + + return this == null || this.length == 0 +} /** * Returns `true` if this char sequence is empty (contains no characters). @@ -253,7 +260,13 @@ public inline fun CharSequence.isNotBlank(): Boolean = !isBlank() * Returns `true` if this nullable char sequence is either `null` or empty or consists solely of whitespace characters. */ @kotlin.internal.InlineOnly -public inline fun CharSequence?.isNullOrBlank(): Boolean = this == null || this.isBlank() +public inline fun CharSequence?.isNullOrBlank(): Boolean { + contract { + returns(false) implies (this@isNullOrBlank != null) + } + + return this == null || this.isBlank() +} /** * Iterator for characters of the given char sequence. diff --git a/libraries/stdlib/src/kotlin/util/Preconditions.kt b/libraries/stdlib/src/kotlin/util/Preconditions.kt index 7ae8d724907..7aabd40aa87 100644 --- a/libraries/stdlib/src/kotlin/util/Preconditions.kt +++ b/libraries/stdlib/src/kotlin/util/Preconditions.kt @@ -2,13 +2,20 @@ @file:kotlin.jvm.JvmName("PreconditionsKt") package kotlin +import kotlin.internal.contracts.* + /** * Throws an [IllegalArgumentException] if the [value] is false. * * @sample samples.misc.Preconditions.failRequireWithLazyMessage */ @kotlin.internal.InlineOnly -public inline fun require(value: Boolean): Unit = require(value) { "Failed requirement." } +public inline fun require(value: Boolean): Unit { + contract { + returns() implies value + } + require(value) { "Failed requirement." } +} /** * Throws an [IllegalArgumentException] with the result of calling [lazyMessage] if the [value] is false. @@ -17,6 +24,9 @@ public inline fun require(value: Boolean): Unit = require(value) { "Failed requi */ @kotlin.internal.InlineOnly public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit { + contract { + returns() implies value + } if (!value) { val message = lazyMessage() throw IllegalArgumentException(message.toString()) @@ -27,7 +37,12 @@ public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit { * Throws an [IllegalArgumentException] if the [value] is null. Otherwise returns the not null value. */ @kotlin.internal.InlineOnly -public inline fun requireNotNull(value: T?): T = requireNotNull(value) { "Required value was null." } +public inline fun requireNotNull(value: T?): T { + contract { + returns() implies (value != null) + } + return requireNotNull(value) { "Required value was null." } +} /** * Throws an [IllegalArgumentException] with the result of calling [lazyMessage] if the [value] is null. Otherwise @@ -37,6 +52,10 @@ public inline fun requireNotNull(value: T?): T = requireNotNull(value) { */ @kotlin.internal.InlineOnly public inline fun requireNotNull(value: T?, lazyMessage: () -> Any): T { + contract { + returns() implies (value != null) + } + if (value == null) { val message = lazyMessage() throw IllegalArgumentException(message.toString()) @@ -51,7 +70,12 @@ public inline fun requireNotNull(value: T?, lazyMessage: () -> Any): T { * @sample samples.misc.Preconditions.failCheckWithLazyMessage */ @kotlin.internal.InlineOnly -public inline fun check(value: Boolean): Unit = check(value) { "Check failed." } +public inline fun check(value: Boolean): Unit { + contract { + returns() implies value + } + check(value) { "Check failed." } +} /** * Throws an [IllegalStateException] with the result of calling [lazyMessage] if the [value] is false. @@ -60,6 +84,9 @@ public inline fun check(value: Boolean): Unit = check(value) { "Check failed." } */ @kotlin.internal.InlineOnly public inline fun check(value: Boolean, lazyMessage: () -> Any): Unit { + contract { + returns() implies value + } if (!value) { val message = lazyMessage() throw IllegalStateException(message.toString()) @@ -83,6 +110,10 @@ public inline fun checkNotNull(value: T?): T = checkNotNull(value) { "Re */ @kotlin.internal.InlineOnly public inline fun checkNotNull(value: T?, lazyMessage: () -> Any): T { + contract { + returns() implies (value != null) + } + if (value == null) { val message = lazyMessage() throw IllegalStateException(message.toString()) diff --git a/libraries/stdlib/src/kotlin/util/Standard.kt b/libraries/stdlib/src/kotlin/util/Standard.kt index e524197ebab..98421de1651 100644 --- a/libraries/stdlib/src/kotlin/util/Standard.kt +++ b/libraries/stdlib/src/kotlin/util/Standard.kt @@ -2,6 +2,8 @@ @file:kotlin.jvm.JvmName("StandardKt") package kotlin +import kotlin.internal.contracts.* + /** * An exception is thrown to indicate that a method body remains to be implemented. */ @@ -28,52 +30,91 @@ public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An * Calls the specified function [block] and returns its result. */ @kotlin.internal.InlineOnly -public inline fun run(block: () -> R): R = block() +public inline fun run(block: () -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block() +} /** * Calls the specified function [block] with `this` value as its receiver and returns its result. */ @kotlin.internal.InlineOnly -public inline fun T.run(block: T.() -> R): R = block() +public inline fun T.run(block: T.() -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block() +} /** * Calls the specified function [block] with the given [receiver] as its receiver and returns its result. */ @kotlin.internal.InlineOnly -public inline fun with(receiver: T, block: T.() -> R): R = receiver.block() +public inline fun with(receiver: T, block: T.() -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return receiver.block() +} /** * Calls the specified function [block] with `this` value as its receiver and returns `this` value. */ @kotlin.internal.InlineOnly -public inline fun T.apply(block: T.() -> Unit): T { block(); return this } +public inline fun T.apply(block: T.() -> Unit): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + return this +} /** * Calls the specified function [block] with `this` value as its argument and returns `this` value. */ @kotlin.internal.InlineOnly @SinceKotlin("1.1") -public inline fun T.also(block: (T) -> Unit): T { block(this); return this } +public inline fun T.also(block: (T) -> Unit): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block(this) + return this +} /** * Calls the specified function [block] with `this` value as its argument and returns its result. */ @kotlin.internal.InlineOnly -public inline fun T.let(block: (T) -> R): R = block(this) +public inline fun T.let(block: (T) -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block(this) +} /** * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't. */ @kotlin.internal.InlineOnly @SinceKotlin("1.1") -public inline fun T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null +public inline fun T.takeIf(predicate: (T) -> Boolean): T? { + contract { + callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) + } + return if (predicate(this)) this else null +} /** * Returns `this` value if it _does not_ satisfy the given [predicate] or `null`, if it does. */ @kotlin.internal.InlineOnly @SinceKotlin("1.1") -public inline fun T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null +public inline fun T.takeUnless(predicate: (T) -> Boolean): T? { + return if (!predicate(this)) this else null +} /** * Executes the given function [action] specified number of [times]. @@ -82,7 +123,9 @@ public inline fun T.takeUnless(predicate: (T) -> Boolean): T? = if (!predica */ @kotlin.internal.InlineOnly public inline fun repeat(times: Int, action: (Int) -> Unit) { - for (index in 0 until times) { + contract { callsInPlace(action) } + + for (index in 0..times - 1) { action(index) } } diff --git a/prepare/mock-runtime-for-test/build.gradle.kts b/prepare/mock-runtime-for-test/build.gradle.kts index 6e4ee448696..d04024e2c40 100644 --- a/prepare/mock-runtime-for-test/build.gradle.kts +++ b/prepare/mock-runtime-for-test/build.gradle.kts @@ -36,7 +36,9 @@ val copySources by task { .include("kotlin/collections/TypeAliases.kt", "kotlin/jvm/JvmVersion.kt", "kotlin/util/Standard.kt", - "kotlin/internal/Annotations.kt") + "kotlin/internal/Annotations.kt", + "kotlin/internal/contracts/ContractBuilder.kt", + "kotlin/internal/contracts/Effect.kt") into(File(buildDir, "src")) }