From 9f22b17918996a15f58ef2a50d15dac74c13852e Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 12 Feb 2016 15:42:36 +0300 Subject: [PATCH] Optimize external overridability conditions - Skip ones that can lead only to success after first success - And vice versa --- .../SamAdapterOverridabilityCondition.java | 11 +++--- .../java/BuiltinOverridabilityCondition.kt | 2 + .../java/ErasedOverridabilityCondition.kt | 2 + .../load/java/FieldOverridabilityCondition.kt | 2 + .../ExternalOverridabilityCondition.java | 7 ++++ .../kotlin/resolve/OverridingUtil.java | 38 ++++++++++++++++--- 6 files changed, 52 insertions(+), 10 deletions(-) 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 d4a70cf2953..8d8cd981757 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 @@ -46,15 +46,16 @@ public class SamAdapterOverridabilityCondition implements ExternalOverridability return subOriginal == null ? Result.UNKNOWN : Result.INCOMPATIBLE; // DECLARATION can override anything } - OverridingUtil.OverrideCompatibilityInfo basicResult = OverridingUtil.DEFAULT - .isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, /* checkReturnType = */ false); - - if (basicResult.getResult() != OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) return Result.UNKNOWN; - // inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure return equalErasure(superOriginal, subOriginal) ? Result.UNKNOWN : Result.INCOMPATIBLE; } + @NotNull + @Override + public Contract getContract() { + return Contract.CONFLICTS_ONLY; + } + private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) { List parameters1 = fun1.getValueParameters(); List parameters2 = fun2.getValueParameters(); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/BuiltinOverridabilityCondition.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/BuiltinOverridabilityCondition.kt index cfd2e7c87e2..0baf63507e0 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/BuiltinOverridabilityCondition.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/BuiltinOverridabilityCondition.kt @@ -64,4 +64,6 @@ class BuiltinOverridabilityCondition : ExternalOverridabilityCondition { // incompatible override return Result.INCOMPATIBLE } + + override fun getContract() = ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/ErasedOverridabilityCondition.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/ErasedOverridabilityCondition.kt index 5970aeeb0b3..a3678ef962b 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/ErasedOverridabilityCondition.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/ErasedOverridabilityCondition.kt @@ -43,4 +43,6 @@ class ErasedOverridabilityCondition : ExternalOverridabilityCondition { else -> Result.UNKNOWN } } + + override fun getContract() = ExternalOverridabilityCondition.Contract.SUCCESS_ONLY } 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 73bca44c541..0bfdc84bf50 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 @@ -33,4 +33,6 @@ class FieldOverridabilityCondition : ExternalOverridabilityCondition { return Result.UNKNOWN } + + override fun getContract() = ExternalOverridabilityCondition.Contract.BOTH } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java index 34578b7c66c..83a52b24d7d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/ExternalOverridabilityCondition.java @@ -26,10 +26,17 @@ public interface ExternalOverridabilityCondition { OVERRIDABLE, CONFLICT, INCOMPATIBLE, UNKNOWN } + enum Contract { + CONFLICTS_ONLY, SUCCESS_ONLY, BOTH + } + @NotNull Result isOverridable( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, @Nullable ClassDescriptor subClassDescriptor ); + + @NotNull + Contract getContract(); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index 1e39e7149f4..364eb4c36fd 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -84,13 +84,20 @@ public class OverridingUtil { @Nullable ClassDescriptor subClassDescriptor, boolean checkReturnType ) { - boolean wasSuccessfulExternalCondition = false; + OverrideCompatibilityInfo basicResult = isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, checkReturnType); + boolean wasSuccess = basicResult.getResult() == OVERRIDABLE; + for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { + // Do not run CONFLICTS_ONLY while there was no success + if (externalCondition.getContract() == ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue; + if (wasSuccess && externalCondition.getContract() == ExternalOverridabilityCondition.Contract.SUCCESS_ONLY) continue; + ExternalOverridabilityCondition.Result result = externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor); + switch (result) { case OVERRIDABLE: - wasSuccessfulExternalCondition = true; + wasSuccess = true; break; case CONFLICT: return OverrideCompatibilityInfo.conflict("External condition failed"); @@ -102,11 +109,32 @@ public class OverridingUtil { } } - if (wasSuccessfulExternalCondition) { - return OverrideCompatibilityInfo.success(); + if (!wasSuccess) { + return basicResult; } - return isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, checkReturnType); + // Search for conflicts from external conditions + for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { + // Run all conditions that was not run before (i.e. CONFLICTS_ONLY) + if (externalCondition.getContract() != ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue; + + ExternalOverridabilityCondition.Result result = + externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor); + switch (result) { + case CONFLICT: + return OverrideCompatibilityInfo.conflict("External condition failed"); + case INCOMPATIBLE: + return OverrideCompatibilityInfo.incompatible("External condition"); + case OVERRIDABLE: + throw new IllegalStateException( + "Contract violation in " + externalCondition.getClass().getName() + " condition. It's not supposed to end with success"); + case UNKNOWN: + // do nothing + // go to the next external condition or default override check + } + } + + return OverrideCompatibilityInfo.success(); } @NotNull