From 2bb7ef974767c9e283f38b3bb0d4b613ac6678b0 Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Fri, 7 May 2021 21:20:17 -0700 Subject: [PATCH] FIR DFA: store stability in RealVariable As part of this change, we also extend the usage of RealVariable in more places during DFA. Now mutable properties, property with custom getters, delegated properties, etc are also treatd as a `RealVariable`. In general this is needed in order to carry out smartcast computation in order to report `SMARTCAST_IMPOSSIBLE`. It seems to also have side effects that improves behavior of some test files. --- .../analysis/cfa/FirReturnsImpliesAnalyzer.kt | 44 +++++----- .../kotlin/fir/resolve/ResolveUtils.kt | 17 ++-- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 34 +++++--- .../kotlin/fir/resolve/dfa/VariableStorage.kt | 80 ++++++++++++------- .../jetbrains/kotlin/fir/resolve/dfa/model.kt | 29 ++++++- .../FirExpressionWithSmartcastToNull.kt | 4 +- .../fir/tree/generator/NodeConfigurator.kt | 2 + .../nestedCalls/makeNullableIfSafeCall.fir.kt | 4 +- .../localDelegatedPropertyAfter.fir.kt | 4 +- .../localDelegatedPropertyBefore.fir.kt | 4 +- .../smartCasts/publicVals/otherModule.fir.kt | 4 +- .../diagnostics/notLinked/dfa/pos/53.fir.kt | 4 +- 12 files changed, 152 insertions(+), 78 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt index 53cc228d7ff..bd1f76c1106 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt @@ -156,30 +156,34 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() { variableStorage: VariableStorage, flow: Flow, context: CheckerContext - ): MutableTypeStatements? = when (this) { - is ConeBinaryLogicExpression -> { - val left = left.buildTypeStatements(function, logicSystem, variableStorage, flow, context) - val right = right.buildTypeStatements(function, logicSystem, variableStorage, flow, context) - if (left != null && right != null) { - if (kind == LogicOperationKind.AND) { - left.apply { mergeTypeStatements(right) } - } else logicSystem.orForTypeStatements(left, right) - } else (left ?: right) - } - is ConeIsInstancePredicate -> { + ): MutableTypeStatements? { + fun buildTypeStatements(arg: ConeValueParameterReference, exactType: Boolean, type: ConeKotlinType): MutableTypeStatements? { val fir = function.getParameterSymbol(arg.parameterIndex, context).fir val realVar = variableStorage.getOrCreateRealVariable(flow, fir.symbol, fir) - realVar?.to(simpleTypeStatement(realVar, !isNegated, type))?.let { mutableMapOf(it) } + ?.takeIf { + it.stability == PropertyStability.STABLE_VALUE || + // TODO: consider removing the part below + it.stability == PropertyStability.LOCAL_VAR + } + return realVar?.to(simpleTypeStatement(realVar, exactType, type))?.let { mutableMapOf(it) } } - is ConeIsNullPredicate -> { - val fir = function.getParameterSymbol(arg.parameterIndex, context).fir - val realVar = variableStorage.getOrCreateRealVariable(flow, fir.symbol, fir) - realVar?.to(simpleTypeStatement(realVar, isNegated, context.session.builtinTypes.anyType.type))?.let { mutableMapOf(it) } - } - is ConeLogicalNot -> arg.buildTypeStatements(function, logicSystem, variableStorage, flow, context) - ?.mapValuesTo(mutableMapOf()) { (_, value) -> value.invert() } + return when (this) { + is ConeBinaryLogicExpression -> { + val left = left.buildTypeStatements(function, logicSystem, variableStorage, flow, context) + val right = right.buildTypeStatements(function, logicSystem, variableStorage, flow, context) + if (left != null && right != null) { + if (kind == LogicOperationKind.AND) { + left.apply { mergeTypeStatements(right) } + } else logicSystem.orForTypeStatements(left, right) + } else (left ?: right) + } + is ConeIsInstancePredicate -> buildTypeStatements(arg, !isNegated, type) + is ConeIsNullPredicate -> buildTypeStatements(arg, isNegated, context.session.builtinTypes.anyType.type) + is ConeLogicalNot -> arg.buildTypeStatements(function, logicSystem, variableStorage, flow, context) + ?.mapValuesTo(mutableMapOf()) { (_, value) -> value.invert() } - else -> null + else -> null + } } private fun ConeKotlinType.isInapplicableWith(operation: Operation, session: FirSession): Boolean { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 24792247808..61421dd7140 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -10,7 +10,10 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassKind import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.diagnostics.* +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.references.FirErrorNamedReference @@ -23,12 +26,12 @@ import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType -import org.jetbrains.kotlin.fir.resolve.providers.* +import org.jetbrains.kotlin.fir.resolve.providers.getSymbolByTypeRef import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData -import org.jetbrains.kotlin.fir.symbols.* +import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef @@ -247,7 +250,8 @@ private fun BodyResolveComponents.typeFromSymbol(symbol: AbstractFirBasedSymbol< fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo( qualifiedAccessExpression: FirQualifiedAccessExpression ): FirQualifiedAccessExpression { - val typesFromSmartCast = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression) ?: return qualifiedAccessExpression + val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression) + ?: return qualifiedAccessExpression val originalType = qualifiedAccessExpression.resultType.coneType // For example, if (x == null) { ... }, // we don't want to smartcast to Nothing?, but we want to record the nullability to its own kind of node. @@ -271,6 +275,8 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo( smartcastType = intersectedTypeRefWithoutNullableNothing // NB: Nothing? in types from smartcast in DFA is recorded here (and the expression kind itself). this.typesFromSmartCast = typesFromSmartCast + // TODO: differentiate capture local variable + this.smartcastStability = stability.impliedSmartcastStability ?: SmartcastStability.STABLE_VALUE } } val allTypes = typesFromSmartCast.also { @@ -288,7 +294,8 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo( originalExpression = qualifiedAccessExpression smartcastType = intersectedTypeRef this.typesFromSmartCast = typesFromSmartCast - smartcastStability = SmartcastStability.STABLE_VALUE + // TODO: differentiate capture local variable + this.smartcastStability = stability.impliedSmartcastStability ?: SmartcastStability.STABLE_VALUE } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index 4272d28e9ec..ab25fbd0eec 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -162,7 +162,7 @@ abstract class FirDataFlowAnalyzer( // ----------------------------------- Requests ----------------------------------- - fun getTypeUsingSmartcastInfo(qualifiedAccessExpression: FirQualifiedAccessExpression): MutableList? { + fun getTypeUsingSmartcastInfo(qualifiedAccessExpression: FirQualifiedAccessExpression): Pair>? { /* * DataFlowAnalyzer holds variables only for declarations that have some smartcast (or can have) * If there is no useful information there is no data flow variable also @@ -170,13 +170,14 @@ abstract class FirDataFlowAnalyzer( val symbol: AbstractFirBasedSymbol<*> = qualifiedAccessExpression.symbol ?: return null val flow = graphBuilder.lastNode.flow var variable = variableStorage.getRealVariableWithoutUnwrappingAlias(symbol, qualifiedAccessExpression, flow) ?: return null + val stability = variable.stability val result = mutableListOf() flow.directAliasMap[variable]?.let { result.addIfNotNull(it.originalType) variable = it.variable } flow.getTypeStatement(variable)?.exactType?.let { result += it } - return result.takeIf { it.isNotEmpty() } + return result.takeIf { it.isNotEmpty() }?.let { stability to it } } fun returnExpressionsOfAnonymousFunction(function: FirAnonymousFunction): Collection { @@ -1009,7 +1010,12 @@ abstract class FirDataFlowAnalyzer( assignment: FirVariableAssignment? ) { val flow = node.flow - val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias(flow, property.symbol, assignment ?: property) + val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias( + flow, + property.symbol, + assignment ?: property, + if (property.isVal) PropertyStability.STABLE_VALUE else PropertyStability.LOCAL_VAR + ) val isAssignment = assignment != null if (isAssignment) { logicSystem.removeLocalVariableAlias(flow, propertyVariable) @@ -1017,13 +1023,21 @@ abstract class FirDataFlowAnalyzer( logicSystem.recordNewAssignment(flow, propertyVariable, context.newAssignmentIndex()) } - variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer)?.let { initializerVariable -> - logicSystem.addLocalVariableAlias( - flow, propertyVariable, - RealVariableAndType(initializerVariable, initializer.coneType) - ) - // node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null)) - } + variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer) + ?.let { initializerVariable -> + // TODO: handle capture variable + if ((initializerVariable.stability == PropertyStability.STABLE_VALUE || initializerVariable.stability == PropertyStability.LOCAL_VAR) && + (propertyVariable.stability == PropertyStability.STABLE_VALUE || propertyVariable.stability == PropertyStability.LOCAL_VAR) + ) { + logicSystem.addLocalVariableAlias( + flow, propertyVariable, + RealVariableAndType(initializerVariable, initializer.coneType) + ) + // node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null)) + } else { + logicSystem.replaceVariableFromConditionInStatements(flow, initializerVariable, propertyVariable) + } + } variableStorage.getSyntheticVariable(initializer)?.let { initializerVariable -> /* diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt index 4e8854bca5e..5e7114cbd53 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt @@ -8,7 +8,9 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession +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.modality import org.jetbrains.kotlin.fir.expressions.* @@ -34,14 +36,24 @@ class VariableStorage(private val session: FirSession) { fun clear(): VariableStorage = VariableStorage(session) - fun getOrCreateRealVariableWithoutUnwrappingAlias(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable { + fun getOrCreateRealVariableWithoutUnwrappingAlias( + flow: Flow, + symbol: AbstractFirBasedSymbol<*>, + fir: FirElement, + stability: PropertyStability + ): RealVariable { val realFir = fir.unwrapElement() val identifier = getIdentifierBySymbol(flow, symbol, realFir) - return _realVariables.getOrPut(identifier) { createRealVariableInternal(flow, identifier, realFir) } + return _realVariables.getOrPut(identifier) { createRealVariableInternal(flow, identifier, realFir, stability) } } - private fun getOrCreateRealVariable(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable { - val variable = getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir) + private fun getOrCreateRealVariable( + flow: Flow, + symbol: AbstractFirBasedSymbol<*>, + fir: FirElement, + stability: PropertyStability + ): RealVariable { + val variable = getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir, stability) return flow.directAliasMap[variable]?.variable ?: variable } @@ -69,7 +81,12 @@ class VariableStorage(private val session: FirSession) { /** * [originalFir] used for extracting expression under and extracting receiver */ - private fun createRealVariableInternal(flow: Flow, identifier: Identifier, originalFir: FirElement): RealVariable { + private fun createRealVariableInternal( + flow: Flow, + identifier: Identifier, + originalFir: FirElement, + stability: PropertyStability + ): RealVariable { val receiver: FirExpression? val isThisReference: Boolean val expression: FirQualifiedAccess? = when (originalFir) { @@ -88,12 +105,12 @@ class VariableStorage(private val session: FirSession) { } val receiverVariable = receiver?.let { getOrCreateVariable(flow, it) } - return RealVariable(identifier, isThisReference, receiverVariable, counter++) + return RealVariable(identifier, isThisReference, receiverVariable, counter++, stability) } @JvmName("getOrCreateRealVariableOrNull") fun getOrCreateRealVariable(flow: Flow, symbol: AbstractFirBasedSymbol<*>?, fir: FirElement): RealVariable? = - symbol.takeIf { it.isStable(fir) }?.let { getOrCreateRealVariable(flow, it, fir) } + symbol.getStability(fir)?.let { getOrCreateRealVariable(flow, symbol!!, fir, it) } fun createSyntheticVariable(fir: FirElement): SyntheticVariable = SyntheticVariable(fir, counter++).also { syntheticVariables[fir] = it } @@ -101,8 +118,9 @@ class VariableStorage(private val session: FirSession) { fun getOrCreateVariable(flow: Flow, fir: FirElement): DataFlowVariable { val realFir = fir.unwrapElement() val symbol = realFir.symbol - return if (symbol.isStable(realFir)) { - getOrCreateRealVariable(flow, symbol!!, realFir) + val stability = symbol.getStability(realFir) + return if (stability != null) { + getOrCreateRealVariable(flow, symbol!!, realFir, stability) } else { syntheticVariables[realFir] ?: createSyntheticVariable(realFir) } @@ -110,7 +128,7 @@ class VariableStorage(private val session: FirSession) { fun getRealVariableWithoutUnwrappingAlias(symbol: AbstractFirBasedSymbol<*>?, fir: FirElement, flow: Flow): RealVariable? { val realFir = fir.unwrapElement() - return symbol.takeIf { it.isStable(realFir) }?.let { + return symbol.takeIf { it.getStability(realFir) != null }?.let { _realVariables[getIdentifierBySymbol(flow, it, realFir.unwrapElement())] } } @@ -126,7 +144,8 @@ class VariableStorage(private val session: FirSession) { fun getVariable(fir: FirElement, flow: Flow): DataFlowVariable? { val realFir = fir.unwrapElement() val symbol = realFir.symbol - return if (symbol.isStable(fir)) { + val stability = symbol.getStability(fir) + return if (stability != null) { getRealVariable(symbol, realFir, flow) } else { getSyntheticVariable(fir) @@ -143,39 +162,40 @@ class VariableStorage(private val session: FirSession) { } @OptIn(ExperimentalContracts::class) - fun AbstractFirBasedSymbol<*>?.isStable(originalFir: FirElement): Boolean { + fun AbstractFirBasedSymbol<*>?.getStability(originalFir: FirElement): PropertyStability? { contract { - returns(true) implies(this@isStable != null) + returnsNotNull() implies (this@getStability != null) } when (this) { - is FirAnonymousObjectSymbol -> return false + is FirAnonymousObjectSymbol -> return null is FirFunctionSymbol<*>, is FirClassSymbol<*>, - is FirBackingFieldSymbol -> return true - null -> return false + is FirBackingFieldSymbol -> return PropertyStability.STABLE_VALUE + null -> return null } - if (originalFir is FirThisReceiverExpression) return true - if (this !is FirVariableSymbol<*>) return false + if (originalFir is FirThisReceiverExpression) return PropertyStability.STABLE_VALUE + if (this !is FirVariableSymbol<*>) return null - val property = this.fir as? FirProperty ?: return true + val property = this.fir as? FirProperty ?: return PropertyStability.STABLE_VALUE return when { - property.isLocal -> true - property.isVar -> false - property.receiverTypeRef != null -> false - property.getter.let { it != null && it !is FirDefaultPropertyAccessor } -> false + property.delegate != null -> PropertyStability.DELEGATED_PROPERTY + property.isLocal -> if (property.isVal) PropertyStability.STABLE_VALUE else PropertyStability.LOCAL_VAR + property.isVar -> PropertyStability.MUTABLE_PROPERTY + property.receiverTypeRef != null -> PropertyStability.PROPERTY_WITH_GETTER + property.getter.let { it != null && it !is FirDefaultPropertyAccessor } -> PropertyStability.PROPERTY_WITH_GETTER + property.moduleData.session != session -> PropertyStability.ALIEN_PUBLIC_PROPERTY property.modality != Modality.FINAL -> { - val dispatchReceiver = (originalFir.unwrapElement() as? FirQualifiedAccess)?.dispatchReceiver ?: return false - val receiverType = dispatchReceiver.typeRef.coneTypeSafe()?.fullyExpandedType(session) ?: return false - val receiverSymbol = receiverType.lookupTag.toSymbol(session) ?: return false + val dispatchReceiver = (originalFir.unwrapElement() as? FirQualifiedAccess)?.dispatchReceiver ?: return null + val receiverType = dispatchReceiver.typeRef.coneTypeSafe()?.fullyExpandedType(session) ?: return null + val receiverSymbol = receiverType.lookupTag.toSymbol(session) ?: return null when (val receiverFir = receiverSymbol.fir) { - is org.jetbrains.kotlin.fir.declarations.FirAnonymousObject -> true - is org.jetbrains.kotlin.fir.declarations.FirRegularClass -> receiverFir.modality == Modality.FINAL + is FirAnonymousObject -> PropertyStability.STABLE_VALUE + is FirRegularClass -> if (receiverFir.modality == Modality.FINAL) PropertyStability.STABLE_VALUE else PropertyStability.PROPERTY_WITH_GETTER else -> throw IllegalStateException("Should not be here: $receiverFir") } - } - else -> true + else -> PropertyStability.STABLE_VALUE } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt index 85c18947b66..d808cc66015 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/model.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.types.ConeClassErrorType import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.types.SmartcastStability import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -33,11 +34,37 @@ sealed class DataFlowVariable(private val variableIndexForDebug: Int) { } } +enum class PropertyStability(val impliedSmartcastStability: SmartcastStability?) { + // Immutable and no custom getter or local. + // Smartcast is definitely safe regardless of usage. + STABLE_VALUE(SmartcastStability.STABLE_VALUE), + + // Open or custom getter. + // Smartcast is always unsafe regardless of usage. + PROPERTY_WITH_GETTER(SmartcastStability.PROPERTY_WITH_GETTER), + + // Protected / public member value from another module. + // Smartcast is always unsafe regardless of usage. + ALIEN_PUBLIC_PROPERTY(SmartcastStability.ALIEN_PUBLIC_PROPERTY), + + // Smartcast may or may not be safe, depending on whether there are concurrent writes to this local variable. + LOCAL_VAR(null), + + // Mutable member property of a class or object. + // Smartcast is always unsafe regardless of usage. + MUTABLE_PROPERTY(SmartcastStability.MUTABLE_PROPERTY), + + // Delegated property of a class or object. + // Smartcast is always unsafe regardless of usage. + DELEGATED_PROPERTY(SmartcastStability.DELEGATED_PROPERTY), +} + class RealVariable( val identifier: Identifier, val isThisReference: Boolean, val explicitReceiverVariable: DataFlowVariable?, - variableIndexForDebug: Int + variableIndexForDebug: Int, + val stability: PropertyStability, ) : DataFlowVariable(variableIndexForDebug) { override fun equals(other: Any?): Boolean { return this === other diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt index 35589539326..9181ab521fb 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt @@ -29,11 +29,11 @@ abstract class FirExpressionWithSmartcastToNull : FirExpressionWithSmartcast() { abstract override val explicitReceiver: FirExpression? abstract override val dispatchReceiver: FirExpression abstract override val extensionReceiver: FirExpression - abstract override val smartcastType: FirTypeRef - abstract override val smartcastStability: SmartcastStability abstract override val originalExpression: FirQualifiedAccessExpression abstract override val typesFromSmartCast: Collection abstract override val originalType: FirTypeRef + abstract override val smartcastType: FirTypeRef + abstract override val smartcastStability: SmartcastStability override fun accept(visitor: FirVisitor, data: D): R = visitor.visitExpressionWithSmartcastToNull(this, data) diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index be9656b215c..a3faf7e2ee0 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -471,6 +471,8 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild +field("originalExpression", qualifiedAccessExpression) +field("typesFromSmartCast", "Collection", null, customType = coneKotlinTypeType) +field("originalType", typeRef) + +field("smartcastType", typeRef) + +smartcastStability } safeCallExpression.configure { diff --git a/compiler/testData/diagnostics/tests/inference/nestedCalls/makeNullableIfSafeCall.fir.kt b/compiler/testData/diagnostics/tests/inference/nestedCalls/makeNullableIfSafeCall.fir.kt index 145ff09c7ec..1926dacd36d 100644 --- a/compiler/testData/diagnostics/tests/inference/nestedCalls/makeNullableIfSafeCall.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/nestedCalls/makeNullableIfSafeCall.fir.kt @@ -14,13 +14,13 @@ fun test(u: A?, x: A?, y: A?, z: A?, w: A, v: A?) { u!!.b?.foo()!! x?.b!!.foo()!! // x?.b is not null - x!!.b!!.foo()!! + x!!.b!!.foo()!! y?.nb?.foo()!! y!!.nb?.foo()!! z?.nb!!.foo()!! // z?.nb is not null - z!!.nb!!.foo()!! + z!!.nb!!.foo()!! w.b?.foo()!! w.b!!.foo()!! diff --git a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt index 13f0a640d8d..086c4e05ef7 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt @@ -10,6 +10,6 @@ fun failsWithClassCastException() { val sometimesNotInt: Any? by AlternatingDelegate() if (sometimesNotInt is Int) { - sometimesNotInt.inc() + sometimesNotInt.inc() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt index 8777e5aea0a..8876767b0ec 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt @@ -10,6 +10,6 @@ fun failsWithClassCastException() { val sometimesNotInt: Any? by AlternatingDelegate() if (sometimesNotInt is Int) { - sometimesNotInt.inc() + sometimesNotInt.inc() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt index 3b467593ed3..10449588bdd 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt @@ -17,7 +17,7 @@ import a.X public fun X.gav(): Int { if (x != null) // Smart cast is not possible if definition is in another module - return x.length + return x.length else return 0 } @@ -29,7 +29,7 @@ package a public fun X.gav(): Int { if (x != null) // Even if it's in the same package - return x.length + return x.length else return 0 } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt index 501fe32d597..84ee533bd4c 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt @@ -33,7 +33,7 @@ fun case_3(x: Int) = "" fun case_3(x: Int?) = 10 fun case_3() { if (case_3_prop != null) { - val z = case_3(case_3_prop) + val z = case_3(case_3_prop) z } } @@ -89,7 +89,7 @@ fun case_7(x: Int) = "" fun case_7(x: Int?) = 10 fun case_7() { if (case_7_prop != null) { - val z = case_7(case_7_prop) + val z = case_7(case_7_prop) z } }