Common supertypes: unwrap captured type from DNN type during recursion control

This commit handles subtle situation when K1 represents flexible type
arguments as just T..T?, but K2 does it as T&Any..T?.
This can provoke a type like Captured(*)&Any..Captured(*)?,
and before this commit we couldn't find recursion inside Captured(*)&Any.
This could lead to explosions inside type system and inference errors

#KT-60581 Fixed
This commit is contained in:
Mikhail Glukhikh
2023-09-21 14:22:49 +02:00
committed by Space Team
parent 610a9d9c6a
commit aea7b8f00a
5 changed files with 4 additions and 92 deletions
@@ -421,10 +421,10 @@ object NewCommonSuperTypeCalculator {
}
private fun TypeSystemCommonSuperTypesContext.isCapturedStarProjection(type: SimpleTypeMarker): Boolean =
type.asCapturedType()?.typeConstructor()?.projection()?.isStarProjection() == true
type.originalIfDefinitelyNotNullable().asCapturedType()?.typeConstructor()?.projection()?.isStarProjection() == true
private fun TypeSystemCommonSuperTypesContext.supertypesIfCapturedStarProjection(type: SimpleTypeMarker): Collection<KotlinTypeMarker>? {
val constructor = type.asCapturedType()?.typeConstructor() ?: return null
val constructor = type.originalIfDefinitelyNotNullable().asCapturedType()?.typeConstructor() ?: return null
return if (constructor.projection().isStarProjection())
constructor.supertypes()
else null
@@ -1,85 +0,0 @@
// ISSUE: KT-60581
// WITH_STDLIB
// ---------------------- AssertJ declarations --------------------------
// FILE: AbstractAssert.java
public abstract class AbstractAssert<SELF extends AbstractAssert<SELF, ACTUAL>, ACTUAL> {}
// FILE: EnumerableAssert.java
public interface EnumerableAssert<SELF extends EnumerableAssert<SELF, ELEMENT>, ELEMENT> {}
// FILE: ObjectEnumerableAssert.java
public interface ObjectEnumerableAssert<SELF extends ObjectEnumerableAssert<SELF, ELEMENT>, ELEMENT>
extends EnumerableAssert<SELF, ELEMENT> {}
// FILE: IndexedObjectEnumerableAssert.java
public interface IndexedObjectEnumerableAssert<SELF extends IndexedObjectEnumerableAssert<SELF, ELEMENT>, ELEMENT>
extends ObjectEnumerableAssert<SELF, ELEMENT> {}
// FILE: AbstractIterableAssert.java
public abstract class AbstractIterableAssert<
SELF extends AbstractIterableAssert<SELF, ACTUAL, ELEMENT, ELEMENT_ASSERT>,
ACTUAL extends Iterable<? extends ELEMENT>,
ELEMENT,
ELEMENT_ASSERT extends AbstractAssert<ELEMENT_ASSERT, ELEMENT>>
extends AbstractAssert<SELF, ACTUAL> implements ObjectEnumerableAssert<SELF, ELEMENT> {}
// FILE: AbstractListAssert.java
public abstract class AbstractListAssert<
SELF extends AbstractListAssert<SELF, ACTUAL, ELEMENT, ELEMENT_ASSERT>,
ACTUAL extends List<? extends ELEMENT>,
ELEMENT,
ELEMENT_ASSERT extends AbstractAssert<ELEMENT_ASSERT, ELEMENT>>
extends AbstractIterableAssert<SELF, ACTUAL, ELEMENT, ELEMENT_ASSERT>
implements IndexedObjectEnumerableAssert<SELF, ELEMENT> {
SELF isNotEmpty() {
return null;
}
}
// FILE: ListAssert.java
public class ListAssert<ELEMENT> extends AbstractListAssert<ListAssert<ELEMENT>, List<? extends ELEMENT>, ELEMENT, ObjectAssert<ELEMENT>> {}
// FILE: AbstractCharSequenceAssert.java
public abstract class AbstractCharSequenceAssert<SELF extends AbstractCharSequenceAssert<SELF, ACTUAL>, ACTUAL extends CharSequence>
extends AbstractAssert<SELF, ACTUAL> implements EnumerableAssert<SELF, Character> {}
// FILE: AbstractStringAssert.java
public class AbstractStringAssert<SELF extends AbstractStringAssert<SELF>> extends AbstractCharSequenceAssert<SELF, String> {
public SELF isEqualTo(String expected) {
return null;
}
}
// FILE: StringAssert.java
public class StringAssert extends AbstractStringAssert<StringAssert> {}
// FILE: test/Assertions.java
import java.util.List;
public class Assertions {
public static <ELEMENT> ListAssert<ELEMENT> assertThat(java.util.List<? extends ELEMENT> actual) {
return null;
}
public static AbstractStringAssert<?> assertThat(String actual) {
return null;
}
}
// FILE: foo.kt
fun test() {
val sessionIds = listOf("")
val directSessionIds = listOf("")
<!NEW_INFERENCE_ERROR!>if (true) {
if (true) {
Assertions.assertThat(sessionIds[0])
} else {
Assertions.assertThat(directSessionIds)
}
} else {
Assertions.assertThat(sessionIds)
}<!>
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// ISSUE: KT-60581
// WITH_STDLIB
File diff suppressed because one or more lines are too long
@@ -72,7 +72,5 @@ fun test() {
true -> Assertions.assertThat(listOf("foo")).isNotEmpty
else -> Assertions.assertThat("bar").isEqualTo("bar")
}
// TODO: FIR
// {AbstractAssert<*, out Any!>! & EnumerableAssert<*, {Comparable<*> & java.io.Serializable!}>!} with unfolded flexible nullability
<!DEBUG_INFO_EXPRESSION_TYPE("({AbstractAssert<*, out (Any..Any?)> & EnumerableAssert<*, out ({Comparable<*> & java.io.Serializable}..{Comparable<*>? & java.io.Serializable?})>}..{AbstractAssert<*, out (Any..Any?)>? & EnumerableAssert<*, out ({Comparable<*> & java.io.Serializable}..{Comparable<*>? & java.io.Serializable?})>?})")!>assertion<!>
}