K2: Put boolean DFA variables under a feature flag
^KT-62547 Fixed I also tested the commit by disabling DfaBooleanVariables in all tests and checking what tests will fail I didn't find anything that worked in K1, but doesn't work in K2 with DfaBooleanVariables disabled Related tests: - DiagnosticCompilerTestFirTestdataTestGenerated$Resolve$Smartcasts - LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated$Resolve$Smartcasts - PreFirIdeSpecTestGenerated$NotLinked$Dfa - DiagnosticCompilerTestFE10TestdataTestGenerated$Tests$SmartCasts - FirPsiDiagnosticTestGenerated$Resolve$Expresssions.testSyntheticSmartCast
This commit is contained in:
+6
@@ -34962,6 +34962,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/dataFlowInfoForArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disableDfaBooleanVariables.kt")
|
||||
public void testDisableDfaBooleanVariables() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/disableDfaBooleanVariables.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("doubleLambdaArgument.kt")
|
||||
public void testDoubleLambdaArgument() throws Exception {
|
||||
|
||||
+6
@@ -34962,6 +34962,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/dataFlowInfoForArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disableDfaBooleanVariables.kt")
|
||||
public void testDisableDfaBooleanVariables() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/disableDfaBooleanVariables.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("doubleLambdaArgument.kt")
|
||||
public void testDoubleLambdaArgument() throws Exception {
|
||||
|
||||
+6
@@ -32606,6 +32606,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/dataFlowInfoForArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disableDfaBooleanVariables.kt")
|
||||
public void testDisableDfaBooleanVariables() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/disableDfaBooleanVariables.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("doubleLambdaArgument.kt")
|
||||
public void testDoubleLambdaArgument() throws Exception {
|
||||
|
||||
+6
@@ -32732,6 +32732,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/dataFlowInfoForArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disableDfaBooleanVariables.kt")
|
||||
public void testDisableDfaBooleanVariables() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/disableDfaBooleanVariables.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("doubleLambdaArgument.kt")
|
||||
public void testDoubleLambdaArgument() throws Exception {
|
||||
|
||||
+8
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||
|
||||
import kotlinx.collections.immutable.toPersistentSet
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||
import org.jetbrains.kotlin.contracts.description.canBeRevisited
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -1086,9 +1087,15 @@ abstract class FirDataFlowAnalyzer(
|
||||
// if (b != null) { /* a != null, but a.x could have changed */ }
|
||||
logicSystem.translateVariableFromConditionInStatements(flow, initializerVariable, propertyVariable)
|
||||
}
|
||||
} else if (initializerVariable != null && propertyVariable.isStable) {
|
||||
} else if (initializerVariable != null && propertyVariable.isStable &&
|
||||
(components.session.languageVersionSettings.supportsFeature(LanguageFeature.DfaBooleanVariables) ||
|
||||
!initializer.resolvedType.isBoolean)
|
||||
) {
|
||||
// val b = x is String
|
||||
// if (b) { /* x is String */ }
|
||||
|
||||
// val b = x?.foo() // `x?.foo()` is synthetic
|
||||
// if (b != null) { /* x != null */ }
|
||||
logicSystem.translateVariableFromConditionInStatements(flow, initializerVariable, propertyVariable)
|
||||
}
|
||||
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
// FIR_IDENTICAL
|
||||
// DIAGNOSTICS: -DEBUG_INFO_SMARTCAST
|
||||
// LANGUAGE:-DfaBooleanVariables
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
fun test1() {
|
||||
val nullableString: String? = ""
|
||||
val test = nullableString != null
|
||||
if (test) nullableString<!UNSAFE_CALL!>.<!>length
|
||||
if (nullableString != null) nullableString.length
|
||||
}
|
||||
|
||||
class A {
|
||||
val a: String? = ""
|
||||
}
|
||||
fun test3(a: A) {
|
||||
val test = a.a != null
|
||||
if (test) a.a<!UNSAFE_CALL!>.<!>length
|
||||
if (a.a != null) {
|
||||
a.a.length
|
||||
}
|
||||
}
|
||||
|
||||
fun test4() {
|
||||
val nullableAny: Any? = ""
|
||||
val test = nullableAny != null && nullableAny is String?
|
||||
if (test) nullableAny.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
if (nullableAny != null && nullableAny is String?) nullableAny.length
|
||||
}
|
||||
|
||||
fun test7(bar: Any) {
|
||||
val test = bar is String
|
||||
if (test) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
if (bar is String) bar.length
|
||||
}
|
||||
|
||||
fun test8(bar: Any) {
|
||||
val test = bar is String
|
||||
when {
|
||||
test -> bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
when {
|
||||
bar is String -> bar.length
|
||||
}
|
||||
}
|
||||
|
||||
fun test9(bar: Any) {
|
||||
bar is String && bar.length == 0
|
||||
val test = bar is String
|
||||
test && bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
|
||||
fun test10(bar: Any) {
|
||||
val test = bar !is String
|
||||
run {
|
||||
if (test) return@run
|
||||
bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
run {
|
||||
if (bar !is String) return@run
|
||||
bar.length
|
||||
}
|
||||
}
|
||||
|
||||
fun test11(bar: Any, baz: Any) {
|
||||
val test = baz is String && baz === bar
|
||||
val test2 = baz is String
|
||||
val test3 = baz === bar
|
||||
val test4 = test2 && test3
|
||||
|
||||
if (test) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
if (test2 && test3) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
if (baz is String && test3) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
if (test2 && baz === bar) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
if (test4) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
|
||||
if (baz is String && baz === bar) bar.length
|
||||
}
|
||||
|
||||
fun test12(bar: Any) {
|
||||
val test = bar !is String
|
||||
if (!test) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
|
||||
fun test13(bar: Any) {
|
||||
val test = bar is String
|
||||
if (test == true) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
when (test) {
|
||||
true -> bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
false -> {}
|
||||
}
|
||||
|
||||
val test2: Boolean? = bar is String
|
||||
if (test2 == true) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
|
||||
fun test14(bar: Any) {
|
||||
val test = (bar as? String) != null
|
||||
if (test) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
|
||||
fun test15(bar: Any) {
|
||||
val test = bar is String
|
||||
val test2 = test
|
||||
if (test2) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
|
||||
fun test16(bar: Any) {
|
||||
val x = bar.isString()
|
||||
if (x) bar.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
if (bar.isString()) bar.length
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun Any.isString(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isString is String)
|
||||
}
|
||||
return this is String
|
||||
}
|
||||
|
||||
fun String.isEmpty(): Boolean = length == 0
|
||||
fun test17(a: String?) {
|
||||
val x = a?.length
|
||||
if (x != null) a.length
|
||||
|
||||
val y = a?.isEmpty()
|
||||
if (y == true) a.length
|
||||
}
|
||||
Generated
+6
@@ -34962,6 +34962,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/dataFlowInfoForArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("disableDfaBooleanVariables.kt")
|
||||
public void testDisableDfaBooleanVariables() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/disableDfaBooleanVariables.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("doubleLambdaArgument.kt")
|
||||
public void testDoubleLambdaArgument() throws Exception {
|
||||
|
||||
@@ -308,6 +308,7 @@ enum class LanguageFeature(
|
||||
ForbidInferringTypeVariablesIntoEmptyIntersection(KOTLIN_2_0, kind = BUG_FIX), // KT-51221
|
||||
ProhibitDefaultArgumentsInExpectActualizedByFakeOverride(KOTLIN_2_0, kind = BUG_FIX), // KT-62036
|
||||
DisableCompatibilityModeForNewInference(KOTLIN_2_0, kind = OTHER), // KT-63558 (umbrella), KT-64306, KT-64307, KT-64308
|
||||
DfaBooleanVariables(KOTLIN_2_0), // KT-25747
|
||||
|
||||
// 2.1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user