예제 #1
0
  @NotNull
  private KotlinTypeChecker createTypeChecker(
      @NotNull List<TypeParameterDescriptor> firstParameters,
      @NotNull List<TypeParameterDescriptor> secondParameters) {
    assert firstParameters.size() == secondParameters.size()
        : "Should be the same number of type parameters: "
            + firstParameters
            + " vs "
            + secondParameters;
    if (firstParameters.isEmpty()) return KotlinTypeChecker.withAxioms(equalityAxioms);

    final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors =
        new HashMap<TypeConstructor, TypeConstructor>();
    for (int i = 0; i < firstParameters.size(); i++) {
      matchingTypeConstructors.put(
          firstParameters.get(i).getTypeConstructor(),
          secondParameters.get(i).getTypeConstructor());
    }

    return KotlinTypeChecker.withAxioms(
        new KotlinTypeChecker.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);
            return (img1 != null && img1.equals(b)) || (img2 != null && img2.equals(a));
          }
        });
  }
예제 #2
0
  /**
   * Check if cast from supertype to subtype is erased. It is an error in "is" statement and warning
   * in "as".
   */
  public static boolean isCastErased(
      @NotNull KotlinType supertype,
      @NotNull KotlinType subtype,
      @NotNull KotlinTypeChecker typeChecker) {
    // cast between T and T? is always OK
    if (supertype.isMarkedNullable() || subtype.isMarkedNullable()) {
      return isCastErased(
          TypeUtils.makeNotNullable(supertype), TypeUtils.makeNotNullable(subtype), typeChecker);
    }

    // if it is a upcast, it's never erased
    if (typeChecker.isSubtypeOf(supertype, subtype)) return false;

    // downcasting to a non-reified type parameter is always erased
    if (TypeUtils.isNonReifiedTypeParemeter(subtype)) return true;

    // Check that we are actually casting to a generic type
    // NOTE: this does not account for 'as Array<List<T>>'
    if (allParametersReified(subtype)) return false;

    KotlinType staticallyKnownSubtype =
        findStaticallyKnownSubtype(supertype, subtype.getConstructor()).getResultingType();

    // If the substitution failed, it means that the result is an impossible type, e.g. something
    // like Out<in Foo>
    // In this case, we can't guarantee anything, so the cast is considered to be erased
    if (staticallyKnownSubtype == null) return true;

    // If the type we calculated is a subtype of the cast target, it's OK to use the cast target
    // instead.
    // If not, it's wrong to use it
    return !typeChecker.isSubtypeOf(staticallyKnownSubtype, subtype);
  }
예제 #3
0
 private static boolean isReturnTypeMoreSpecific(
     @NotNull CallableDescriptor a,
     @NotNull KotlinType aReturnType,
     @NotNull CallableDescriptor b,
     @NotNull KotlinType bReturnType) {
   KotlinTypeChecker typeChecker =
       DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters());
   return typeChecker.isSubtypeOf(aReturnType, bReturnType);
 }
예제 #4
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();
  }
예제 #5
0
 private static boolean areTypesEquivalent(
     @NotNull KotlinType typeInSuper,
     @NotNull KotlinType typeInSub,
     @NotNull KotlinTypeChecker typeChecker) {
   boolean bothErrors = typeInSuper.isError() && typeInSub.isError();
   return bothErrors || typeChecker.equalTypes(typeInSuper, typeInSub);
 }
예제 #6
0
 private static boolean lowerThanBound(
     KotlinTypeChecker typeChecker,
     KotlinType argument,
     TypeParameterDescriptor parameterDescriptor) {
   for (KotlinType bound : parameterDescriptor.getUpperBounds()) {
     if (typeChecker.isSubtypeOf(argument, bound)) {
       if (!argument.getConstructor().equals(bound.getConstructor())) {
         return true;
       }
     }
   }
   return false;
 }
예제 #7
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();
  }