Fix type parameter bound check in expect-actual checker

Also make TypeParameterUpperBounds a "strong" incompatibility, meaning
that non-actual members from platform module are _not_ going to be
matched to the expected members if this incompatibility exists between
them, and therefore NO_ACTUAL_FOR_EXPECT will be reported on the
expected declaration, instead of ACTUAL_MISSING on the platform member.
This is needed because the difference in type parameter upper bounds can
have effect on the function signature on the platform (e.g. on JVM,
Array<T> -> T[], but Array<T> -> Comparable[] if T : Comparable<T>), and
it would be incorrect to report ACTUAL_MISSING on the member that has
nothing to do with the expected declaration that happens to coincide
with it in everything except type parameter bounds

 #KT-21864 Fixed
This commit is contained in:
Alexander Udalov
2018-01-08 15:35:59 +01:00
parent 8c6b140865
commit f198a28276
11 changed files with 224 additions and 3 deletions
@@ -0,0 +1,12 @@
// !LANGUAGE: +MultiPlatformProjects
// MODULE: m1-common
// FILE: common.kt
expect fun <T : Comparable<T>> Array<out T>.sort(): Unit
// MODULE: m2-jvm(m1-common)
// FILE: jvm.kt
actual fun <T : Comparable<T>> Array<out T>.sort(): Unit {}
fun <T> Array<out T>.sort(): Unit {}
@@ -0,0 +1,11 @@
// -- Module: <m1-common> --
package
public expect fun </*0*/ T : kotlin.Comparable<T>> kotlin.Array<out T>.sort(): kotlin.Unit
// -- Module: <m2-jvm> --
package
public fun </*0*/ T> kotlin.Array<out T>.sort(): kotlin.Unit
public actual fun </*0*/ T : kotlin.Comparable<T>> kotlin.Array<out T>.sort(): kotlin.Unit
@@ -0,0 +1,25 @@
// !LANGUAGE: +MultiPlatformProjects
// MODULE: m1-common
// FILE: common.kt
expect class A {
fun <T : Any> foo(): Unit
fun <S : Comparable<S>> bar(): List<S>
}
// MODULE: m2-jvm(m1-common)
// FILE: jvm.kt
actual typealias A = JavaA
// FILE: JavaA.java
import java.util.List;
public class JavaA {
public <T> void foo() {}
public <S extends Comparable<S>> List<S> bar() {
return null;
}
}
@@ -0,0 +1,24 @@
// -- Module: <m1-common> --
package
public final expect class A {
public final expect fun </*0*/ S : kotlin.Comparable<S>> bar(): kotlin.collections.List<S>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final expect fun </*0*/ T : kotlin.Any> foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
// -- Module: <m2-jvm> --
package
public open class JavaA {
public constructor JavaA()
public open fun </*0*/ S : kotlin.Comparable<S!>!> bar(): kotlin.collections.(Mutable)List<S!>!
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun </*0*/ T : kotlin.Any!> foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public actual typealias A = JavaA
@@ -0,0 +1,13 @@
// !LANGUAGE: +MultiPlatformProjects
// MODULE: m1-common
// FILE: common.kt
interface A
interface B
expect fun <!JVM:NO_ACTUAL_FOR_EXPECT!><T><!> List<T>.foo() where T : A, T : B
// MODULE: m2-jvm(m1-common)
// FILE: jvm.kt
fun <T> List<T>.foo() where T : B, T : A {}
@@ -0,0 +1,34 @@
// -- Module: <m1-common> --
package
public expect fun </*0*/ T : A> kotlin.collections.List<T>.foo(): kotlin.Unit where T : B
public interface A {
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 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
}
// -- Module: <m2-jvm> --
package
public fun </*0*/ T : B> kotlin.collections.List<T>.foo(): kotlin.Unit where T : A
public interface A {
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 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
}