[FE] Use indexed loop to prevent CME in incorporation

#KT-60225 Fixed
This commit is contained in:
Kirill Rakhman
2023-12-14 12:59:54 +01:00
committed by Space Team
parent 3e41faf91f
commit 3bfcf3090c
8 changed files with 61 additions and 3 deletions
@@ -16920,6 +16920,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/inference/receiverTypeMismatch_withoutProper.kt");
}
@Test
@TestMetadata("recursiveGenericExtensionReceiver.kt")
public void testRecursiveGenericExtensionReceiver() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/recursiveGenericExtensionReceiver.kt");
}
@Test
@TestMetadata("reportAboutUnresolvedReferenceAsUnresolved.kt")
public void testReportAboutUnresolvedReferenceAsUnresolved() throws Exception {
@@ -16920,6 +16920,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/inference/receiverTypeMismatch_withoutProper.kt");
}
@Test
@TestMetadata("recursiveGenericExtensionReceiver.kt")
public void testRecursiveGenericExtensionReceiver() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/recursiveGenericExtensionReceiver.kt");
}
@Test
@TestMetadata("reportAboutUnresolvedReferenceAsUnresolved.kt")
public void testReportAboutUnresolvedReferenceAsUnresolved() throws Exception {
@@ -16914,6 +16914,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/inference/receiverTypeMismatch_withoutProper.kt");
}
@Test
@TestMetadata("recursiveGenericExtensionReceiver.kt")
public void testRecursiveGenericExtensionReceiver() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/recursiveGenericExtensionReceiver.kt");
}
@Test
@TestMetadata("reportAboutUnresolvedReferenceAsUnresolved.kt")
public void testReportAboutUnresolvedReferenceAsUnresolved() throws Exception {
@@ -16920,6 +16920,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/inference/receiverTypeMismatch_withoutProper.kt");
}
@Test
@TestMetadata("recursiveGenericExtensionReceiver.kt")
public void testRecursiveGenericExtensionReceiver() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/recursiveGenericExtensionReceiver.kt");
}
@Test
@TestMetadata("reportAboutUnresolvedReferenceAsUnresolved.kt")
public void testReportAboutUnresolvedReferenceAsUnresolved() throws Exception {
@@ -27,7 +27,7 @@ class ConstraintIncorporator(
// if such type variable is fixed then it is error
fun getTypeVariable(typeConstructor: TypeConstructorMarker): TypeVariableMarker?
fun getConstraintsForVariable(typeVariable: TypeVariableMarker): Collection<Constraint>
fun getConstraintsForVariable(typeVariable: TypeVariableMarker): List<Constraint>
fun addNewIncorporatedConstraint(
lowerType: KotlinTypeMarker,
@@ -67,7 +67,7 @@ class ConstraintIncorporator(
// \alpha <: constraint.type
if (constraint.kind != ConstraintKind.LOWER) {
getConstraintsForVariable(typeVariable).forEach {
forEachConstraint(typeVariable) {
if (it.kind != ConstraintKind.UPPER) {
addNewIncorporatedConstraint(it.type, constraint.type, shouldBeTypeVariableFlexible, it.isNullabilityConstraint)
}
@@ -76,7 +76,7 @@ class ConstraintIncorporator(
// constraint.type <: \alpha
if (constraint.kind != ConstraintKind.UPPER) {
getConstraintsForVariable(typeVariable).forEach {
forEachConstraint(typeVariable) {
if (it.kind != ConstraintKind.LOWER) {
val isFromDeclaredUpperBound =
it.position.from is DeclaredUpperBoundConstraintPosition<*> && !it.type.typeConstructor().isTypeVariable()
@@ -92,6 +92,16 @@ class ConstraintIncorporator(
}
}
private inline fun Context.forEachConstraint(typeVariable: TypeVariableMarker, action: (Constraint) -> Unit) {
// We use an indexed loop because the collection might be modified during the iteration.
// However, the only modification is appending, so we should be fine.
val constraints = getConstraintsForVariable(typeVariable)
var i = 0
while (i < constraints.size) {
action(constraints[i++])
}
}
// \alpha <: Number, \beta <: Inv<\alpha> => \beta <: Inv<out Number>
private fun Context.insideOtherConstraint(
typeVariable: TypeVariableMarker,
@@ -46,6 +46,14 @@ class MutableVariableWithConstraints private constructor(
private val mutableConstraints = if (constraints == null) SmartList() else SmartList(constraints)
/**
* The contract for mutating this list is that the only allowed mutation is appending items.
* In any other case, it must be set to `null`, so that it will be recomputed when [constraints] is called.
*
* The reason is that the list might be mutated while it's being iterated.
* For this reason, we use an index loop in
* [org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintIncorporator.forEachConstraint].
*/
private var simplifiedConstraints: SmartList<Constraint>? = mutableConstraints
val rawConstraintsCount get() = mutableConstraints.size
@@ -0,0 +1,10 @@
// FIR_IDENTICAL
// ISSUE: KT-60225
class Klass<T: Klass<T>>
fun <T: Klass<T>> Klass<T>.foo() {}
fun main() {
Klass().foo()
}
@@ -16920,6 +16920,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/inference/receiverTypeMismatch_withoutProper.kt");
}
@Test
@TestMetadata("recursiveGenericExtensionReceiver.kt")
public void testRecursiveGenericExtensionReceiver() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/recursiveGenericExtensionReceiver.kt");
}
@Test
@TestMetadata("reportAboutUnresolvedReferenceAsUnresolved.kt")
public void testReportAboutUnresolvedReferenceAsUnresolved() throws Exception {