FIR: fix infinite recursion with equality operator checker
This commit is contained in:
committed by
teamcityserver
parent
d4717569b9
commit
db55a973d4
+6
@@ -620,6 +620,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
|
||||||
|
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("ReserveYield.kt")
|
@TestMetadata("ReserveYield.kt")
|
||||||
public void testReserveYield() throws Exception {
|
public void testReserveYield() throws Exception {
|
||||||
|
|||||||
+6
@@ -620,6 +620,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
|
||||||
|
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("ReserveYield.kt")
|
@TestMetadata("ReserveYield.kt")
|
||||||
public void testReserveYield() throws Exception {
|
public void testReserveYield() throws Exception {
|
||||||
|
|||||||
+13
-3
@@ -98,7 +98,8 @@ internal object ConeTypeCompatibilityChecker {
|
|||||||
private fun ConeInferenceContext.areCompatible(
|
private fun ConeInferenceContext.areCompatible(
|
||||||
upperBounds: Set<ConeClassLikeType>,
|
upperBounds: Set<ConeClassLikeType>,
|
||||||
lowerBounds: Set<ConeClassLikeType>,
|
lowerBounds: Set<ConeClassLikeType>,
|
||||||
compatibilityUpperBound: Compatibility
|
compatibilityUpperBound: Compatibility,
|
||||||
|
checkedTypeParameters: MutableSet<FirTypeParameterRef> = mutableSetOf(),
|
||||||
): Compatibility {
|
): Compatibility {
|
||||||
val upperBoundClasses: Set<FirClassWithSuperClasses> = upperBounds.mapNotNull { it.toFirClassWithSuperClasses(this) }.toSet()
|
val upperBoundClasses: Set<FirClassWithSuperClasses> = upperBounds.mapNotNull { it.toFirClassWithSuperClasses(this) }.toSet()
|
||||||
|
|
||||||
@@ -134,8 +135,17 @@ internal object ConeTypeCompatibilityChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var result = Compatibility.COMPATIBLE
|
var result = Compatibility.COMPATIBLE
|
||||||
val typeArgsCompatibility = typeArgumentMapping.values.asSequence()
|
val typeArgsCompatibility = typeArgumentMapping.asSequence()
|
||||||
.map { (upper, lower, compatibilityUpperBound) -> areCompatible(upper, lower, compatibilityUpperBound) }
|
.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) {
|
for (compatibility in typeArgsCompatibility) {
|
||||||
if (compatibility == compatibilityUpperBound) return compatibility
|
if (compatibility == compatibilityUpperBound) return compatibility
|
||||||
if (compatibility > result) {
|
if (compatibility > result) {
|
||||||
|
|||||||
+9
@@ -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
|
||||||
|
}
|
||||||
Generated
+6
@@ -620,6 +620,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
|
||||||
|
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("ReserveYield.kt")
|
@TestMetadata("ReserveYield.kt")
|
||||||
public void testReserveYield() throws Exception {
|
public void testReserveYield() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user