[k2, dfa] Smartcasts are not allowed on FirJavaField from other module

Handle case with FirField properly. Previously the code was returning
STABLE_VALUE in that case.

Note that in fact the changed 'when' branch expects only FirJavaField,
as FirFieldImpl should be handled by FirBackingFieldSymbol-check at
the beginning of the method. However, it is impossible to refer to
FirJavaField directly due to module visibility

Enumerate all cases more carefully via exhaustive 'when',
it's more readable and will prevent potential issues in future in case
more subclasses are added.

^KT-58279 Fixed
This commit is contained in:
Dmitry Savvinov
2024-01-17 15:16:08 +01:00
committed by Space Team
parent 6661a66fc3
commit 74fa6fc12c
2 changed files with 37 additions and 21 deletions
@@ -9,14 +9,9 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject import org.jetbrains.kotlin.fir.declarations.*
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.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.originalOrSelf import org.jetbrains.kotlin.fir.originalOrSelf
@@ -170,7 +165,25 @@ class VariableStorageImpl(private val session: FirSession) : VariableStorage() {
if (this !is FirVariableSymbol<*>) return null if (this !is FirVariableSymbol<*>) return null
if (this is FirFieldSymbol && !this.isFinal) return PropertyStability.MUTABLE_PROPERTY if (this is FirFieldSymbol && !this.isFinal) return PropertyStability.MUTABLE_PROPERTY
val property = this.fir as? FirProperty ?: return PropertyStability.STABLE_VALUE val property = when (val variable = this.fir) { // intentionally exhaustive 'when'
is FirEnumEntry, is FirErrorProperty, is FirValueParameter -> return PropertyStability.STABLE_VALUE
// NB: FirJavaField is expected here. FirFieldImpl should've been handled by FirBackingFieldSymbol check above
is FirField -> {
if (variable.isJava)
return variable.determineStabilityByModule()
else
errorWithAttachment("Expected to handle non-Java FirFields via symbol-based checks") {
withFirEntry("fir", variable)
}
}
is FirBackingField -> errorWithAttachment("Expected to handle Backing Field entirely via symbol-based checks") {
withFirEntry("fir", variable)
}
is FirProperty -> variable
}
return when { return when {
property.delegate != null -> PropertyStability.DELEGATED_PROPERTY property.delegate != null -> PropertyStability.DELEGATED_PROPERTY
@@ -192,16 +205,19 @@ class VariableStorageImpl(private val session: FirSession) : VariableStorage() {
} }
} }
} }
else -> { else -> property.determineStabilityByModule()
val propertyModuleData = property.originalOrSelf().moduleData }
val currentModuleData = session.moduleData }
when (propertyModuleData) {
currentModuleData, private fun FirVariable.determineStabilityByModule(): PropertyStability {
in currentModuleData.friendDependencies, val propertyModuleData = originalOrSelf().moduleData
in currentModuleData.dependsOnDependencies -> PropertyStability.STABLE_VALUE val currentModuleData = session.moduleData
else -> PropertyStability.ALIEN_PUBLIC_PROPERTY return when (propertyModuleData) {
} currentModuleData,
} in currentModuleData.friendDependencies,
in currentModuleData.dependsOnDependencies,
-> PropertyStability.STABLE_VALUE
else -> PropertyStability.ALIEN_PUBLIC_PROPERTY
} }
} }
} }
@@ -11,8 +11,8 @@ public class J {
// MODULE: app(lib) // MODULE: app(lib)
fun isCast() { fun isCast() {
if (J.staticFinalJava is String) { if (J.staticFinalJava is String) {
J.staticFinalJava.length <!SMARTCAST_IMPOSSIBLE!>J.staticFinalJava<!>.length
(J.staticFinalJava <!USELESS_CAST!>as String<!>).length (J.staticFinalJava as String).length
} }
if (J.staticNonFinalJava is String) { if (J.staticNonFinalJava is String) {
@@ -23,7 +23,7 @@ fun isCast() {
fun asCast() { fun asCast() {
J.staticFinalJava as String J.staticFinalJava as String
J.staticFinalJava.length <!SMARTCAST_IMPOSSIBLE!>J.staticFinalJava<!>.length
J.staticNonFinalJava as String J.staticNonFinalJava as String
<!SMARTCAST_IMPOSSIBLE!>J.staticNonFinalJava<!>.length <!SMARTCAST_IMPOSSIBLE!>J.staticNonFinalJava<!>.length