Add tests for inferring self types from Java

This commit is contained in:
Victor Petukhov
2021-07-07 14:19:55 +03:00
parent 3b16865152
commit 9e48ef85ea
11 changed files with 171 additions and 10 deletions
@@ -2,7 +2,6 @@
class Builder<B : Builder<B>> {
fun <T : B> test(): T = TODO()
fun foo() {}
}
@@ -2,7 +2,6 @@
class Builder<B : Builder<B>> {
fun <T : B> test(): T = TODO()
fun foo() {}
}
@@ -1,5 +1,14 @@
// !LANGUAGE: +TypeInferenceOnCallsWithSelfTypes
// FILE: JavaBuilder.java
public class JavaBuilder<B extends JavaBuilder<B>> {
<T extends B> T test() {
return null;
}
void foo() { }
}
// FILE: main.kt
class Builder<B : Builder<B>> {
fun <T : B> test(): T = TODO()
@@ -7,7 +16,7 @@ class Builder<B : Builder<B>> {
}
fun testStar(builder: Builder<*>) {
builder.test()
<!DEBUG_INFO_EXPRESSION_TYPE("Builder<*>")!>builder.test()<!>
builder
.test()
@@ -15,9 +24,25 @@ fun testStar(builder: Builder<*>) {
}
fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
builder.test()
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>builder.test()<!>
builder
.test()
.foo()
}
}
fun testStarJava(builder: JavaBuilder<*>) {
<!DEBUG_INFO_EXPRESSION_TYPE("Builder<*>")!>builder.test()<!>
builder
.test()
.foo()
}
fun <K : JavaBuilder<K>> testTypeParamJava(builder: JavaBuilder<K>) {
<!DEBUG_INFO_EXPRESSION_TYPE("K")!>builder.test()<!>
builder
.test()
.foo()
}
@@ -1,5 +1,14 @@
// !LANGUAGE: +TypeInferenceOnCallsWithSelfTypes
// FILE: JavaBuilder.java
public class JavaBuilder<B extends JavaBuilder<B>> {
<T extends B> T test() {
return null;
}
void foo() { }
}
// FILE: main.kt
class Builder<B : Builder<B>> {
fun <T : B> test(): T = TODO()
@@ -21,3 +30,19 @@ fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
.test()
.foo()
}
fun testStarJava(builder: JavaBuilder<*>) {
<!DEBUG_INFO_EXPRESSION_TYPE("(JavaBuilder<*>..JavaBuilder<*>?)")!>builder.test()<!>
builder
.test()
.foo()
}
fun <K : JavaBuilder<K>> testTypeParamJava(builder: JavaBuilder<K>) {
<!DEBUG_INFO_EXPRESSION_TYPE("(K..K?)")!>builder.test()<!>
builder
.test()
.foo()
}
@@ -1,7 +1,9 @@
package
public fun testStar(/*0*/ builder: Builder<*>): kotlin.Unit
public fun testStarJava(/*0*/ builder: JavaBuilder<*>): kotlin.Unit
public fun </*0*/ K : Builder<K>> testTypeParam(/*0*/ builder: Builder<K>): kotlin.Unit
public fun </*0*/ K : JavaBuilder<K>> testTypeParamJava(/*0*/ builder: JavaBuilder<K>): kotlin.Unit
public final class Builder</*0*/ B : Builder<B>> {
public constructor Builder</*0*/ B : Builder<B>>()
@@ -12,3 +14,12 @@ public final class Builder</*0*/ B : Builder<B>> {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class JavaBuilder</*0*/ B : JavaBuilder<B!>!> {
public constructor JavaBuilder</*0*/ B : JavaBuilder<B!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public/*package*/ open fun </*0*/ T : B!> test(): T!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -1,10 +1,23 @@
// !LANGUAGE: +TypeInferenceOnCallsWithSelfTypes
// FILE: JavaBodySpec.java
public interface JavaBodySpec<B, S extends JavaBodySpec<B, S>> {
default <T extends S> T isEqualTo(B expected) {
return null;
}
}
// FILE: main.kt
interface BodySpec<B, S : BodySpec<B, S>> {
fun <T : S> isEqualTo(expected: B): T
}
fun test(b: BodySpec<String, *>) {
val x = b.isEqualTo("")
x
}
<!DEBUG_INFO_EXPRESSION_TYPE("BodySpec<*, *>")!>x<!>
}
fun testJava(b: JavaBodySpec<String, *>) {
val x = b.isEqualTo("")
<!DEBUG_INFO_EXPRESSION_TYPE("BodySpec<*, *>")!>x<!>
}
@@ -1,5 +1,13 @@
// !LANGUAGE: +TypeInferenceOnCallsWithSelfTypes
// FILE: JavaBodySpec.java
public interface JavaBodySpec<B, S extends JavaBodySpec<B, S>> {
default <T extends S> T isEqualTo(B expected) {
return null;
}
}
// FILE: main.kt
interface BodySpec<B, S : BodySpec<B, S>> {
fun <T : S> isEqualTo(expected: B): T
}
@@ -8,3 +16,8 @@ fun test(b: BodySpec<String, *>) {
val x = b.isEqualTo("")
<!DEBUG_INFO_EXPRESSION_TYPE("BodySpec<*, *>")!>x<!>
}
fun testJava(b: JavaBodySpec<String, *>) {
val x = b.isEqualTo("")
<!DEBUG_INFO_EXPRESSION_TYPE("(JavaBodySpec<*, *>..JavaBodySpec<*, *>?)")!>x<!>
}
@@ -1,5 +1,23 @@
// !LANGUAGE: +TypeInferenceOnCallsWithSelfTypes
// FILE: JavaWriterAppender.java
public class JavaWriterAppender {
interface Builder2<K extends Builder2<K>> {}
class Builder1<B extends Builder1<B>> {
B asBuilder() { return null; }
}
<B extends Builder1<B>> B newBuilder() {
return null;
}
<B extends Builder1<B> & Builder2<B>> B intersectTwoSelfTypes() {
return null;
}
}
// FILE: main.kt
fun test() {
<!DEBUG_INFO_EXPRESSION_TYPE("WriterAppender.Builder1<*>")!>WriterAppender.newBuilder()<!>
<!DEBUG_INFO_EXPRESSION_TYPE("WriterAppender.Builder1<out WriterAppender.Builder1<*>>")!>WriterAppender.Builder1()<!>
@@ -7,6 +25,13 @@ fun test() {
<!DEBUG_INFO_EXPRESSION_TYPE("{Builder1<*> & Builder2<*>}")!>WriterAppender.intersectTwoSelfTypes()<!>
}
fun testJava(appender: JavaWriterAppender) {
<!DEBUG_INFO_EXPRESSION_TYPE("WriterAppender.Builder1<*>")!>appender.newBuilder()<!>
<!DEBUG_INFO_EXPRESSION_TYPE("WriterAppender.Builder1<out WriterAppender.Builder1<*>>")!>appender.Builder1()<!>
<!DEBUG_INFO_EXPRESSION_TYPE("{Builder1<*> & Builder2<*>}")!>appender.intersectTwoSelfTypes()<!>
}
object WriterAppender {
interface Builder2<K : Builder2<K>>
@@ -1,5 +1,23 @@
// !LANGUAGE: +TypeInferenceOnCallsWithSelfTypes
// FILE: JavaWriterAppender.java
public class JavaWriterAppender {
interface Builder2<K extends Builder2<K>> {}
class Builder1<B extends Builder1<B>> {
B asBuilder() { return null; }
}
<B extends Builder1<B>> B newBuilder() {
return null;
}
<B extends Builder1<B> & Builder2<B>> B intersectTwoSelfTypes() {
return null;
}
}
// FILE: main.kt
fun test() {
<!DEBUG_INFO_EXPRESSION_TYPE("WriterAppender.Builder1<*>")!>WriterAppender.newBuilder()<!>
<!DEBUG_INFO_EXPRESSION_TYPE("WriterAppender.Builder1<out WriterAppender.Builder1<*>>")!>WriterAppender.Builder1()<!>
@@ -7,6 +25,13 @@ fun test() {
<!DEBUG_INFO_EXPRESSION_TYPE("{Builder1<*> & Builder2<*>}")!>WriterAppender.intersectTwoSelfTypes()<!>
}
fun testJava(appender: JavaWriterAppender) {
<!DEBUG_INFO_EXPRESSION_TYPE("(JavaWriterAppender.Builder1<*>..JavaWriterAppender.Builder1<*>?)")!>appender.newBuilder()<!>
<!DEBUG_INFO_EXPRESSION_TYPE("JavaWriterAppender.Builder1<out (JavaWriterAppender.Builder1<*>..JavaWriterAppender.Builder1<*>?)>")!>appender.Builder1()<!>
<!DEBUG_INFO_EXPRESSION_TYPE("({Builder1<*> & Builder2<*>}..{Builder1<*>? & Builder2<*>?}?)")!>appender.intersectTwoSelfTypes()<!>
}
object WriterAppender {
interface Builder2<K : Builder2<K>>
@@ -1,6 +1,30 @@
package
public fun test(): kotlin.Unit
public fun testJava(/*0*/ appender: JavaWriterAppender): kotlin.Unit
public open class JavaWriterAppender {
public constructor JavaWriterAppender()
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 fun </*0*/ B : JavaWriterAppender.Builder1<B!>!> intersectTwoSelfTypes(): B! where B : JavaWriterAppender.Builder2<B!>!
public/*package*/ open fun </*0*/ B : JavaWriterAppender.Builder1<B!>!> newBuilder(): B!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public/*package*/ open inner class Builder1</*0*/ B : JavaWriterAppender.Builder1<B!>!> {
public/*package*/ constructor Builder1</*0*/ B : JavaWriterAppender.Builder1<B!>!>()
public/*package*/ open fun asBuilder(): B!
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/*package*/ interface Builder2</*0*/ K : JavaWriterAppender.Builder2<K!>!> {
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 object WriterAppender {
private constructor WriterAppender()
@@ -546,13 +546,15 @@ object AbstractTypeChecker {
targetType: KotlinTypeMarker
): TypeParameterMarker? {
for (i in 0 until baseType.argumentsCount()) {
val typeArgument = baseType.getArgument(i).takeIf { !it.isStarProjection() } ?: continue
val typeArgument = baseType.getArgument(i).takeIf { !it.isStarProjection() }?.getType() ?: continue
val areBothTypesCaptured =
typeArgument.lowerBoundIfFlexible().isCapturedType() && targetType.lowerBoundIfFlexible().isCapturedType()
if (typeArgument.getType() == targetType) {
if (typeArgument == targetType || (areBothTypesCaptured && typeArgument.typeConstructor() == targetType.typeConstructor())) {
return baseType.typeConstructor().getParameter(i)
}
getTypeParameterForArgumentInBaseIfItEqualToTarget(typeArgument.getType(), targetType)?.let { return it }
getTypeParameterForArgumentInBaseIfItEqualToTarget(typeArgument, targetType)?.let { return it }
}
return null