[NI] CST: add preemptive recursion detection

For single super type constructor create star projection argument when types for that argument are equal to the original types.
Captured star projections are replaced with their corresponding supertypes during this check.
Skip check for `in` parameters, for which recursive cst calculation does not happen.
Adjust constant in fallback recursion condition.

^KT-38544 Fixed
This commit is contained in:
Pavel Kirpichenkov
2020-04-29 20:35:24 +03:00
parent 7cde9b4355
commit 003ba1c8f5
44 changed files with 1505 additions and 59 deletions
@@ -0,0 +1,79 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER, -UNUSED_EXPRESSION
// Issue: KT-35844
// ---------------------- 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: Assertions.java
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;
}
}
// ---------------------- AssertJ declarations end --------------------------
// FILE: test.kt
fun test() {
val assertion = when {
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 AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!> & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>..AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!>? & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>?, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!> & EnumerableAssert<out AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!> & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>..AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!>? & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>?, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>..AbstractAssert<out AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!> & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>..AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!>? & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>?, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!>? & EnumerableAssert<out AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!> & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>..AbstractAssert<*, out ERROR CLASS: Unresolved: <error>..ERROR CLASS: Unresolved: <error>!>? & EnumerableAssert<*, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>?, out kotlin.Comparable<kotlin.String & kotlin.Char> & java.io.Serializable..kotlin.Comparable<kotlin.String & kotlin.Char>? & java.io.Serializable?>?")!>assertion<!>
}
@@ -0,0 +1,79 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER, -UNUSED_EXPRESSION
// Issue: KT-35844
// ---------------------- 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: Assertions.java
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;
}
}
// ---------------------- AssertJ declarations end --------------------------
// FILE: test.kt
fun test() {
val assertion = when {
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 (kotlin.Any..kotlin.Any?)> & EnumerableAssert<*, out ({Comparable<*> & java.io.Serializable}..{Comparable<*>? & java.io.Serializable?})>}..{AbstractAssert<*, out (kotlin.Any..kotlin.Any?)>? & EnumerableAssert<*, out ({Comparable<*> & java.io.Serializable}..{Comparable<*>? & java.io.Serializable?})>?})")!>assertion<!>
}
@@ -0,0 +1,85 @@
package
public fun test(): kotlin.Unit
public abstract class AbstractAssert</*0*/ SELF : AbstractAssert<SELF!, ACTUAL!>!, /*1*/ ACTUAL : kotlin.Any!> {
public constructor AbstractAssert</*0*/ SELF : AbstractAssert<SELF!, ACTUAL!>!, /*1*/ ACTUAL : kotlin.Any!>()
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 abstract class AbstractCharSequenceAssert</*0*/ SELF : AbstractCharSequenceAssert<SELF!, ACTUAL!>!, /*1*/ ACTUAL : kotlin.CharSequence!> : AbstractAssert<SELF!, ACTUAL!>, EnumerableAssert<SELF!, kotlin.Char!> {
public constructor AbstractCharSequenceAssert</*0*/ SELF : AbstractCharSequenceAssert<SELF!, ACTUAL!>!, /*1*/ ACTUAL : kotlin.CharSequence!>()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract class AbstractIterableAssert</*0*/ SELF : AbstractIterableAssert<SELF!, ACTUAL!, ELEMENT!, ELEMENT_ASSERT!>!, /*1*/ ACTUAL : kotlin.collections.(Mutable)Iterable<ELEMENT!>!, /*2*/ ELEMENT : kotlin.Any!, /*3*/ ELEMENT_ASSERT : AbstractAssert<ELEMENT_ASSERT!, ELEMENT!>!> : AbstractAssert<SELF!, ACTUAL!>, ObjectEnumerableAssert<SELF!, ELEMENT!> {
public constructor AbstractIterableAssert</*0*/ SELF : AbstractIterableAssert<SELF!, ACTUAL!, ELEMENT!, ELEMENT_ASSERT!>!, /*1*/ ACTUAL : kotlin.collections.(Mutable)Iterable<ELEMENT!>!, /*2*/ ELEMENT : kotlin.Any!, /*3*/ ELEMENT_ASSERT : AbstractAssert<ELEMENT_ASSERT!, ELEMENT!>!>()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract class AbstractListAssert</*0*/ SELF : AbstractListAssert<SELF!, ACTUAL!, ELEMENT!, ELEMENT_ASSERT!>!, /*1*/ ACTUAL : List!, /*2*/ ELEMENT : kotlin.Any!, /*3*/ ELEMENT_ASSERT : AbstractAssert<ELEMENT_ASSERT!, ELEMENT!>!> : AbstractIterableAssert<SELF!, ACTUAL!, ELEMENT!, ELEMENT_ASSERT!>, IndexedObjectEnumerableAssert<SELF!, ELEMENT!> {
public constructor AbstractListAssert</*0*/ SELF : AbstractListAssert<SELF!, ACTUAL!, ELEMENT!, ELEMENT_ASSERT!>!, /*1*/ ACTUAL : List!, /*2*/ ELEMENT : kotlin.Any!, /*3*/ ELEMENT_ASSERT : AbstractAssert<ELEMENT_ASSERT!, ELEMENT!>!>()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public/*package*/ open fun isNotEmpty(): SELF!
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class AbstractStringAssert</*0*/ SELF : AbstractStringAssert<SELF!>!> : AbstractCharSequenceAssert<SELF!, kotlin.String!> {
public constructor AbstractStringAssert</*0*/ SELF : AbstractStringAssert<SELF!>!>()
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 fun isEqualTo(/*0*/ expected: kotlin.String!): SELF!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class Assertions {
public constructor Assertions()
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
// Static members
public open fun </*0*/ ELEMENT : kotlin.Any!> assertThat(/*0*/ actual: (kotlin.collections.MutableList<out ELEMENT!>..kotlin.collections.List<ELEMENT!>?)): ListAssert<ELEMENT!>!
public open fun assertThat(/*0*/ actual: kotlin.String!): AbstractStringAssert<*>!
}
public interface EnumerableAssert</*0*/ SELF : EnumerableAssert<SELF!, ELEMENT!>!, /*1*/ ELEMENT : kotlin.Any!> {
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 IndexedObjectEnumerableAssert</*0*/ SELF : IndexedObjectEnumerableAssert<SELF!, ELEMENT!>!, /*1*/ ELEMENT : kotlin.Any!> : ObjectEnumerableAssert<SELF!, ELEMENT!> {
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 open class ListAssert</*0*/ ELEMENT : kotlin.Any!> : AbstractListAssert<ListAssert<ELEMENT!>!, List!, ELEMENT!, ObjectAssert!> {
public constructor ListAssert</*0*/ ELEMENT : kotlin.Any!>()
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/*package*/ open override /*1*/ /*fake_override*/ fun isNotEmpty(): ListAssert<ELEMENT!>!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface ObjectEnumerableAssert</*0*/ SELF : ObjectEnumerableAssert<SELF!, ELEMENT!>!, /*1*/ ELEMENT : kotlin.Any!> : EnumerableAssert<SELF!, ELEMENT!> {
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 open class StringAssert : AbstractStringAssert<StringAssert!> {
public constructor StringAssert()
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 isEqualTo(/*0*/ expected: kotlin.String!): StringAssert!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}