Optimize external overridability conditions

- Skip ones that can lead only to success after first success
- And vice versa
This commit is contained in:
Denis Zharkov
2016-02-12 15:42:36 +03:00
parent 1b4b8ab5db
commit 9f22b17918
6 changed files with 52 additions and 10 deletions
@@ -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<ValueParameterDescriptor> parameters1 = fun1.getValueParameters();
List<ValueParameterDescriptor> parameters2 = fun2.getValueParameters();
@@ -64,4 +64,6 @@ class BuiltinOverridabilityCondition : ExternalOverridabilityCondition {
// incompatible override
return Result.INCOMPATIBLE
}
override fun getContract() = ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY
}
@@ -43,4 +43,6 @@ class ErasedOverridabilityCondition : ExternalOverridabilityCondition {
else -> Result.UNKNOWN
}
}
override fun getContract() = ExternalOverridabilityCondition.Contract.SUCCESS_ONLY
}
@@ -33,4 +33,6 @@ class FieldOverridabilityCondition : ExternalOverridabilityCondition {
return Result.UNKNOWN
}
override fun getContract() = ExternalOverridabilityCondition.Contract.BOTH
}
@@ -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();
}
@@ -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