diff --git a/compiler/resolution/src/org/jetbrains/kotlin/contracts/description/ContractDescriptionRenderer.kt b/compiler/resolution/src/org/jetbrains/kotlin/contracts/description/ContractDescriptionRenderer.kt new file mode 100644 index 00000000000..b2d06945c33 --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/contracts/description/ContractDescriptionRenderer.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.contracts.description + +import org.jetbrains.kotlin.contracts.description.expressions.* + +class ContractDescriptionRenderer(private val builder: StringBuilder) : ContractDescriptionVisitor { + override fun visitConditionalEffectDeclaration(conditionalEffect: ConditionalEffectDeclaration, data: Unit) { + conditionalEffect.effect.accept(this, data) + builder.append(" -> ") + conditionalEffect.condition.accept(this, data) + } + + override fun visitReturnsEffectDeclaration(returnsEffect: ReturnsEffectDeclaration, data: Unit) { + builder.append("Returns(") + returnsEffect.value.accept(this, data) + builder.append(")") + } + + override fun visitCallsEffectDeclaration(callsEffect: CallsEffectDeclaration, data: Unit) { + builder.append("CallsInPlace(") + callsEffect.variableReference.accept(this, data) + builder.append(", ${callsEffect.kind})") + + } + + override fun visitLogicalOr(logicalOr: LogicalOr, data: Unit) { + inBracketsIfNecessary(logicalOr, logicalOr.left) { logicalOr.left.accept(this, data) } + builder.append(" || ") + inBracketsIfNecessary(logicalOr, logicalOr.right) { logicalOr.right.accept(this, data) } + } + + override fun visitLogicalAnd(logicalAnd: LogicalAnd, data: Unit) { + inBracketsIfNecessary(logicalAnd, logicalAnd.left) { logicalAnd.left.accept(this, data) } + builder.append(" && ") + inBracketsIfNecessary(logicalAnd, logicalAnd.right) { logicalAnd.right.accept(this, data) } + } + + override fun visitLogicalNot(logicalNot: LogicalNot, data: Unit) { + inBracketsIfNecessary(logicalNot, logicalNot.arg) { builder.append("!") } + logicalNot.arg.accept(this, data) + } + + override fun visitIsInstancePredicate(isInstancePredicate: IsInstancePredicate, data: Unit) { + isInstancePredicate.arg.accept(this, data) + builder.append(" ${if (isInstancePredicate.isNegated) "!" else ""}is ${isInstancePredicate.type}") + } + + override fun visitIsNullPredicate(isNullPredicate: IsNullPredicate, data: Unit) { + isNullPredicate.arg.accept(this, data) + builder.append(" ${if (isNullPredicate.isNegated) "!=" else "=="} null") + } + + override fun visitConstantDescriptor(constantReference: ConstantReference, data: Unit) { + builder.append(constantReference.name) + } + + override fun visitVariableReference(variableReference: VariableReference, data: Unit) { + builder.append(variableReference.descriptor.name) + } + + private fun ContractDescriptionElement.isAtom(): Boolean = + this is VariableReference || this is ConstantReference || this is IsNullPredicate || this is IsInstancePredicate + + private fun needsBrackets(parent: ContractDescriptionElement, child: ContractDescriptionElement): Boolean { + if (child.isAtom()) return false + if (parent is LogicalNot) return true + return parent::class != child::class + } + + private fun inBracketsIfNecessary(parent: ContractDescriptionElement, child: ContractDescriptionElement, block: () -> Unit) { + if (needsBrackets(parent, child)) { + builder.append("(") + block() + builder.append(")") + } + else { + block() + } + } + +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt new file mode 100644 index 00000000000..228d4574fc4 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt @@ -0,0 +1,24 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +fun callsEffectWithKind(block: (X, Y, Z) -> R) { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } +} + +inline fun callsEffectImplicitUnknown(x: Int, y: Int, block: () -> Unit) { + contract { + callsInPlace(block) + } +} + +inline fun callsEffectExplicitUnknown(x: Int, block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.UNKNOWN) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.txt new file mode 100644 index 00000000000..3530cdddc0f --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.txt @@ -0,0 +1,10 @@ +package test + +public inline fun callsEffectExplicitUnknown(/*0*/ x: kotlin.Int, /*1*/ block: () -> kotlin.Unit): kotlin.Unit + CallsInPlace(block, UNKNOWN) + +public inline fun callsEffectImplicitUnknown(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int, /*2*/ block: () -> kotlin.Unit): kotlin.Unit + CallsInPlace(block, UNKNOWN) + +public fun callsEffectWithKind(/*0*/ block: (X, Y, Z) -> R): kotlin.Unit + CallsInPlace(block, EXACTLY_ONCE) diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.kt new file mode 100644 index 00000000000..ffe5442dfbf --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.kt @@ -0,0 +1,14 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +class A + +fun deeplyNested(x: Any?, y: Any?, b: Boolean, s: String?) { + contract { + returns(true) implies (((x is Int && x is String) || (x is Int && y is A) || b || (!b)) && s != null && (y is A || x is String)) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.txt new file mode 100644 index 00000000000..0d10b7301df --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.txt @@ -0,0 +1,8 @@ +package test + +public fun deeplyNested(/*0*/ x: kotlin.Any?, /*1*/ y: kotlin.Any?, /*2*/ b: kotlin.Boolean, /*3*/ s: kotlin.String?): kotlin.Unit + Returns(TRUE) -> ((x is Int && x is String) || (x is Int && y is A) || b || (!b)) && s != null && (y is A || x is String) + +public final class A { + /*primary*/ public constructor A() +} diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.kt new file mode 100644 index 00000000000..3ac48df3889 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.kt @@ -0,0 +1,33 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +// this tests specifically use primitive condition (predicate/value) as the +// first argument of sequence, so that it would be optimized and embedded into message + +fun embedVariable(x: Any, b: Boolean) { + contract { + returns() implies (b && x is String) + } +} + +fun embedInstancePredicate(x: Any, y: Any?) { + contract { + returns() implies (x is String && y is String) + } +} + +fun embedNullCheckPredicate(x: Any?, y: Int?) { + contract { + returns() implies (y != null && x is String) + } +} + +fun Boolean.embedReceiverReference(b: Boolean) { + contract { + returns() implies (!this@embedReceiverReference && b) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.txt new file mode 100644 index 00000000000..3ba33868817 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.txt @@ -0,0 +1,13 @@ +package test + +public fun embedInstancePredicate(/*0*/ x: kotlin.Any, /*1*/ y: kotlin.Any?): kotlin.Unit + Returns(WILDCARD) -> x is String && y is String + +public fun embedNullCheckPredicate(/*0*/ x: kotlin.Any?, /*1*/ y: kotlin.Int?): kotlin.Unit + Returns(WILDCARD) -> y != null && x is String + +public fun embedVariable(/*0*/ x: kotlin.Any, /*1*/ b: kotlin.Boolean): kotlin.Unit + Returns(WILDCARD) -> b && x is String + +public fun kotlin.Boolean.embedReceiverReference(/*0*/ b: kotlin.Boolean): kotlin.Unit + Returns(WILDCARD) -> (!) && b diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.kt new file mode 100644 index 00000000000..64117949f82 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.kt @@ -0,0 +1,65 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +public inline fun run(block: () -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block() +} + +public inline fun T.run(block: T.() -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block() +} + +public inline fun with(receiver: T, block: T.() -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return receiver.block() +} + +public inline fun T.apply(block: T.() -> Unit): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + return this +} + +public inline fun T.also(block: (T) -> Unit): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block(this) + return this +} + +public inline fun T.let(block: (T) -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block(this) +} + +public inline fun T.takeIf(predicate: (T) -> Boolean): T? { + contract { + callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) + } + return if (predicate(this)) this else null +} + +public inline fun repeat(times: Int, action: (Int) -> Unit) { + contract { callsInPlace(action) } + + for (index in 0..times - 1) { + action(index) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.txt new file mode 100644 index 00000000000..969c14512c9 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.txt @@ -0,0 +1,25 @@ +package test + +public inline fun repeat(/*0*/ times: kotlin.Int, /*1*/ action: (kotlin.Int) -> kotlin.Unit): kotlin.Unit + CallsInPlace(action, UNKNOWN) + +public inline fun run(/*0*/ block: () -> R): R + CallsInPlace(block, EXACTLY_ONCE) + +public inline fun with(/*0*/ receiver: T, /*1*/ block: T.() -> R): R + CallsInPlace(block, EXACTLY_ONCE) + +public inline fun T.also(/*0*/ block: (T) -> kotlin.Unit): T + CallsInPlace(block, EXACTLY_ONCE) + +public inline fun T.apply(/*0*/ block: T.() -> kotlin.Unit): T + CallsInPlace(block, EXACTLY_ONCE) + +public inline fun T.let(/*0*/ block: (T) -> R): R + CallsInPlace(block, EXACTLY_ONCE) + +public inline fun T.run(/*0*/ block: T.() -> R): R + CallsInPlace(block, EXACTLY_ONCE) + +public inline fun T.takeIf(/*0*/ predicate: (T) -> kotlin.Boolean): T? + CallsInPlace(predicate, EXACTLY_ONCE) diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.kt new file mode 100644 index 00000000000..7e180ab0833 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.kt @@ -0,0 +1,20 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +class A + +fun simpleIsInstace(x: Any?) { + contract { + returns(true) implies (x is A) + } +} + +fun Any?.receiverIsInstance() { + contract { + returns(true) implies (this@receiverIsInstance is A) + } +} diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.txt new file mode 100644 index 00000000000..9b5255b92c5 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.txt @@ -0,0 +1,11 @@ +package test + +public fun simpleIsInstace(/*0*/ x: kotlin.Any?): kotlin.Unit + Returns(TRUE) -> x is A + +public fun kotlin.Any?.receiverIsInstance(): kotlin.Unit + Returns(TRUE) -> is A + +public final class A { + /*primary*/ public constructor A() +} diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.kt new file mode 100644 index 00000000000..e8abe05a162 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.kt @@ -0,0 +1,22 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + + +fun orSequence(x: Any?, y: Any?, b: Boolean) { + contract { + returns() implies (x is String || y is Int || !b) + } +} + +class A +class B + +fun andSequence(x: Any?, y: Any?, b:Boolean) { + contract { + returns() implies (x is A && x is B && ((y is A) && b)) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.txt new file mode 100644 index 00000000000..376477ae99f --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.txt @@ -0,0 +1,15 @@ +package test + +public fun andSequence(/*0*/ x: kotlin.Any?, /*1*/ y: kotlin.Any?, /*2*/ b: kotlin.Boolean): kotlin.Unit + Returns(WILDCARD) -> x is A && x is B && y is A && b + +public fun orSequence(/*0*/ x: kotlin.Any?, /*1*/ y: kotlin.Any?, /*2*/ b: kotlin.Boolean): kotlin.Unit + Returns(WILDCARD) -> x is String || y is Int || (!b) + +public final class A { + /*primary*/ public constructor A() +} + +public final class B { + /*primary*/ public constructor B() +} diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.kt new file mode 100644 index 00000000000..53c7d2d1bfc --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.kt @@ -0,0 +1,44 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +fun twoReturnsValue(b: Boolean) { + contract { + returns(true) implies b + returns(false) implies (!b) + } +} + +fun threeReturnsValue(b: Boolean) { + contract { + returnsNotNull() implies (b != null) + returns(true) implies (b) + returns(false) implies (!b) + } +} + +fun returnsAndFinished(b: Boolean) { + contract { + returns(true) implies (b) + returns() implies (b != null) + returns(false) implies (!b) + } +} + +fun returnsAndCalls(b: Boolean, block: () -> Unit) { + contract { + returns(false) implies (!b) + callsInPlace(block) + returns(true) implies (b) + } +} + +fun severalCalls(x: () -> Unit, y: () -> Unit) { + contract { + callsInPlace(x, InvocationKind.AT_MOST_ONCE) + callsInPlace(y, InvocationKind.AT_LEAST_ONCE) + } +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.txt new file mode 100644 index 00000000000..13de325fe50 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.txt @@ -0,0 +1,24 @@ +package test + +public fun returnsAndCalls(/*0*/ b: kotlin.Boolean, /*1*/ block: () -> kotlin.Unit): kotlin.Unit + Returns(FALSE) -> !b + CallsInPlace(block, UNKNOWN) + Returns(TRUE) -> b + +public fun returnsAndFinished(/*0*/ b: kotlin.Boolean): kotlin.Unit + Returns(TRUE) -> b + Returns(WILDCARD) -> b != null + Returns(FALSE) -> !b + +public fun severalCalls(/*0*/ x: () -> kotlin.Unit, /*1*/ y: () -> kotlin.Unit): kotlin.Unit + CallsInPlace(x, AT_MOST_ONCE) + CallsInPlace(y, AT_LEAST_ONCE) + +public fun threeReturnsValue(/*0*/ b: kotlin.Boolean): kotlin.Unit + Returns(NOT_NULL) -> b != null + Returns(TRUE) -> b + Returns(FALSE) -> !b + +public fun twoReturnsValue(/*0*/ b: kotlin.Boolean): kotlin.Unit + Returns(TRUE) -> b + Returns(FALSE) -> !b diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.kt new file mode 100644 index 00000000000..6e4da68abc4 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.kt @@ -0,0 +1,20 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +fun foo(x: Any?): Boolean { + contract { + returns() implies (x is String) + } + return bar(x) +} + +fun bar(x: Any?): Boolean { + contract { + returns() implies (x is Int) + } + return foo(x) +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.txt new file mode 100644 index 00000000000..7c1f98ac7ab --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.txt @@ -0,0 +1,8 @@ +package test + +public fun bar(/*0*/ x: kotlin.Any?): kotlin.Boolean + Returns(WILDCARD) -> x is Int + +public fun foo(/*0*/ x: kotlin.Any?): kotlin.Boolean + Returns(WILDCARD) -> x is String + diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.kt new file mode 100644 index 00000000000..dd069883158 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.kt @@ -0,0 +1,13 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +fun foo(n: Int, x: Any?): Boolean { + contract { + returns(true) implies (x is String) + } + return if (n == 0) x is String else foo(n - 1, x) +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.txt new file mode 100644 index 00000000000..12e60a86f42 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.txt @@ -0,0 +1,4 @@ +package test + +public fun foo(/*0*/ n: kotlin.Int, /*1*/ x: kotlin.Any?): kotlin.Boolean + Returns(TRUE) -> x is String diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.kt new file mode 100644 index 00000000000..16915e146c8 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.kt @@ -0,0 +1,13 @@ +// LANGUAGE_VERSION: 1.3 +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package test + +import kotlin.internal.contracts.* + +fun Any?.isNotNull(): Boolean { + contract { + returns(true) implies (this@isNotNull != null) + } + return this != null +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.txt new file mode 100644 index 00000000000..05604868dc7 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.txt @@ -0,0 +1,5 @@ +package test + +public fun kotlin.Any?.isNotNull(): kotlin.Boolean + Returns(TRUE) -> != null + diff --git a/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/AbstractLoadJavaTest.java b/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/AbstractLoadJavaTest.java index c46bf64dd6e..f5d6fa7cb6d 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/AbstractLoadJavaTest.java +++ b/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/AbstractLoadJavaTest.java @@ -26,9 +26,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM; import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt; -import org.jetbrains.kotlin.config.CompilerConfiguration; -import org.jetbrains.kotlin.config.ContentRootsKt; -import org.jetbrains.kotlin.config.JVMConfigurationKeys; +import org.jetbrains.kotlin.config.*; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.ModuleDescriptor; @@ -120,6 +118,8 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { if (useTypeTableInSerializer) { configuration.put(JVMConfigurationKeys.USE_TYPE_TABLE, true); } + updateConfigurationWithLanguageVersionDirective(ktFile, configuration); + KotlinCoreEnvironment environment = KotlinCoreEnvironment.createForTests(getTestRootDisposable(), configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); registerJavacIfNeeded(environment); @@ -129,7 +129,8 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { Assert.assertEquals("test", packageFromSource.getName().asString()); PackageViewDescriptor packageFromBinary = LoadDescriptorUtil.loadTestPackageAndBindingContextFromJavaRoot( - tmpdir, getTestRootDisposable(), getJdkKind(), configurationKind, true, false, useJavacWrapper() + tmpdir, getTestRootDisposable(), getJdkKind(), configurationKind, true, false, useJavacWrapper(), + configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS) ).first; for (DeclarationDescriptor descriptor : DescriptorUtils.getAllDescriptors(packageFromBinary.getMemberScope())) { @@ -140,10 +141,21 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { DescriptorValidator.validate(errorTypesForbidden(), packageFromSource); DescriptorValidator.validate(new DeserializedScopeValidationVisitor(), packageFromBinary); - Configuration comparatorConfiguration = COMPARATOR_CONFIGURATION.checkPrimaryConstructors(true).checkPropertyAccessors(true); + Configuration comparatorConfiguration = COMPARATOR_CONFIGURATION.checkPrimaryConstructors(true).checkPropertyAccessors(true).checkFunctionContracts(true); compareDescriptors(packageFromSource, packageFromBinary, comparatorConfiguration, txtFile); } + private static void updateConfigurationWithLanguageVersionDirective(File file, CompilerConfiguration configuration) throws IOException { + String version = InTextDirectivesUtils.findStringWithPrefixes(FileUtil.loadFile(file, true), "// LANGUAGE_VERSION:"); + if (version != null) { + LanguageVersion explicitVersion = LanguageVersion.fromVersionString(version); + CommonConfigurationKeysKt.setLanguageVersionSettings( + configuration, + new LanguageVersionSettingsImpl(explicitVersion, ApiVersion.createByLanguageVersion(explicitVersion)) + ); + } + } + protected boolean useFastClassFilesReading() { return false; } @@ -222,7 +234,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { Pair javaPackageAndContext = loadTestPackageAndBindingContextFromJavaRoot( tmpdir, getTestRootDisposable(), getJdkKind(), ConfigurationKind.JDK_ONLY, false, - false, useJavacWrapper()); + false, useJavacWrapper(), null); checkJavaPackage( expectedFile, javaPackageAndContext.first, javaPackageAndContext.second, @@ -267,7 +279,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { ) throws IOException { compileJavaWithAnnotationsJar(javaFiles, outDir); return loadTestPackageAndBindingContextFromJavaRoot(outDir, myTestRootDisposable, getJdkKind(), configurationKind, true, - useFastClassFilesReading(), useJavacWrapper()); + useFastClassFilesReading(), useJavacWrapper(), null); } private static void checkJavaPackage( diff --git a/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/LoadDescriptorUtil.java b/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/LoadDescriptorUtil.java index 72e9d2ad428..7b6d8e3d908 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/LoadDescriptorUtil.java +++ b/compiler/tests-common/org/jetbrains/kotlin/jvm/compiler/LoadDescriptorUtil.java @@ -25,6 +25,7 @@ import kotlin.io.FilesKt; import kotlin.sequences.SequencesKt; import kotlin.text.Charsets; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; @@ -32,8 +33,10 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.codegen.GenerationUtils; import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.kotlin.codegen.state.GenerationState; +import org.jetbrains.kotlin.config.CommonConfigurationKeys; import org.jetbrains.kotlin.config.CompilerConfiguration; import org.jetbrains.kotlin.config.JVMConfigurationKeys; +import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.descriptors.ModuleDescriptor; import org.jetbrains.kotlin.descriptors.PackageViewDescriptor; import org.jetbrains.kotlin.jvm.compiler.javac.JavacRegistrarForTests; @@ -80,7 +83,8 @@ public class LoadDescriptorUtil { @NotNull ConfigurationKind configurationKind, boolean isBinaryRoot, boolean useFastClassReading, - boolean useJavacWrapper + boolean useJavacWrapper, + @Nullable LanguageVersionSettings explicitLanguageVersionSettings ) { List javaBinaryRoots = new ArrayList<>(); javaBinaryRoots.add(KotlinTestUtils.getAnnotationsJar()); @@ -97,6 +101,9 @@ public class LoadDescriptorUtil { KotlinTestUtils.newConfiguration(configurationKind, testJdkKind, javaBinaryRoots, javaSourceRoots); configuration.put(JVMConfigurationKeys.USE_FAST_CLASS_FILES_READING, useFastClassReading); configuration.put(JVMConfigurationKeys.USE_JAVAC, useJavacWrapper); + if (explicitLanguageVersionSettings != null) { + configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, explicitLanguageVersionSettings); + } KotlinCoreEnvironment environment = KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); if (useJavacWrapper) { diff --git a/compiler/tests-common/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt b/compiler/tests-common/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt index 5f99fe69926..3720e9616f6 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/jvm/runtime/AbstractJvmRuntimeDescriptorLoaderTest.kt @@ -97,6 +97,7 @@ abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() { /* checkPropertyAccessors = */ true, /* includeMethodsOfKotlinAny = */ false, /* renderDeclarationsFromOtherModules = */ true, + /* checkFunctionContract = */ false, // Skip Java annotation constructors because order of their parameters is not retained at runtime { descriptor -> !descriptor!!.isJavaAnnotationConstructor() }, errorTypesForbidden(), renderer @@ -109,7 +110,7 @@ abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() { } val expected = LoadDescriptorUtil.loadTestPackageAndBindingContextFromJavaRoot( - tmpdir, testRootDisposable, jdkKind, ConfigurationKind.ALL, true, false, false + tmpdir, testRootDisposable, jdkKind, ConfigurationKind.ALL, true, false, false, null ).first RecursiveDescriptorComparator.validateAndCompareDescriptors(expected, actual, comparatorConfiguration, null) diff --git a/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorComparator.java b/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorComparator.java index 11bac2ba230..fdd41e8c5e3 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorComparator.java +++ b/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorComparator.java @@ -22,6 +22,7 @@ import kotlin.Unit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.contracts.description.*; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.impl.SubpackagesScope; import org.jetbrains.kotlin.jvm.compiler.ExpectedLoadErrorsUtil; @@ -63,12 +64,12 @@ public class RecursiveDescriptorComparator { ); public static final Configuration DONT_INCLUDE_METHODS_OF_OBJECT = new Configuration(false, false, false, false, - descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER); + false, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER); public static final Configuration RECURSIVE = new Configuration(false, false, true, false, - descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER); + false, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER); public static final Configuration RECURSIVE_ALL = new Configuration(true, true, true, false, - descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER); + true, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER); public static final Predicate SKIP_BUILT_INS_PACKAGES = descriptor -> { if (descriptor instanceof PackageViewDescriptor) { @@ -111,6 +112,11 @@ public class RecursiveDescriptorComparator { boolean isPrimaryConstructor = descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary(); printer.print(isPrimaryConstructor && conf.checkPrimaryConstructors ? "/*primary*/ " : "", conf.renderer.render(descriptor)); + if (descriptor instanceof FunctionDescriptor && conf.checkFunctionContracts) { + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + printEffectsIfAny(functionDescriptor, printer); + } + if (isClassOrPackage) { if (!topLevel) { printer.printlnWithNoIndent(" {").pushIndent(); @@ -171,6 +177,24 @@ public class RecursiveDescriptorComparator { } } + private void printEffectsIfAny(FunctionDescriptor functionDescriptor, Printer printer) { + LazyContractProvider contractProvider = functionDescriptor.getUserData(ContractProviderKey.INSTANCE); + if (contractProvider == null) return; + + ContractDescription contractDescription = contractProvider.getContractDescription(); + if (contractDescription == null || contractDescription.getEffects().isEmpty()) return; + + printer.println(); + printer.pushIndent(); + for (EffectDeclaration effect : contractDescription.getEffects()) { + StringBuilder sb = new StringBuilder(); + ContractDescriptionRenderer renderer = new ContractDescriptionRenderer(sb); + effect.accept(renderer, Unit.INSTANCE); + printer.println(sb.toString()); + } + printer.popIndent(); + } + @NotNull private MemberScope getPackageScopeInModule(@NotNull PackageViewDescriptor descriptor, @NotNull ModuleDescriptor module) { // See LazyPackageViewDescriptorImpl#memberScope @@ -298,6 +322,7 @@ public class RecursiveDescriptorComparator { private final boolean checkPropertyAccessors; private final boolean includeMethodsOfKotlinAny; private final boolean renderDeclarationsFromOtherModules; + private final boolean checkFunctionContracts; private final Predicate recursiveFilter; private final DescriptorRenderer renderer; private final DescriptorValidator.ValidationVisitor validationStrategy; @@ -307,6 +332,7 @@ public class RecursiveDescriptorComparator { boolean checkPropertyAccessors, boolean includeMethodsOfKotlinAny, boolean renderDeclarationsFromOtherModules, + boolean checkFunctionContracts, Predicate recursiveFilter, DescriptorValidator.ValidationVisitor validationStrategy, DescriptorRenderer renderer @@ -315,6 +341,7 @@ public class RecursiveDescriptorComparator { this.checkPropertyAccessors = checkPropertyAccessors; this.includeMethodsOfKotlinAny = includeMethodsOfKotlinAny; this.renderDeclarationsFromOtherModules = renderDeclarationsFromOtherModules; + this.checkFunctionContracts = checkFunctionContracts; this.recursiveFilter = recursiveFilter; this.validationStrategy = validationStrategy; this.renderer = renderer; @@ -322,38 +349,43 @@ public class RecursiveDescriptorComparator { public Configuration filterRecursion(@NotNull Predicate stepIntoFilter) { return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, - renderDeclarationsFromOtherModules, stepIntoFilter, + renderDeclarationsFromOtherModules, checkFunctionContracts, stepIntoFilter, validationStrategy.withStepIntoFilter(stepIntoFilter), renderer); } public Configuration checkPrimaryConstructors(boolean checkPrimaryConstructors) { return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, - renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer); + renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer); } public Configuration checkPropertyAccessors(boolean checkPropertyAccessors) { return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, - renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer); + renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer); + } + + public Configuration checkFunctionContracts(boolean checkFunctionContracts) { + return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, + renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer); } public Configuration includeMethodsOfKotlinAny(boolean includeMethodsOfKotlinAny) { return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, - renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer); + renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer); } public Configuration renderDeclarationsFromOtherModules(boolean renderDeclarationsFromOtherModules) { return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, - renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer); + renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer); } public Configuration withValidationStrategy(@NotNull DescriptorValidator.ValidationVisitor validationStrategy) { return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, - renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer); + renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer); } public Configuration withRenderer(@NotNull DescriptorRenderer renderer) { return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, - renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer); + renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer); } } } diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index a6eaa69d7b7..2957380f002 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -4976,6 +4976,75 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { } } + @TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Contracts extends AbstractLoadJavaTest { + public void testAllFilesPresentInContracts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("callsEffect.kt") + public void testCallsEffect() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("deeplyNestedExpression.kt") + public void testDeeplyNestedExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("embedding.kt") + public void testEmbedding() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("fromStandardKt.kt") + public void testFromStandardKt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("isInstancePredicate.kt") + public void testIsInstancePredicate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("logicOperators.kt") + public void testLogicOperators() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("multieffectContracts.kt") + public void testMultieffectContracts() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("mutualRecursion.kt") + public void testMutualRecursion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("recursion.kt") + public void testRecursion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("withReceiver.kt") + public void testWithReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java index 2791e402eff..518ea5e7376 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java @@ -4976,6 +4976,75 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT } } + @TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Contracts extends AbstractLoadJavaUsingJavacTest { + public void testAllFilesPresentInContracts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("callsEffect.kt") + public void testCallsEffect() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/callsEffect.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("deeplyNestedExpression.kt") + public void testDeeplyNestedExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/deeplyNestedExpression.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("embedding.kt") + public void testEmbedding() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/embedding.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("fromStandardKt.kt") + public void testFromStandardKt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/fromStandardKt.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("isInstancePredicate.kt") + public void testIsInstancePredicate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/isInstancePredicate.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("logicOperators.kt") + public void testLogicOperators() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/logicOperators.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("multieffectContracts.kt") + public void testMultieffectContracts() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/multieffectContracts.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("mutualRecursion.kt") + public void testMutualRecursion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/mutualRecursion.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("recursion.kt") + public void testRecursion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/recursion.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + + @TestMetadata("withReceiver.kt") + public void testWithReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/contracts/withReceiver.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt index 6f84ee01eb7..df71556b348 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt @@ -222,6 +222,7 @@ interface DescriptorRendererOptions { var renderUnabbreviatedType: Boolean var includeAdditionalModifiers: Boolean var parameterNamesInFunctionalTypes: Boolean + var renderFunctionContracts: Boolean } object ExcludedTypeAnnotations { diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt index 8315fa5d017..b45fa9fb5e7 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt @@ -109,4 +109,6 @@ internal class DescriptorRendererOptionsImpl : DescriptorRendererOptions { override var includeAdditionalModifiers: Boolean by property(true) override var parameterNamesInFunctionalTypes: Boolean by property(true) + + override var renderFunctionContracts: Boolean by property(false) }