Example #1
0
  /**
   * Remember that we are trying to cast something of type {@code supertype} to {@code subtype}.
   *
   * <p>Since at runtime we can only check the class (type constructor), the rest of the subtype
   * should be known statically, from supertype. This method reconstructs all static information
   * that can be obtained from supertype.
   *
   * <p>Example 1: supertype = Collection<String> subtype = List<...> result = List<String>, all
   * arguments are inferred
   *
   * <p>Example 2: supertype = Any subtype = List<...> result = List<*>, some arguments were not
   * inferred, replaced with '*'
   */
  public static TypeReconstructionResult findStaticallyKnownSubtype(
      @NotNull KotlinType supertype, @NotNull TypeConstructor subtypeConstructor) {
    assert !supertype.isMarkedNullable() : "This method only makes sense for non-nullable types";

    // Assume we are casting an expression of type Collection<Foo> to List<Bar>
    // First, let's make List<T>, where T is a type variable
    ClassifierDescriptor descriptor = subtypeConstructor.getDeclarationDescriptor();
    assert descriptor != null : "Can't create default type for " + subtypeConstructor;
    KotlinType subtypeWithVariables = descriptor.getDefaultType();

    // Now, let's find a supertype of List<T> that is a Collection of something,
    // in this case it will be Collection<T>
    KotlinType supertypeWithVariables =
        TypeCheckingProcedure.findCorrespondingSupertype(subtypeWithVariables, supertype);

    final List<TypeParameterDescriptor> variables =
        subtypeWithVariables.getConstructor().getParameters();

    Map<TypeConstructor, TypeProjection> substitution;
    if (supertypeWithVariables != null) {
      // Now, let's try to unify Collection<T> and Collection<Foo> solution is a map from T to Foo
      TypeUnifier.UnificationResult solution =
          TypeUnifier.unify(
              new TypeProjectionImpl(supertype),
              new TypeProjectionImpl(supertypeWithVariables),
              new Predicate<TypeConstructor>() {
                @Override
                public boolean apply(TypeConstructor typeConstructor) {
                  ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
                  return descriptor instanceof TypeParameterDescriptor
                      && variables.contains(descriptor);
                }
              });
      substitution = Maps.newHashMap(solution.getSubstitution());
    } else {
      // If there's no corresponding supertype, no variables are determined
      // This may be OK, e.g. in case 'Any as List<*>'
      substitution = Maps.newHashMapWithExpectedSize(variables.size());
    }

    // If some of the parameters are not determined by unification, it means that these parameters
    // are lost,
    // let's put stars instead, so that we can only cast to something like List<*>, e.g. (a: Any) as
    // List<*>
    boolean allArgumentsInferred = true;
    for (TypeParameterDescriptor variable : variables) {
      TypeProjection value = substitution.get(variable.getTypeConstructor());
      if (value == null) {
        substitution.put(variable.getTypeConstructor(), TypeUtils.makeStarProjection(variable));
        allArgumentsInferred = false;
      }
    }

    // At this point we have values for all type parameters of List
    // Let's make a type by substituting them: List<T> -> List<Foo>
    KotlinType substituted =
        TypeSubstitutor.create(substitution).substitute(subtypeWithVariables, Variance.INVARIANT);

    return new TypeReconstructionResult(substituted, allArgumentsInferred);
  }
Example #2
0
 @Nullable
 public static KotlinType createSubstitutedSupertype(
     @NotNull KotlinType subType,
     @NotNull KotlinType superType,
     @NotNull TypeSubstitutor substitutor) {
   KotlinType substitutedType = substitutor.substitute(superType, Variance.INVARIANT);
   if (substitutedType != null) {
     return makeNullableIfNeeded(substitutedType, subType.isMarkedNullable());
   }
   return null;
 }
Example #3
0
 @NotNull
 public static List<KotlinType> getImmediateSupertypes(@NotNull KotlinType type) {
   TypeSubstitutor substitutor = TypeSubstitutor.create(type);
   Collection<KotlinType> originalSupertypes = type.getConstructor().getSupertypes();
   List<KotlinType> result = new ArrayList<KotlinType>(originalSupertypes.size());
   for (KotlinType supertype : originalSupertypes) {
     KotlinType substitutedType = createSubstitutedSupertype(type, supertype, substitutor);
     if (substitutedType != null) {
       result.add(substitutedType);
     }
   }
   return result;
 }
Example #4
0
 @NotNull
 public static TypeSubstitutor createSubstitutorForTypeParameters(
     @NotNull
         Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameters) {
   Map<TypeConstructor, TypeProjection> typeSubstitutionContext =
       new HashMap<TypeConstructor, TypeProjection>();
   for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl>
       originalToAltTypeParameter : originalToAltTypeParameters.entrySet()) {
     typeSubstitutionContext.put(
         originalToAltTypeParameter.getKey().getTypeConstructor(),
         new TypeProjectionImpl(originalToAltTypeParameter.getValue().getDefaultType()));
   }
   // TODO: Use IndexedParametersSubstitution here instead of map creation
   return TypeSubstitutor.create(typeSubstitutionContext);
 }
Example #5
0
  @NotNull
  public static KotlinType substituteProjectionsForParameters(
      @NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
    List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
    if (clazzTypeParameters.size() != projections.size()) {
      throw new IllegalArgumentException(
          "type parameter counts do not match: " + clazz + ", " + projections);
    }

    Map<TypeConstructor, TypeProjection> substitutions =
        org.jetbrains.kotlin.utils.CollectionsKt.newHashMapWithExpectedSize(
            clazzTypeParameters.size());

    for (int i = 0; i < clazzTypeParameters.size(); ++i) {
      TypeConstructor typeConstructor = clazzTypeParameters.get(i).getTypeConstructor();
      substitutions.put(typeConstructor, projections.get(i));
    }

    return TypeSubstitutor.create(substitutions)
        .substitute(clazz.getDefaultType(), Variance.INVARIANT);
  }