diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.fir.txt index 6dcf1dd39b3..c410947b5e3 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.fir.txt @@ -33,7 +33,7 @@ FILE: module_main_smartcastsFromEquals_differentModule.kt public final fun testFinal(x: R|Final<*>|, y: R|Final|): R|kotlin/Unit| { when () { ==(R|/x|, R|/y|) -> { - #(R|/x|) + R|/takeIntFinal|(R|/x|) } } @@ -61,7 +61,7 @@ FILE: module_main_smartcastsFromEquals_differentModule.kt public final fun testDerived(x: R|Derived<*>|, y: R|Derived|): R|kotlin/Unit| { when () { ==(R|/x|, R|/y|) -> { - #(R|/x|) + R|/takeIntDerived|(R|/x|) } } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.kt index e6c3e3c79e5..15710191344 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.kt +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.kt @@ -20,7 +20,10 @@ class FinalWithOverride { // MODULE: main(lib) fun testFinal(x: Final<*>, y: Final) { if (x == y) { - takeIntFinal(x) // Error + // No error, even while `Final` belongs to a different module and "equals" contract might be changed without re-compilation + // But since we had such behavior in FE1.0, it might be too strict to prohibit it now, especially once there's a lot of cases + // when different modules belong to a single project, so they're totally safe (see KT-50534) + takeIntFinal(x) } if (x === y) { takeIntFinal(x) // OK @@ -38,7 +41,10 @@ fun testBase(x: Base<*>, y: Base) { fun testDerived(x: Derived<*>, y: Derived) { if (x == y) { - takeIntDerived(x) // Error + // No error, even while `Final` belongs to a different module and "equals" contract might be changed without re-compilation + // But since we had such behavior in FE1.0, it might be too strict to prohibit it now, especially once there's a lot of cases + // when different modules belong to a single project, so they're totally safe (see KT-50534) + takeIntDerived(x) } if (x === y) { takeIntDerived(x) // OK 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 1aad2c184ad..46416a281fb 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 @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.contracts.description.ConeConstantReference import org.jetbrains.kotlin.fir.contracts.description.ConeReturnsEffectDeclaration import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor -import org.jetbrains.kotlin.fir.declarations.utils.isFinal import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference @@ -30,7 +29,10 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.scopes.getFunctions import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol -import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.StandardClassIds @@ -710,10 +712,17 @@ abstract class FirDataFlowAnalyzer( if (status.isExpect) return true when (classId) { StandardClassIds.Any, StandardClassIds.String -> return false + // Float and Double effectively had non-trivial `equals` semantics while they don't have explicit overrides (see KT-50535) + StandardClassIds.Float, StandardClassIds.Double -> return true } - if (moduleData != session.moduleData) { - return true - } + + // When the class belongs to a different module, "equals" contract might be changed without re-compilation + // But since we had such behavior in FE1.0, it might be too strict to prohibit it now, especially once there's a lot of cases + // when different modules belong to a single project, so they're totally safe (see KT-50534) + // if (moduleData != session.moduleData) { + // return true + // } + return session.declaredMemberScope(this) .getFunctions(OperatorNameConventions.EQUALS) .any { it.fir.isEquals() }