diff --git a/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectSystem.kt b/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectSystem.kt index 4d0951cc7d8..14af3f26369 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectSystem.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectSystem.kt @@ -132,7 +132,7 @@ class EffectSystem( } private fun getNonTrivialComputation(expression: KtExpression, trace: BindingTrace, moduleDescriptor: ModuleDescriptor): Computation? { - val visitor = EffectsExtractingVisitor(trace, moduleDescriptor, dataFlowValueFactory, constants) + val visitor = EffectsExtractingVisitor(trace, moduleDescriptor, dataFlowValueFactory, constants, languageVersionSettings) return visitor.extractOrGetCached(expression).takeUnless { it == UNKNOWN_COMPUTATION } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.kt index 0b9dfb0b543..a1b2435d951 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/contracts/EffectsExtractingVisitor.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.contracts import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.contracts.description.ContractProviderKey import org.jetbrains.kotlin.contracts.model.Computation import org.jetbrains.kotlin.contracts.model.ConditionalEffect @@ -56,7 +58,8 @@ class EffectsExtractingVisitor( private val trace: BindingTrace, private val moduleDescriptor: ModuleDescriptor, private val dataFlowValueFactory: DataFlowValueFactory, - private val constants: ESConstants + private val constants: ESConstants, + private val languageVersionSettings: LanguageVersionSettings ) : KtVisitor() { private val builtIns: KotlinBuiltIns get() = moduleDescriptor.builtIns @@ -162,7 +165,13 @@ class EffectsExtractingVisitor( private fun ReceiverValue.toComputation(): Computation = when (this) { is ExpressionReceiver -> extractOrGetCached(expression) - is ExtensionReceiver -> ESReceiverWithDataFlowValue(this, createDataFlowValue()) + is ExtensionReceiver -> { + if (languageVersionSettings.supportsFeature(LanguageFeature.ContractsOnCallsWithImplicitReceiver)) { + ESReceiverWithDataFlowValue(this, createDataFlowValue()) + } else { + UNKNOWN_COMPUTATION + } + } else -> UNKNOWN_COMPUTATION } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver.kt index d84019d08ba..f34b254d12c 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver.kt @@ -20,7 +20,7 @@ fun smartcastOnReceiver(s: String?) { length } else { - length + length } } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.kt new file mode 100644 index 00000000000..3e0213fe764 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.kt @@ -0,0 +1,38 @@ +// !LANGUAGE: +AllowContractsForCustomFunctions +UseReturnsEffect +ContractsOnCallsWithImplicitReceiver +// !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts +// !DIAGNOSTICS: -INVISIBLE_REFERENCE -INVISIBLE_MEMBER +// +// ISSUE: KT-28672 + +import kotlin.contracts.* + +fun CharSequence?.isNullOrEmpty(): Boolean { + contract { + returns(false) implies (this@isNullOrEmpty != null) + } + + return this == null || this.length == 0 +} + +fun smartcastOnReceiver(s: String?) { + with(s) { + if (isNullOrEmpty()) { + length + } + else { + length + } + } +} + +fun mixedReceiver(s: String?) { + if (!s.isNullOrEmpty()) { + with(s) { + length + } + } else { + with(s) { + length + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.txt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.txt new file mode 100644 index 00000000000..8605fe32df8 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.txt @@ -0,0 +1,6 @@ +package + +public fun mixedReceiver(/*0*/ s: kotlin.String?): kotlin.Unit +public fun smartcastOnReceiver(/*0*/ s: kotlin.String?): kotlin.Unit +public fun kotlin.CharSequence?.isNullOrEmpty(): kotlin.Boolean + Returns(FALSE) -> != null diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index a913f6217a8..8d730246ec6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -1301,6 +1301,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver.kt"); } + @TestMetadata("extensionReceiver_after.kt") + public void testExtensionReceiver_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.kt"); + } + @TestMetadata("intersectingInfo.kt") public void testIntersectingInfo() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/intersectingInfo.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index 990b63e6031..70a946a7a95 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -1301,6 +1301,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver.kt"); } + @TestMetadata("extensionReceiver_after.kt") + public void testExtensionReceiver_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/extensionReceiver_after.kt"); + } + @TestMetadata("intersectingInfo.kt") public void testIntersectingInfo() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/intersectingInfo.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 0f0da571a48..050ede35d7e 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -121,6 +121,7 @@ enum class LanguageFeature( InlineClasses(sinceVersion = KOTLIN_1_3, defaultState = State.ENABLED_WITH_WARNING, kind = UNSTABLE_FEATURE), + ContractsOnCallsWithImplicitReceiver(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED), ; val presentableName: String