diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java index b9f3c434c06..b9d46ce85b9 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/sam/SamAdapterOverridabilityCondition.java @@ -28,20 +28,21 @@ import org.jetbrains.kotlin.types.TypeUtils; import java.util.List; public class SamAdapterOverridabilityCondition implements ExternalOverridabilityCondition { + @NotNull @Override - public boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { - if (!(subDescriptor instanceof SimpleFunctionDescriptor)) { - return true; + public Result isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { + if (!(subDescriptor instanceof SimpleFunctionDescriptor) || !(superDescriptor instanceof SimpleFunctionDescriptor)) { + return Result.UNKNOWN; } SimpleFunctionDescriptor superOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) superDescriptor); SimpleFunctionDescriptor subOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) subDescriptor); if (superOriginal == null || subOriginal == null) { // super or sub is/overrides DECLARATION - return subOriginal == null; // DECLARATION can override anything + return subOriginal == null ? Result.UNKNOWN : Result.INCOMPATIBLE; // DECLARATION can override anything } // inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure - return equalErasure(superOriginal, subOriginal); + return equalErasure(superOriginal, subOriginal) ? Result.UNKNOWN : Result.INCOMPATIBLE; } private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) { diff --git a/compiler/testData/diagnostics/tests/j+k/fieldOverridesFieldOfDifferentType.kt b/compiler/testData/diagnostics/tests/j+k/fieldOverridesFieldOfDifferentType.kt new file mode 100644 index 00000000000..c1f5ea4c4d5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/fieldOverridesFieldOfDifferentType.kt @@ -0,0 +1,19 @@ +// !CHECK_TYPE + +// FILE: A.java + +public class A { + public int size = 1; +} + +// FILE: B.java + +public class B extends A { + public String size = 1; +} + +// FILE: main.kt + +fun foo() { + B().size.checkType { _() } +} diff --git a/compiler/testData/diagnostics/tests/j+k/fieldOverridesFieldOfDifferentType.txt b/compiler/testData/diagnostics/tests/j+k/fieldOverridesFieldOfDifferentType.txt new file mode 100644 index 00000000000..25d627490b7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/fieldOverridesFieldOfDifferentType.txt @@ -0,0 +1,19 @@ +package + +public fun foo(): kotlin.Unit + +public open class A { + public constructor A() + public final var size: kotlin.Int + 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 B : A { + public constructor B() + public final override /*1*/ var size: kotlin.String + 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index e15618aae9a..116bf524c35 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9282,6 +9282,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("fieldOverridesFieldOfDifferentType.kt") + public void testFieldOverridesFieldOfDifferentType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/fieldOverridesFieldOfDifferentType.kt"); + doTest(fileName); + } + @TestMetadata("fieldOverridesNothing.kt") public void testFieldOverridesNothing() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/fieldOverridesNothing.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FieldOverridabilityCondition.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FieldOverridabilityCondition.kt index fabe36efff7..85d27ab541d 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FieldOverridabilityCondition.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/FieldOverridabilityCondition.kt @@ -20,11 +20,16 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition +import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition.Result class FieldOverridabilityCondition : ExternalOverridabilityCondition { - override fun isOverridable(superDescriptor: CallableDescriptor, subDescriptor: CallableDescriptor): Boolean { - if (subDescriptor !is PropertyDescriptor || superDescriptor !is PropertyDescriptor) return true + override fun isOverridable(superDescriptor: CallableDescriptor, subDescriptor: CallableDescriptor): Result { + if (subDescriptor !is PropertyDescriptor || superDescriptor !is PropertyDescriptor) return Result.UNKNOWN + if (subDescriptor.name != superDescriptor.name) return Result.UNKNOWN - return subDescriptor.isJavaField == superDescriptor.isJavaField + if (subDescriptor.isJavaField && superDescriptor.isJavaField) return Result.OVERRIDABLE + if (subDescriptor.isJavaField || superDescriptor.isJavaField) return Result.INCOMPATIBLE + + return Result.UNKNOWN } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java index c4bc588ee86..d77243272b5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java @@ -20,5 +20,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.CallableDescriptor; public interface ExternalOverridabilityCondition { - boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor); + enum Result { + OVERRIDABLE, CONFLICT, INCOMPATIBLE, UNKNOWN + } + + @NotNull + Result isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index e7d90b84bf8..85c3338ddd9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import java.util.*; import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*; +import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE; public class OverridingUtil { @@ -76,6 +77,30 @@ public class OverridingUtil { @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean checkReturnType + ) { + for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { + ExternalOverridabilityCondition.Result result = externalCondition.isOverridable(superDescriptor, subDescriptor); + switch (result) { + case OVERRIDABLE: + return OverrideCompatibilityInfo.success(); + case CONFLICT: + return OverrideCompatibilityInfo.conflict("External condition failed"); + case INCOMPATIBLE: + return OverrideCompatibilityInfo.incompatible("External condition"); + case UNKNOWN: + // do nothing + // go to the next external condition or default override check + } + } + + return isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, checkReturnType); + } + + @NotNull + public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions( + @NotNull CallableDescriptor superDescriptor, + @NotNull CallableDescriptor subDescriptor, + boolean checkReturnType ) { if (superDescriptor instanceof FunctionDescriptor && !(subDescriptor instanceof FunctionDescriptor) || superDescriptor instanceof PropertyDescriptor && !(subDescriptor instanceof PropertyDescriptor)) { @@ -138,12 +163,6 @@ public class OverridingUtil { } } - for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { - if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) { - return OverrideCompatibilityInfo.incompatible("External condition failed"); - } - } - return OverrideCompatibilityInfo.success(); }