@@ -100,31 +100,6 @@ sealed class DataFlowVariable {
100100 }
101101}
102102
103- private enum class PropertyStability (
104- val inherentInstability : SmartcastStability ? ,
105- val checkModule : Boolean = false ,
106- val checkReceiver : Boolean = false ,
107- ) {
108- // Private vals can only be accessed from the same scope, so they're always safe to smart cast.
109- // Constant values (e.g. singleton objects) cannot be reassigned no matter what, so they're always safe
110- // to smart cast as well, although this is not very useful.
111- PRIVATE_OR_CONST_VAL (null ),
112-
113- // Public final vals can be accessed from different modules, which are not necessarily recompiled
114- // when the module declaring the property changes, so smart casting them there is unsafe.
115- PUBLIC_FINAL_VAL (null , checkModule = true ),
116-
117- // Public open vals can be overridden with custom getters, so smart casting them is only safe
118- // if the receiver is known to be of a final type that doesn't do that.
119- PUBLIC_OPEN_VAL (null , checkModule = true , checkReceiver = true ),
120-
121- CAPTURED_VARIABLE (SmartcastStability .CAPTURED_VARIABLE ),
122- EXPECT_PROPERTY (SmartcastStability .EXPECT_PROPERTY ),
123- PROPERTY_WITH_GETTER (SmartcastStability .PROPERTY_WITH_GETTER ),
124- MUTABLE_PROPERTY (SmartcastStability .MUTABLE_PROPERTY ),
125- DELEGATED_PROPERTY (SmartcastStability .DELEGATED_PROPERTY );
126- }
127-
128103class RealVariable (
129104 val symbol : FirBasedSymbol <* >,
130105 val isImplicit : Boolean ,
@@ -165,95 +140,12 @@ class RealVariable(
165140 append(" (${dispatchReceiver ? : extensionReceiver} )" )
166141 }
167142 }
168-
169- fun getStability (flow : Flow , session : FirSession ): SmartcastStability {
170- if (! isImplicit) {
171- val stability = propertyStability
172-
173- val isUnstableSmartcastOnDelegatedProperties =
174- session.languageVersionSettings.supportsFeature(LanguageFeature .UnstableSmartcastOnDelegatedProperties )
175- if (isUnstableSmartcastOnDelegatedProperties && (symbol.fir as ? FirProperty )?.isDelegated == true ) return SmartcastStability .DELEGATED_PROPERTY
176-
177- stability.inherentInstability?.let { return it }
178- if (symbol is FirPropertySymbol && symbol.fir.isImplicitWhenSubjectVariable) {
179- flow.unwrapVariable(this ).takeIf { it != this }?.let { return it.getStability(flow, session) }
180- }
181- if (stability.checkReceiver && dispatchReceiver?.hasFinalType(flow, session) == false )
182- return SmartcastStability .PROPERTY_WITH_GETTER
183- if (stability.checkModule && ! (symbol.fir as FirVariable ).isInCurrentOrFriendModule(session))
184- return SmartcastStability .ALIEN_PUBLIC_PROPERTY
185- // Members of unstable values should always be unstable, as the receiver could've changed.
186- dispatchReceiver?.getStability(flow, session)?.takeIf { it != SmartcastStability .STABLE_VALUE }?.let { return it }
187- // No need to check extension receiver, as properties with one cannot be stable by symbol stability.
188- }
189- return SmartcastStability .STABLE_VALUE
190- }
191-
192- private fun hasFinalType (flow : Flow , session : FirSession ): Boolean =
193- originalType.isFinal(session) || flow.getTypeStatement(this )?.upperTypes?.any { it.isFinal(session) } == true
194-
195- private val propertyStability: PropertyStability by lazy {
196- when (val fir = symbol.fir) {
197- !is FirVariable -> PropertyStability .PRIVATE_OR_CONST_VAL // named object or containing class for a static field reference
198- is FirEnumEntry -> PropertyStability .PRIVATE_OR_CONST_VAL
199- is FirErrorProperty -> PropertyStability .PRIVATE_OR_CONST_VAL
200- is FirValueParameter -> PropertyStability .PRIVATE_OR_CONST_VAL
201- is FirBackingField -> when {
202- fir.isVal -> PropertyStability .PRIVATE_OR_CONST_VAL
203- else -> PropertyStability .MUTABLE_PROPERTY
204- }
205- is FirField -> when {
206- fir.isVal -> PropertyStability .PUBLIC_FINAL_VAL
207- else -> PropertyStability .MUTABLE_PROPERTY
208- }
209- is FirProperty -> when {
210- fir.isExpect -> PropertyStability .EXPECT_PROPERTY
211- fir.delegate != null -> PropertyStability .DELEGATED_PROPERTY
212- // Local vars are only *sometimes* unstable (when there are concurrent assignments). `FirDataFlowAnalyzer`
213- // will check that at each use site individually and mark the access as stable when possible.
214- fir.symbol is FirLocalPropertySymbol -> when {
215- fir.isVal -> PropertyStability .PRIVATE_OR_CONST_VAL
216- else -> PropertyStability .CAPTURED_VARIABLE
217- }
218- fir.isVar -> PropertyStability .MUTABLE_PROPERTY
219- fir.isInstanceExtension -> PropertyStability .PROPERTY_WITH_GETTER
220- fir.getter !is FirDefaultPropertyAccessor ? -> PropertyStability .PROPERTY_WITH_GETTER
221- fir.visibility == Visibilities .Private -> PropertyStability .PRIVATE_OR_CONST_VAL
222- // REPL vals can be treated the same as local vals.
223- // TODO(???): allow REPL vars to be treated as local vars.
224- fir.isReplSnippetDeclaration == true -> PropertyStability .PRIVATE_OR_CONST_VAL
225- fir.isFinal -> PropertyStability .PUBLIC_FINAL_VAL
226- else -> PropertyStability .PUBLIC_OPEN_VAL
227- }
228- }
229- }
230143}
231144
232145data class SyntheticVariable (val fir : FirExpression ) : DataFlowVariable() {
233146 override val originalType: ConeKotlinType get() = fir.resolvedType
234147}
235148
236- private fun ConeKotlinType.isFinal (session : FirSession ): Boolean = when (this ) {
237- is ConeFlexibleType -> lowerBound.isFinal(session)
238- is ConeDefinitelyNotNullType -> original.isFinal(session)
239- is ConeClassLikeType -> toSymbol(session)?.fullyExpandedClass(session)?.isFinal == true
240- is ConeTypeParameterType -> toTypeParameterSymbol(session)?.resolvedBounds?.any { it.coneType.isFinal(session) } == true
241-
242- is ConeIntersectionType -> intersectedTypes.any { it.isFinal(session) }
243- is ConeCapturedType -> constructor .supertypes?.any { it.isFinal(session) } == true
244- is ConeIntegerLiteralType -> true
245-
246- is ConeStubType ,
247- is ConeTypeVariableType ,
248- -> false
249- }
250-
251- private fun FirVariable.isInCurrentOrFriendModule (session : FirSession ): Boolean {
252- val propertyModuleData = originalOrSelf().moduleData
253- val currentModuleData = session.moduleData
254- return currentModuleData.canSeeInternalsOf(propertyModuleData)
255- }
256-
257149private tailrec fun FirExpression.unwrapElement (): FirExpression ? {
258150 return when (this ) {
259151 is FirSmartCastExpression -> originalExpression.unwrapElement()
0 commit comments