[kotlin] Fixed infinite recursion in MakeUpperBoundNonNullableFix

There was an infinite loop in the quick fix factory for "Make upper
bound non-nullable" quick fix during the search for type parameters that
would differ in nullability. The loop occurred when processing some
types containing the star projection (e.g., `Enum<*>` and
`Class<Enum<*>>`).

This commit fixes the infinite loop by adding an
explicit check to skip the recursive call if any involved type
projection is a star projection.

^KTIJ-21154 Fixed

Cherry-picked from 334c4ea9d094ca4974d300f78544feb8460a81a7

IJ-CR-20929

GitOrigin-RevId: 3fe9693e107a92f13b5e158a6b2bf5a0b80ec887
This commit is contained in:
Dmitry Timofeev
2022-02-17 14:52:34 +00:00
committed by intellij-monorepo-bot
parent 4c436ea3bb
commit b5cbcf9fb1
3 changed files with 26 additions and 1 deletions
@@ -147,7 +147,9 @@ open class MakeUpperBoundNonNullableFix(
}
for ((actualProjection, expectedProjection) in actual.arguments.zip(expected.arguments)) {
result.addAll(extractPotentiallyFixableTypesForExpectedType(actualProjection.type, expectedProjection.type))
if (!actualProjection.isStarProjection && !expectedProjection.isStarProjection) {
result.addAll(extractPotentiallyFixableTypesForExpectedType(actualProjection.type, expectedProjection.type))
}
}
return result
@@ -9181,6 +9181,11 @@ public abstract class QuickFixTestGenerated extends AbstractQuickFixTest {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("noStackOverflowOnStarProjection.kt")
public void testNoStackOverflowOnStarProjection() throws Exception {
runTest("testData/quickfix/makeUpperBoundNonNullable/noStackOverflowOnStarProjection.kt");
}
@TestMetadata("typeMismatchAny1.kt")
public void testTypeMismatchAny1() throws Exception {
runTest("testData/quickfix/makeUpperBoundNonNullable/typeMismatchAny1.kt");
@@ -0,0 +1,18 @@
// "Add 'Any' as upper bound for T to make it non-nullable" "false"
// ERROR: Type mismatch: inferred type is Enum<*> but Enum<Enum<*>> was expected
// ERROR: Type mismatch: inferred type is Enum<*> but Enum<in Enum<*>> was expected
// ACTION: Change parameter 'enumClass' type of primary constructor of class 'Foo' to 'Class<Enum<*>>'
// ACTION: Create function 'Foo'
// ACTION: Create secondary constructor
// ACTION: Introduce import alias
// LANGUAGE_VERSION: 1.7
class Test
class Foo<T : Enum<T>>(private val enumClass: Class<T>) {
fun test() {}
}
fun bar() {
Foo(<caret>Test::class as Class<Enum<*>>).test()
}