From e3bab4a7da6229e4eae217b05b17c5c523014035 Mon Sep 17 00:00:00 2001 From: "Anastasia.Nekrasova" Date: Tue, 19 Sep 2023 19:03:15 +0300 Subject: [PATCH] [K2] Prohibit smart casts for 'expect' properties ^KT-61340 --- ...DiagnosticsWithLightTreeTestGenerated.java | 22 ++++++++++++++++ ...endMPPDiagnosticsWithPsiTestGenerated.java | 22 ++++++++++++++++ .../kotlin/fir/resolve/dfa/DfaVariables.kt | 3 +++ .../fir/resolve/dfa/VariableStorageImpl.kt | 2 ++ .../smartCasts/kt61340_commonCode.fir.kt | 25 ++++++++++++++++++ .../smartCasts/kt61340_commonCode.kt | 25 ++++++++++++++++++ .../smartCasts/kt61340_platformCode.kt | 26 +++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 22 ++++++++++++++++ .../kotlin/types/SmartcastStability.kt | 3 +++ 9 files changed, 150 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.fir.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_platformCode.kt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java index e5999f26b9d..f221a7f6fec 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java @@ -1723,6 +1723,28 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/smartCasts") + @TestDataPath("$PROJECT_ROOT") + public class SmartCasts { + @Test + public void testAllFilesPresentInSmartCasts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/smartCasts"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("kt61340_commonCode.kt") + public void testKt61340_commonCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.kt"); + } + + @Test + @TestMetadata("kt61340_platformCode.kt") + public void testKt61340_platformCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_platformCode.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/topLevelFun") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java index 5989e20ac71..73c77db0eb3 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java @@ -1723,6 +1723,28 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/smartCasts") + @TestDataPath("$PROJECT_ROOT") + public class SmartCasts { + @Test + public void testAllFilesPresentInSmartCasts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/smartCasts"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("kt61340_commonCode.kt") + public void testKt61340_commonCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.kt"); + } + + @Test + @TestMetadata("kt61340_platformCode.kt") + public void testKt61340_platformCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_platformCode.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/topLevelFun") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/DfaVariables.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/DfaVariables.kt index 93669b0abd0..a0f219c0f4e 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/DfaVariables.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/DfaVariables.kt @@ -36,6 +36,9 @@ enum class PropertyStability(val impliedSmartcastStability: SmartcastStability?) // Smartcast may or may not be safe, depending on whether there are concurrent writes to this local variable. LOCAL_VAR(null), + // Smartcast is always unsafe regardless of usage. + EXPECT_PROPERTY(SmartcastStability.EXPECT_PROPERTY), + // Open or custom getter. // Smartcast is always unsafe regardless of usage. PROPERTY_WITH_GETTER(SmartcastStability.PROPERTY_WITH_GETTER), diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorageImpl.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorageImpl.kt index f3b608e9eae..497a02d0a0a 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorageImpl.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorageImpl.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isFinal import org.jetbrains.kotlin.fir.declarations.utils.modality import org.jetbrains.kotlin.fir.declarations.utils.visibility @@ -165,6 +166,7 @@ class VariableStorageImpl(private val session: FirSession) : VariableStorage() { is FirFunctionSymbol<*>, is FirClassSymbol<*> -> return PropertyStability.STABLE_VALUE is FirBackingFieldSymbol -> return if (isVal) PropertyStability.STABLE_VALUE else PropertyStability.MUTABLE_PROPERTY } + if (this is FirCallableSymbol && this.isExpect) return PropertyStability.EXPECT_PROPERTY if (this !is FirVariableSymbol<*>) return null if (this is FirFieldSymbol && !this.isFinal) return PropertyStability.MUTABLE_PROPERTY diff --git a/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.fir.kt new file mode 100644 index 00000000000..0117bbe00fa --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.fir.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -DEBUG_INFO_SMARTCAST +// MODULE: m1-common +// FILE: common.kt + +expect val foo: Any + +expect class Bar() { + val bus: Any +} + +fun common() { + if (foo is String) foo.length + + val bar = Bar() + if (bar.bus is String) bar.bus.length +} + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual val foo: Any = 2 + +actual class Bar actual constructor() { + actual val bus: Any + get() = "bus" +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.kt b/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.kt new file mode 100644 index 00000000000..d47a38878b6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.kt @@ -0,0 +1,25 @@ +// !DIAGNOSTICS: -DEBUG_INFO_SMARTCAST +// MODULE: m1-common +// FILE: common.kt + +expect val foo: Any + +expect class Bar() { + val bus: Any +} + +fun common() { + if (foo is String) foo.length + + val bar = Bar() + if (bar.bus is String) bar.bus.length +} + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual val foo: Any = 2 + +actual class Bar actual constructor() { + actual val bus: Any + get() = "bus" +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_platformCode.kt b/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_platformCode.kt new file mode 100644 index 00000000000..90f48e74622 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_platformCode.kt @@ -0,0 +1,26 @@ +// FIR_IDENTICAL +// !DIAGNOSTICS: -DEBUG_INFO_SMARTCAST +// MODULE: m1-common +// FILE: common.kt + +expect val foo: Any + +expect class Bar() { + val bus: Any +} + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual val foo: Any = 2 + +actual class Bar actual constructor() { + actual val bus: Any + get() = "bus" +} + +fun platform() { + if (foo is String) foo.length + + val bar = Bar() + if (bar.bus is String) bar.bus.length +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 94619682f84..a8a5c696996 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -24892,6 +24892,28 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/smartCasts") + @TestDataPath("$PROJECT_ROOT") + public class SmartCasts { + @Test + public void testAllFilesPresentInSmartCasts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/smartCasts"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); + } + + @Test + @TestMetadata("kt61340_commonCode.kt") + public void testKt61340_commonCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_commonCode.kt"); + } + + @Test + @TestMetadata("kt61340_platformCode.kt") + public void testKt61340_platformCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/smartCasts/kt61340_platformCode.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/topLevelFun") @TestDataPath("$PROJECT_ROOT") diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/SmartcastStability.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/SmartcastStability.kt index a7ba64f1806..d92d9674712 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/SmartcastStability.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/SmartcastStability.kt @@ -17,6 +17,9 @@ enum class SmartcastStability(private val str: String, val description: String = // Smart casts are completely safe STABLE_VALUE("stable val"), + // Smart casts are not safe + EXPECT_PROPERTY("expect property"), + // Member value with open / custom getter // Smart casts are not safe PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"),