FIR: fix infinite recursion with equality operator checker

This commit is contained in:
Tianyu Geng
2021-04-28 14:13:24 -07:00
committed by teamcityserver
parent d4717569b9
commit db55a973d4
7 changed files with 77 additions and 3 deletions
@@ -620,6 +620,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
}
@Test
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
}
@Test
@TestMetadata("ReserveYield.kt")
public void testReserveYield() throws Exception {
@@ -620,6 +620,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
}
@Test
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
}
@Test
@TestMetadata("ReserveYield.kt")
public void testReserveYield() throws Exception {
@@ -98,7 +98,8 @@ internal object ConeTypeCompatibilityChecker {
private fun ConeInferenceContext.areCompatible(
upperBounds: Set<ConeClassLikeType>,
lowerBounds: Set<ConeClassLikeType>,
compatibilityUpperBound: Compatibility
compatibilityUpperBound: Compatibility,
checkedTypeParameters: MutableSet<FirTypeParameterRef> = mutableSetOf(),
): Compatibility {
val upperBoundClasses: Set<FirClassWithSuperClasses> = upperBounds.mapNotNull { it.toFirClassWithSuperClasses(this) }.toSet()
@@ -134,8 +135,17 @@ internal object ConeTypeCompatibilityChecker {
}
}
var result = Compatibility.COMPATIBLE
val typeArgsCompatibility = typeArgumentMapping.values.asSequence()
.map { (upper, lower, compatibilityUpperBound) -> areCompatible(upper, lower, compatibilityUpperBound) }
val typeArgsCompatibility = typeArgumentMapping.asSequence()
.map { (paramRef, boundTypeArguments) ->
val (upper, lower, compatibility) = boundTypeArguments
if (paramRef in checkedTypeParameters) {
// if we are already checking this type parameter, simply bail out to prevent infinite recursion.
Compatibility.COMPATIBLE
} else {
checkedTypeParameters.add(paramRef)
areCompatible(upper, lower, compatibility, checkedTypeParameters)
}
}
for (compatibility in typeArgsCompatibility) {
if (compatibility == compatibilityUpperBound) return compatibility
if (compatibility > result) {
@@ -0,0 +1,9 @@
interface Foo<out T>
interface Bar1 : Foo<Bar1>
interface Bar2 : Foo<Bar2>
class Bar3 : Foo<Bar3>
fun test(b1: Bar1, b2: Bar2, b3: Bar3) {
b1 == b2
<!EQUALITY_NOT_APPLICABLE_WARNING!>b1 == b3<!>
}
@@ -0,0 +1,9 @@
interface Foo<out T>
interface Bar1 : Foo<Bar1>
interface Bar2 : Foo<Bar2>
class Bar3 : Foo<Bar3>
fun test(b1: Bar1, b2: Bar2, b3: Bar3) {
b1 == b2
<!EQUALITY_NOT_APPLICABLE!>b1 == b3<!>
}
@@ -0,0 +1,28 @@
package
public fun test(/*0*/ b1: Bar1, /*1*/ b2: Bar2, /*2*/ b3: Bar3): kotlin.Unit
public interface Bar1 : Foo<Bar1> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface Bar2 : Foo<Bar2> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Bar3 : Foo<Bar3> {
public constructor Bar3()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface Foo</*0*/ out T> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -620,6 +620,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
}
@Test
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
}
@Test
@TestMetadata("ReserveYield.kt")
public void testReserveYield() throws Exception {