Example #1
0
  @Nullable
  public static OverrideCompatibilityInfo getBasicOverridabilityProblem(
      @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
    if (superDescriptor instanceof FunctionDescriptor
            && !(subDescriptor instanceof FunctionDescriptor)
        || superDescriptor instanceof PropertyDescriptor
            && !(subDescriptor instanceof PropertyDescriptor)) {
      return OverrideCompatibilityInfo.incompatible("Member kind mismatch");
    }

    if (!(superDescriptor instanceof FunctionDescriptor)
        && !(superDescriptor instanceof PropertyDescriptor)) {
      throw new IllegalArgumentException(
          "This type of CallableDescriptor cannot be checked for overridability: "
              + superDescriptor);
    }

    // TODO: check outside of this method
    if (!superDescriptor.getName().equals(subDescriptor.getName())) {
      return OverrideCompatibilityInfo.incompatible("Name mismatch");
    }

    OverrideCompatibilityInfo receiverAndParameterResult =
        checkReceiverAndParameterCount(superDescriptor, subDescriptor);
    if (receiverAndParameterResult != null) {
      return receiverAndParameterResult;
    }

    return null;
  }
Example #2
0
  @Nullable
  static OverrideCompatibilityInfo checkReceiverAndParameterCount(
      CallableDescriptor superDescriptor, CallableDescriptor subDescriptor) {
    if ((superDescriptor.getExtensionReceiverParameter() == null)
        != (subDescriptor.getExtensionReceiverParameter() == null)) {
      return OverrideCompatibilityInfo.incompatible("Receiver presence mismatch");
    }

    if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
      return OverrideCompatibilityInfo.incompatible("Value parameter number mismatch");
    }

    return null;
  }
Example #3
0
  @Nullable
  static OverrideCompatibilityInfo checkReceiverAndParameterCount(
      CallableDescriptor superDescriptor, CallableDescriptor subDescriptor) {
    if ((superDescriptor.getExtensionReceiverParameter() == null)
        != (subDescriptor.getExtensionReceiverParameter() == null)) {
      return OverrideCompatibilityInfo.receiverPresenceMismatch();
    }

    if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
      return OverrideCompatibilityInfo.valueParameterNumberMismatch();
    }

    return null;
  }
Example #4
0
  @NotNull
  private OverrideCompatibilityInfo isOverridableBy(
      @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);
  }
Example #5
0
  @NotNull
  public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions(
      @NotNull CallableDescriptor superDescriptor,
      @NotNull CallableDescriptor subDescriptor,
      boolean checkReturnType) {
    OverrideCompatibilityInfo basicOverridability =
        getBasicOverridabilityProblem(superDescriptor, subDescriptor);
    if (basicOverridability != null) return basicOverridability;

    List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor);
    List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor);

    List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
    List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();

    if (superTypeParameters.size() != subTypeParameters.size()) {
      for (int i = 0; i < superValueParameters.size(); ++i) {
        // TODO: compare erasure
        if (!KotlinTypeChecker.DEFAULT.equalTypes(
            superValueParameters.get(i), subValueParameters.get(i))) {
          return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch");
        }
      }
      return OverrideCompatibilityInfo.conflict("Type parameter number mismatch");
    }

    KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters);

    for (int i = 0; i < superTypeParameters.size(); i++) {
      if (!areTypeParametersEquivalent(
          superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch");
      }
    }

    for (int i = 0; i < superValueParameters.size(); i++) {
      if (!areTypesEquivalent(
          superValueParameters.get(i), subValueParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch");
      }
    }

    if (checkReturnType) {
      KotlinType superReturnType = superDescriptor.getReturnType();
      KotlinType subReturnType = subDescriptor.getReturnType();

      if (superReturnType != null && subReturnType != null) {
        boolean bothErrors = subReturnType.isError() && superReturnType.isError();
        if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) {
          return OverrideCompatibilityInfo.conflict("Return type mismatch");
        }
      }
    }

    return OverrideCompatibilityInfo.success();
  }
Example #6
0
  @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)) {
      return OverrideCompatibilityInfo.incompatible("Member kind mismatch");
    }

    if (!(superDescriptor instanceof FunctionDescriptor)
        && !(superDescriptor instanceof PropertyDescriptor)) {
      throw new IllegalArgumentException(
          "This type of CallableDescriptor cannot be checked for overridability: "
              + superDescriptor);
    }

    // TODO: check outside of this method
    if (!superDescriptor.getName().equals(subDescriptor.getName())) {
      return OverrideCompatibilityInfo.incompatible("Name mismatch");
    }

    OverrideCompatibilityInfo receiverAndParameterResult =
        checkReceiverAndParameterCount(superDescriptor, subDescriptor);
    if (receiverAndParameterResult != null) {
      return receiverAndParameterResult;
    }

    List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor);
    List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor);

    List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
    List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();

    if (superTypeParameters.size() != subTypeParameters.size()) {
      for (int i = 0; i < superValueParameters.size(); ++i) {
        // TODO: compare erasure
        if (!KotlinTypeChecker.DEFAULT.equalTypes(
            superValueParameters.get(i), subValueParameters.get(i))) {
          return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch");
        }
      }
      return OverrideCompatibilityInfo.conflict("Type parameter number mismatch");
    }

    KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters);

    for (int i = 0; i < superTypeParameters.size(); i++) {
      if (!areTypeParametersEquivalent(
          superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch");
      }
    }

    for (int i = 0; i < superValueParameters.size(); i++) {
      if (!areTypesEquivalent(
          superValueParameters.get(i), subValueParameters.get(i), typeChecker)) {
        return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch");
      }
    }

    if (checkReturnType) {
      KotlinType superReturnType = superDescriptor.getReturnType();
      KotlinType subReturnType = subDescriptor.getReturnType();

      if (superReturnType != null && subReturnType != null) {
        boolean bothErrors = subReturnType.isError() && superReturnType.isError();
        if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) {
          return OverrideCompatibilityInfo.conflict("Return type mismatch");
        }
      }
    }

    return OverrideCompatibilityInfo.success();
  }
Example #7
0
  @NotNull
  private OverrideCompatibilityInfo isOverridableBy(
      @NotNull CallableDescriptor superDescriptor,
      @NotNull CallableDescriptor subDescriptor,
      boolean checkReturnType) {
    if (superDescriptor instanceof FunctionDescriptor) {
      if (!(subDescriptor instanceof FunctionDescriptor))
        return OverrideCompatibilityInfo.memberKindMismatch();
    } else if (superDescriptor instanceof PropertyDescriptor) {
      if (!(subDescriptor instanceof PropertyDescriptor))
        return OverrideCompatibilityInfo.memberKindMismatch();
    } else {
      throw new IllegalArgumentException(
          "This type of CallableDescriptor cannot be checked for overridability: "
              + superDescriptor);
    }

    // TODO: check outside of this method
    if (!superDescriptor.getName().equals(subDescriptor.getName())) {
      return OverrideCompatibilityInfo.nameMismatch();
    }

    OverrideCompatibilityInfo receiverAndParameterResult =
        checkReceiverAndParameterCount(superDescriptor, subDescriptor);
    if (receiverAndParameterResult != null) {
      return receiverAndParameterResult;
    }

    List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
    List<JetType> subValueParameters = compiledValueParameters(subDescriptor);

    List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
    List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();

    if (superTypeParameters.size() != subTypeParameters.size()) {
      for (int i = 0; i < superValueParameters.size(); ++i) {
        JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
        JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
        // TODO: compare erasure
        if (!JetTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType)) {
          return OverrideCompatibilityInfo.typeParameterNumberMismatch();
        }
      }
      return OverrideCompatibilityInfo.valueParameterTypeMismatch(
          null, null, OverrideCompatibilityInfo.Result.CONFLICT);
    }

    final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors =
        new HashMap<TypeConstructor, TypeConstructor>();
    for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
      TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
      TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
      matchingTypeConstructors.put(
          superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
    }

    JetTypeChecker.TypeConstructorEquality localEqualityAxioms =
        new JetTypeChecker.TypeConstructorEquality() {
          @Override
          public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
            if (equalityAxioms.equals(a, b)) return true;
            TypeConstructor img1 = matchingTypeConstructors.get(a);
            TypeConstructor img2 = matchingTypeConstructors.get(b);
            if (!(img1 != null && img1.equals(b)) && !(img2 != null && img2.equals(a))) {
              return false;
            }
            return true;
          }
        };

    for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
      TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
      TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);

      if (!areTypesEquivalent(
          superTypeParameter.getUpperBoundsAsType(),
          subTypeParameter.getUpperBoundsAsType(),
          localEqualityAxioms)) {
        return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
      }
    }

    for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size();
        i < unsubstitutedValueParametersSize;
        i++) {
      JetType superValueParameter = superValueParameters.get(i);
      JetType subValueParameter = subValueParameters.get(i);

      if (!areTypesEquivalent(superValueParameter, subValueParameter, localEqualityAxioms)) {
        return OverrideCompatibilityInfo.valueParameterTypeMismatch(
            superValueParameter, subValueParameter, INCOMPATIBLE);
      }
    }

    if (checkReturnType) {
      JetType superReturnType = superDescriptor.getReturnType();
      JetType subReturnType = subDescriptor.getReturnType();

      if (superReturnType != null && subReturnType != null) {
        boolean bothErrors = subReturnType.isError() && superReturnType.isError();
        if (!bothErrors
            && !JetTypeChecker.withAxioms(localEqualityAxioms)
                .isSubtypeOf(subReturnType, superReturnType)) {
          return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType);
        }
      }
    }

    for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
      if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) {
        return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass());
      }
    }

    return OverrideCompatibilityInfo.success();
  }
Example #8
0
  @NotNull
  public OverrideCompatibilityInfo isOverridableBy(
      @NotNull CallableDescriptor superDescriptor,
      @NotNull CallableDescriptor subDescriptor,
      @Nullable ClassDescriptor subClassDescriptor,
      boolean checkReturnType) {
    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:
          wasSuccess = true;
          break;
        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
      }
    }

    if (!wasSuccess) {
      return basicResult;
    }

    // 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();
  }