FIR: Fix smartcast case after equals on class from different module
^KT-50534 Relates
This commit is contained in:
compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastsFromEquals_differentModule.fir.txt
Vendored
+2
-2
@@ -33,7 +33,7 @@ FILE: module_main_smartcastsFromEquals_differentModule.kt
|
|||||||
public final fun testFinal(x: R|Final<*>|, y: R|Final<kotlin/Int>|): R|kotlin/Unit| {
|
public final fun testFinal(x: R|Final<*>|, y: R|Final<kotlin/Int>|): R|kotlin/Unit| {
|
||||||
when () {
|
when () {
|
||||||
==(R|<local>/x|, R|<local>/y|) -> {
|
==(R|<local>/x|, R|<local>/y|) -> {
|
||||||
<Inapplicable(INAPPLICABLE): /takeIntFinal>#(R|<local>/x|)
|
R|/takeIntFinal|(R|<local>/x|)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ FILE: module_main_smartcastsFromEquals_differentModule.kt
|
|||||||
public final fun testDerived(x: R|Derived<*>|, y: R|Derived<kotlin/Int>|): R|kotlin/Unit| {
|
public final fun testDerived(x: R|Derived<*>|, y: R|Derived<kotlin/Int>|): R|kotlin/Unit| {
|
||||||
when () {
|
when () {
|
||||||
==(R|<local>/x|, R|<local>/y|) -> {
|
==(R|<local>/x|, R|<local>/y|) -> {
|
||||||
<Inapplicable(INAPPLICABLE): /takeIntDerived>#(R|<local>/x|)
|
R|/takeIntDerived|(R|<local>/x|)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
-2
@@ -20,7 +20,10 @@ class FinalWithOverride<T> {
|
|||||||
// MODULE: main(lib)
|
// MODULE: main(lib)
|
||||||
fun testFinal(x: Final<*>, y: Final<Int>) {
|
fun testFinal(x: Final<*>, y: Final<Int>) {
|
||||||
if (x == y) {
|
if (x == y) {
|
||||||
takeIntFinal(<!ARGUMENT_TYPE_MISMATCH!>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) {
|
if (x === y) {
|
||||||
takeIntFinal(x) // OK
|
takeIntFinal(x) // OK
|
||||||
@@ -38,7 +41,10 @@ fun testBase(x: Base<*>, y: Base<Int>) {
|
|||||||
|
|
||||||
fun testDerived(x: Derived<*>, y: Derived<Int>) {
|
fun testDerived(x: Derived<*>, y: Derived<Int>) {
|
||||||
if (x == y) {
|
if (x == y) {
|
||||||
takeIntDerived(<!ARGUMENT_TYPE_MISMATCH!>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) {
|
if (x === y) {
|
||||||
takeIntDerived(x) // OK
|
takeIntDerived(x) // OK
|
||||||
|
|||||||
+14
-5
@@ -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.contracts.description.ConeReturnsEffectDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
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.declarations.utils.isLocal
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
|
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.getFunctions
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
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.types.*
|
||||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
@@ -710,10 +712,17 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
if (status.isExpect) return true
|
if (status.isExpect) return true
|
||||||
when (classId) {
|
when (classId) {
|
||||||
StandardClassIds.Any, StandardClassIds.String -> return false
|
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)
|
return session.declaredMemberScope(this)
|
||||||
.getFunctions(OperatorNameConventions.EQUALS)
|
.getFunctions(OperatorNameConventions.EQUALS)
|
||||||
.any { it.fir.isEquals() }
|
.any { it.fir.isEquals() }
|
||||||
|
|||||||
Reference in New Issue
Block a user