Add test for KT-52782

It just demonstrates/fixate the current "broken" behavior in K1
that we unfortunately have and that is fixed in K2
This commit is contained in:
Denis.Zharkov
2022-08-24 12:22:18 +02:00
committed by teamcity
parent 01f567a16d
commit 490382b77f
8 changed files with 152 additions and 0 deletions
@@ -0,0 +1,62 @@
// SKIP_TXT
// FILE: Foo.java
public abstract class Foo<K extends Bar<? extends Foo<K>>> {
abstract String getTest();
}
// FILE: Bar.java
public abstract class Bar<T extends Foo<? extends Bar<T>>> {}
// FILE: main.kt
fun <F : Bar<out Foo<F>>> Foo<F>.bar() {}
fun box(foo: Foo<*>) {
// How inference for the `foo.bar()` call works
//
// X = Captured(*)
// Foo<X> <: Foo<Fv> => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X)
//
// Incorporation 1:
// X <: Fv && Fv <: Bar<out Foo<Fv>> => X <: Bar<out Foo<Fv>>
// X has one supertype Bar<out Foo<X>> ~ Bar<Y> where Y = Captured(out Foo<X>)
// X <: Bar<out Foo<Fv>> => Bar<Y> <: Bar<out Foo<Fv>> =>
// Y <: Foo<Fv>
// Y has two supertypes --> (Foo<out Bar<Y>>, Foo<X>)
// Let Z be a captured type in Foo<out Bar<Y>>
// Foo<Z> <: Foo<Fv> => Z = Fv =>
// But since Z is captured from subtyping we run approximation over it resulting to
// Z ~ Bar<out Foo<*>>
// NewBound(Bar<out Foo<*>> <: Fv)
//
// But since Fv <: X, Bar<out Foo<*>> should be a subtype of X, but it is not :(
//
// Note the problematic part is when Y has two supertypes
// And we just check only first one one the second one would work
// In K2, it's covered by fork-points, see https://youtrack.jetbrains.com/issue/KT-50401 and org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector.TypeCheckerStateForConstraintInjector.runForkingPoint
// Without approximation (just theoretically what would happen if we didn't approximated FROM_SUBTYPING captured types).
// Actually, it's not really relevant but just in case someone need it.
//
// X = Captured(*)
// Foo<X> <: Foo<Fv> => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X)
//
// Incorporation 1:
// X <: Fv && Fv <: Bar<out Foo<Fv>> => X <: Bar<out Foo<Fv>>
// X has one supertype Bar<out Foo<X>> ~ Bar<Y> where Y = Captured(out Foo<X>)
// X <: Bar<out Foo<Fv>> => Bar<Y> <: Bar<out Foo<Fv>> =>
// Y <: Foo<Fv>
// Y has two supertypes --> (Foo<out Bar<Y>>, Foo<X>)
// Let Z be a captured type in Foo<out Bar<Y>>
// Foo<Z> <: Foo<Fv> => Z = Fv => NewBound(Z <: Fv)
//
// Incorporation 2:
// Z <: Fv && Fv <: Bar<out Foo<Fv>> => Z <: Bar<out Foo<Fv>>
// Z has two supertypes --> (Bar<out Foo<Z>>, Bar<Y>)
// ... went into recursion
foo.bar()
foo.test
}
@@ -0,0 +1,62 @@
// SKIP_TXT
// FILE: Foo.java
public abstract class Foo<K extends Bar<? extends Foo<K>>> {
abstract String getTest();
}
// FILE: Bar.java
public abstract class Bar<T extends Foo<? extends Bar<T>>> {}
// FILE: main.kt
fun <F : Bar<out Foo<F>>> Foo<F>.bar() {}
fun box(foo: Foo<*>) {
// How inference for the `foo.bar()` call works
//
// X = Captured(*)
// Foo<X> <: Foo<Fv> => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X)
//
// Incorporation 1:
// X <: Fv && Fv <: Bar<out Foo<Fv>> => X <: Bar<out Foo<Fv>>
// X has one supertype Bar<out Foo<X>> ~ Bar<Y> where Y = Captured(out Foo<X>)
// X <: Bar<out Foo<Fv>> => Bar<Y> <: Bar<out Foo<Fv>> =>
// Y <: Foo<Fv>
// Y has two supertypes --> (Foo<out Bar<Y>>, Foo<X>)
// Let Z be a captured type in Foo<out Bar<Y>>
// Foo<Z> <: Foo<Fv> => Z = Fv =>
// But since Z is captured from subtyping we run approximation over it resulting to
// Z ~ Bar<out Foo<*>>
// NewBound(Bar<out Foo<*>> <: Fv)
//
// But since Fv <: X, Bar<out Foo<*>> should be a subtype of X, but it is not :(
//
// Note the problematic part is when Y has two supertypes
// And we just check only first one one the second one would work
// In K2, it's covered by fork-points, see https://youtrack.jetbrains.com/issue/KT-50401 and org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector.TypeCheckerStateForConstraintInjector.runForkingPoint
// Without approximation (just theoretically what would happen if we didn't approximated FROM_SUBTYPING captured types).
// Actually, it's not really relevant but just in case someone need it.
//
// X = Captured(*)
// Foo<X> <: Foo<Fv> => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X)
//
// Incorporation 1:
// X <: Fv && Fv <: Bar<out Foo<Fv>> => X <: Bar<out Foo<Fv>>
// X has one supertype Bar<out Foo<X>> ~ Bar<Y> where Y = Captured(out Foo<X>)
// X <: Bar<out Foo<Fv>> => Bar<Y> <: Bar<out Foo<Fv>> =>
// Y <: Foo<Fv>
// Y has two supertypes --> (Foo<out Bar<Y>>, Foo<X>)
// Let Z be a captured type in Foo<out Bar<Y>>
// Foo<Z> <: Foo<Fv> => Z = Fv => NewBound(Z <: Fv)
//
// Incorporation 2:
// Z <: Fv && Fv <: Bar<out Foo<Fv>> => Z <: Bar<out Foo<Fv>>
// Z has two supertypes --> (Bar<out Foo<Z>>, Bar<Y>)
// ... went into recursion
foo.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>bar<!>()
foo.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>test<!>
}
@@ -30,6 +30,8 @@ fun String.asFsdAddress(): String {
fun box(): String {
val state = Test().state
if (state is GoBuildingRunningState<*>) {
// Actually, that code is valid and met at IJ, but unfortunately it was broken since 1.7.0
// See KT-52782 and testData/diagnostics/tests/inference/capturedTypes/kt52782.kt
state.buildingWorkingDirectory.asFsdAddress()
}
return "OK"
@@ -30,6 +30,8 @@ fun String.asFsdAddress(): String {
fun box(): String {
val state = Test().state
if (state is GoBuildingRunningState<*>) {
// Actually, that code is valid and met at IJ, but unfortunately it was broken since 1.7.0
// See KT-52782 and testData/diagnostics/tests/inference/capturedTypes/kt52782.kt
state.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>buildingWorkingDirectory<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>asFsdAddress<!>()
}
return "OK"