Exemple #1
0
  /**
   * Return the greatest lower bound of two types. That is, return the largest type that is a
   * subtype of both inputs. If none exists return {@code thisType}.
   */
  public JReferenceType strengthenType(JReferenceType thisType, JReferenceType thatType) {
    if (thisType == thatType) {
      return thisType;
    }

    if (thisType.isNullType() || thatType.isNullType()) {
      return JReferenceType.NULL_TYPE;
    }

    if (thisType.canBeNull() != thatType.canBeNull()) {
      // If either is non-nullable, the result should be non-nullable.
      return strengthenType(thisType.strengthenToNonNull(), thatType.strengthenToNonNull());
    }

    if (typeOracle.castSucceedsTrivially(thisType, thatType)) {
      return thisType;
    }

    if (typeOracle.castSucceedsTrivially(thatType, thisType)) {
      return thatType;
    }

    // This types are incompatible; ideally this code should not be reached, but there are two
    // situations where this happens:
    //   1 - unrelated interfaces;
    //   2 - unsafe code.
    // The original type is preserved in this case.
    return thisType;
  }
Exemple #2
0
  /**
   * Return the least upper bound of two types. That is, the "smallest" type that is a supertype of
   * both types. In this lattice there the smallest element might no exist, there might be multiple
   * minimal elements neither of which is smaller than the others. E.g.
   *
   * <p>{@code I J | \ /| | \ / | | x | | / \ | | / \ | A B }
   *
   * <p>where I and J are interfaces, A and B are classes and both A and B implement I and J. In
   * this case both I and J are generalizing the types A and B.
   */
  private JReferenceType generalizeTypes(JReferenceType thisType, JReferenceType thatType) {

    if (!thisType.canBeNull() && !thatType.canBeNull()) {
      // Nullability is an orthogonal property, so remove non_nullability and perform the
      // generalization on the nullable types, and if both were NOT nullable then strengthen the
      // result to NOT nullable.
      //
      // not_nullable(A) v not_nullable(B) = not_nullable(A v B)
      JReferenceType nulllableGeneralizer =
          generalizeTypes(thisType.weakenToNullable(), thatType.weakenToNullable());
      return nulllableGeneralizer.strengthenToNonNull();
    }
    thisType = thisType.weakenToNullable();
    thatType = thatType.weakenToNullable();

    // From here on nullability does not need to be considered.

    // Generalization for exact types is as follows.
    // exact(A) v null = exact(A)
    // A v null = A
    if (thatType.isNullType()) {
      return thisType;
    }

    // null v exact(A) = exact(A)
    // null v A = A
    if (thisType.isNullType()) {
      return thatType;
    }

    // exact(A) v exact(A)  = exact(A)
    // A v A  = A
    if (thisType == thatType) {
      return thisType;
    }

    // exact(A) v exact(B) = A v B
    // A v exact(B) = A v B
    // exact(A) v B = A v B
    // A v B = A v B
    return generalizeUnderlyingTypes(thisType.getUnderlyingType(), thatType.getUnderlyingType());
  }