[FIR] Add smartcasts from == if equals is from Any

^KT-49127 Fixed
This commit is contained in:
Dmitriy Novozhilov
2021-12-01 13:50:55 +03:00
committed by teamcityserver
parent ac718cd1c4
commit 1f0b62b25f
16 changed files with 472 additions and 29 deletions
@@ -0,0 +1,96 @@
Module: lib
FILE: module_lib_smartcastsFromEquals_differentModule.kt
public final class Final<T> : R|kotlin/Any| {
public constructor<T>(): R|Final<T>| {
super<R|kotlin/Any|>()
}
}
public open class Base<T> : R|kotlin/Any| {
public constructor<T>(): R|Base<T>| {
super<R|kotlin/Any|>()
}
}
public final class Derived<T> : R|Base<T>| {
public constructor<T>(): R|Derived<T>| {
super<R|Base<T>|>()
}
}
public final class FinalWithOverride<T> : R|kotlin/Any| {
public constructor<T>(): R|FinalWithOverride<T>| {
super<R|kotlin/Any|>()
}
public final override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| {
^equals ===(this@R|/FinalWithOverride|, R|<local>/other|)
}
}
Module: main
FILE: module_main_smartcastsFromEquals_differentModule.kt
public final fun testFinal(x: R|Final<*>|, y: R|Final<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
<Inapplicable(INAPPLICABLE): /takeIntFinal>#(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntFinal|(R|<local>/x|)
}
}
}
public final fun testBase(x: R|Base<*>|, y: R|Base<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
<Inapplicable(INAPPLICABLE): /takeIntBase>#(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntBase|(R|<local>/x|)
}
}
}
public final fun testDerived(x: R|Derived<*>|, y: R|Derived<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
<Inapplicable(INAPPLICABLE): /takeIntDerived>#(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntDerived|(R|<local>/x|)
}
}
}
public final fun testFinalWithOverride(x: R|FinalWithOverride<*>|, y: R|FinalWithOverride<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
<Inapplicable(INAPPLICABLE): /takeIntFinalWithOverride>#(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntFinalWithOverride|(R|<local>/x|)
}
}
}
public final fun takeIntFinal(x: R|Final<kotlin/Int>|): R|kotlin/Unit| {
}
public final fun takeIntBase(x: R|Base<kotlin/Int>|): R|kotlin/Unit| {
}
public final fun takeIntDerived(x: R|Derived<kotlin/Int>|): R|kotlin/Unit| {
}
public final fun takeIntFinalWithOverride(x: R|FinalWithOverride<kotlin/Int>|): R|kotlin/Unit| {
}
@@ -0,0 +1,60 @@
// SKIP_JAVAC
// This directive is needed to skip this test in LazyBodyIsNotTouchedTilContractsPhaseTestGenerated,
// because it fails to parse module structure of multimodule test
// ISSUE: KT-49127
// MODULE: lib
class Final<T>
open class Base<T>
class Derived<T> : Base<T>()
class FinalWithOverride<T> {
override fun equals(other: Any?): Boolean {
// some custom implementation
return this === other
}
}
// MODULE: main(lib)
fun testFinal(x: Final<*>, y: Final<Int>) {
if (x == y) {
takeIntFinal(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // Error
}
if (x === y) {
takeIntFinal(x) // OK
}
}
fun testBase(x: Base<*>, y: Base<Int>) {
if (x == y) {
takeIntBase(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // Error
}
if (x === y) {
takeIntBase(x) // OK
}
}
fun testDerived(x: Derived<*>, y: Derived<Int>) {
if (x == y) {
takeIntDerived(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // Error
}
if (x === y) {
takeIntDerived(x) // OK
}
}
fun testFinalWithOverride(x: FinalWithOverride<*>, y: FinalWithOverride<Int>) {
if (x == y) {
takeIntFinalWithOverride(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // Error
}
if (x === y) {
takeIntFinalWithOverride(x) // OK
}
}
fun takeIntFinal(x: Final<Int>) {}
fun takeIntBase(x: Base<Int>) {}
fun takeIntDerived(x: Derived<Int>) {}
fun takeIntFinalWithOverride(x: FinalWithOverride<Int>) {}
@@ -0,0 +1,93 @@
FILE: smartcastsFromEquals_sameModule.kt
public final class Final<T> : R|kotlin/Any| {
public constructor<T>(): R|Final<T>| {
super<R|kotlin/Any|>()
}
}
public open class Base<T> : R|kotlin/Any| {
public constructor<T>(): R|Base<T>| {
super<R|kotlin/Any|>()
}
}
public final class Derived<T> : R|Base<T>| {
public constructor<T>(): R|Derived<T>| {
super<R|Base<T>|>()
}
}
public final class FinalWithOverride<T> : R|kotlin/Any| {
public constructor<T>(): R|FinalWithOverride<T>| {
super<R|kotlin/Any|>()
}
public final override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| {
^equals ===(this@R|/FinalWithOverride|, R|<local>/other|)
}
}
public final fun testFinal(x: R|Final<*>|, y: R|Final<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntFinal|(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntFinal|(R|<local>/x|)
}
}
}
public final fun testBase(x: R|Base<*>|, y: R|Base<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
<Inapplicable(INAPPLICABLE): /takeIntBase>#(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntBase|(R|<local>/x|)
}
}
}
public final fun testDerived(x: R|Derived<*>|, y: R|Derived<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntDerived|(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntDerived|(R|<local>/x|)
}
}
}
public final fun testFinalWithOverride(x: R|FinalWithOverride<*>|, y: R|FinalWithOverride<kotlin/Int>|): R|kotlin/Unit| {
when () {
==(R|<local>/x|, R|<local>/y|) -> {
<Inapplicable(INAPPLICABLE): /takeIntFinalWithOverride>#(R|<local>/x|)
}
}
when () {
===(R|<local>/x|, R|<local>/y|) -> {
R|/takeIntFinalWithOverride|(R|<local>/x|)
}
}
}
public final fun takeIntFinal(x: R|Final<kotlin/Int>|): R|kotlin/Unit| {
}
public final fun takeIntBase(x: R|Base<kotlin/Int>|): R|kotlin/Unit| {
}
public final fun takeIntDerived(x: R|Derived<kotlin/Int>|): R|kotlin/Unit| {
}
public final fun takeIntFinalWithOverride(x: R|FinalWithOverride<kotlin/Int>|): R|kotlin/Unit| {
}
@@ -0,0 +1,55 @@
// ISSUE: KT-49127
class Final<T>
open class Base<T>
class Derived<T> : Base<T>()
class FinalWithOverride<T> {
override fun equals(other: Any?): Boolean {
// some custom implementation
return this === other
}
}
fun testFinal(x: Final<*>, y: Final<Int>) {
if (x == y) {
takeIntFinal(x) // OK
}
if (x === y) {
takeIntFinal(x) // OK
}
}
fun testBase(x: Base<*>, y: Base<Int>) {
if (x == y) {
takeIntBase(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // Error
}
if (x === y) {
takeIntBase(x) // OK
}
}
fun testDerived(x: Derived<*>, y: Derived<Int>) {
if (x == y) {
takeIntDerived(x) // OK
}
if (x === y) {
takeIntDerived(x) // OK
}
}
fun testFinalWithOverride(x: FinalWithOverride<*>, y: FinalWithOverride<Int>) {
if (x == y) {
takeIntFinalWithOverride(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // Error
}
if (x === y) {
takeIntFinalWithOverride(x) // OK
}
}
fun takeIntFinal(x: Final<Int>) {}
fun takeIntBase(x: Base<Int>) {}
fun takeIntDerived(x: Derived<Int>) {}
fun takeIntFinalWithOverride(x: FinalWithOverride<Int>) {}