diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt index 22ed91754e3..68b47f4e980 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt @@ -119,9 +119,18 @@ class HeaderImplDeclarationChecker(val moduleToCheck: ModuleDescriptor? = null) else -> return // do not report anything for incorrect code, e.g. 'impl' local function } candidates.any { declaration -> + // TODO: optimize by caching this per impl-header class pair, do not create a new substitutor for each impl member + val substitutor = + if (container is ClassDescriptor) { + val headerClass = declaration.containingDeclaration as ClassDescriptor + // TODO: this might not work for members of inner generic classes + Substitutor(headerClass.declaredTypeParameters, container.declaredTypeParameters) + } + else null + descriptor != declaration && declaration.isHeader && - areCompatibleCallables(declaration, descriptor, checkImpl = false) == Compatible + areCompatibleCallables(declaration, descriptor, checkImpl = false, parentSubstitutor = substitutor) == Compatible } } is ClassifierDescriptorWithTypeParameters -> descriptor.findDeclarationForClass() != null @@ -342,12 +351,11 @@ class HeaderImplDeclarationChecker(val moduleToCheck: ModuleDescriptor? = null) val bTypeParams = b.declaredTypeParameters if (aTypeParams.size != bTypeParams.size) return Incompatible.TypeParameterCount - val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor) - if (a.modality != b.modality && !(a.modality == Modality.FINAL && b.modality == Modality.OPEN)) return Incompatible.Modality if (a.visibility != b.visibility) return Incompatible.Visibility + val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor) areCompatibleTypeParameters(aTypeParams, bTypeParams, substitutor).let { if (it != Compatible) return it } // Subtract kotlin.Any from supertypes because it's implicitly added if no explicit supertype is specified, diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.kt b/compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.kt new file mode 100644 index 00000000000..13542922806 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.kt @@ -0,0 +1,18 @@ +// !LANGUAGE: +MultiPlatformProjects +// MODULE: m1-common +// FILE: common.kt + +header interface A { + val x: T + var y: List + fun f(p: Collection): Map> +} + +// MODULE: m2-jvm(m1-common) +// FILE: jvm.kt + +impl interface A { + impl val x: T + impl var y: List + impl fun f(p: Collection): Map> +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.txt b/compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.txt new file mode 100644 index 00000000000..dae790fbc1b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.txt @@ -0,0 +1,24 @@ +// -- Module: -- +package + +public header interface A { + public header abstract val x: T + public header abstract var y: kotlin.collections.List + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract header fun f(/*0*/ p: kotlin.collections.Collection): kotlin.collections.Map> + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + + +// -- Module: -- +package + +public impl interface A { + public impl abstract val x: T + public impl abstract var y: kotlin.collections.List + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract impl fun f(/*0*/ p: kotlin.collections.Collection): kotlin.collections.Map> + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 21bcb6cdd58..61cd16f6342 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13153,6 +13153,21 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/generic") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Generic extends AbstractDiagnosticsTest { + public void testAllFilesPresentInGeneric() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/generic"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("membersInGenericClass.kt") + public void testMembersInGenericClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/generic/membersInGenericClass.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/headerClass") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)