private List<TypeProjection> substituteTypeArguments(
      List<TypeParameterDescriptor> typeParameters,
      List<TypeProjection> typeArguments,
      int recursionDepth)
      throws SubstitutionException {
    List<TypeProjection> substitutedArguments =
        new ArrayList<TypeProjection>(typeParameters.size());
    for (int i = 0; i < typeParameters.size(); i++) {
      TypeParameterDescriptor typeParameter = typeParameters.get(i);
      TypeProjection typeArgument = typeArguments.get(i);

      TypeProjection substitutedTypeArgument = unsafeSubstitute(typeArgument, recursionDepth + 1);

      switch (conflictType(
          typeParameter.getVariance(), substitutedTypeArgument.getProjectionKind())) {
        case NO_CONFLICT:
          // if the corresponding type parameter is already co/contra-variant, there's not need for
          // an explicit projection
          if (typeParameter.getVariance() != Variance.INVARIANT
              && !substitutedTypeArgument.isStarProjection()) {
            substitutedTypeArgument =
                new TypeProjectionImpl(Variance.INVARIANT, substitutedTypeArgument.getType());
          }
          break;
        case OUT_IN_IN_POSITION:
        case IN_IN_OUT_POSITION:
          substitutedTypeArgument = TypeUtils.makeStarProjection(typeParameter);
          break;
      }

      substitutedArguments.add(substitutedTypeArgument);
    }
    return substitutedArguments;
  }
Beispiel #2
0
 @NotNull
 public static List<ValueParameterDescriptor> getValueParameters(
     @NotNull FunctionDescriptor functionDescriptor, @NotNull KotlinType type) {
   assert isFunctionOrExtensionFunctionType(type);
   List<TypeProjection> parameterTypes = getParameterTypeProjectionsFromFunctionType(type);
   List<ValueParameterDescriptor> valueParameters =
       new ArrayList<ValueParameterDescriptor>(parameterTypes.size());
   for (int i = 0; i < parameterTypes.size(); i++) {
     TypeProjection parameterType = parameterTypes.get(i);
     ValueParameterDescriptorImpl valueParameterDescriptor =
         new ValueParameterDescriptorImpl(
             functionDescriptor,
             null,
             i,
             Annotations.Companion.getEMPTY(),
             Name.identifier("p" + (i + 1)),
             parameterType.getType(),
             /* declaresDefaultValue = */ false,
             /* isCrossinline = */ false,
             /* isNoinline = */ false,
             null,
             SourceElement.NO_SOURCE);
     valueParameters.add(valueParameterDescriptor);
   }
   return valueParameters;
 }
  // Returns list with type arguments info from supertypes
  // Example:
  //     - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
  //     - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
  //     - output[0] = [String, CharSequence], output[1] = []
  private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
      @NotNull ClassDescriptor klass, @NotNull Collection<TypeAndVariance> typesFromSuper) {
    // For each superclass of klass and its parameters, hold their mapping to klass' parameters
    // #0 of Bar ->  A
    // #1 of Bar ->  List<B>
    // #0 of Baz ->  Boolean
    // #1 of Baz ->  A
    // #0 of Foo ->  A (mapped to itself)
    // #1 of Foo ->  B (mapped to itself)
    Multimap<TypeConstructor, TypeProjection> substitution =
        SubstitutionUtils.buildDeepSubstitutionMultimap(
            TypeUtils.makeUnsubstitutedType(klass, JetScope.EMPTY));

    // for each parameter of klass, hold arguments in corresponding supertypes
    List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
    for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
      parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
    }

    // Enumerate all types from super and all its parameters
    for (TypeAndVariance typeFromSuper : typesFromSuper) {
      for (TypeParameterDescriptor parameter :
          typeFromSuper.type.getConstructor().getParameters()) {
        TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());

        // for given example, this block is executed four times:
        // 1. typeFromSuper = Bar<String, List<Int>>,      parameter = "#0 of Bar",  argument =
        // String
        // 2. typeFromSuper = Bar<String, List<Int>>,      parameter = "#1 of Bar",  argument =
        // List<Int>
        // 3. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#0 of Baz",  argument =
        // Boolean
        // 4. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#1 of Baz",  argument =
        // CharSequence

        // if it is mapped to klass' parameter, then store it into map
        for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) {
          // 1. projection = A
          // 2. projection = List<B>
          // 3. projection = Boolean
          // 4. projection = A
          ClassifierDescriptor classifier =
              projection.getType().getConstructor().getDeclarationDescriptor();

          // this condition is true for 1 and 4, false for 2 and 3
          if (classifier instanceof TypeParameterDescriptor
              && classifier.getContainingDeclaration() == klass) {
            int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
            Variance effectiveVariance =
                parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
            parameterToArgumentsFromSuper
                .get(parameterIndex)
                .add(new TypeProjectionAndVariance(argument, effectiveVariance));
          }
        }
      }
    }
    return parameterToArgumentsFromSuper;
  }
Beispiel #4
0
 public static boolean containsErrorType(@Nullable JetType type) {
   if (type == null) return false;
   if (type instanceof NamespaceType) return false;
   if (isErrorType(type)) return true;
   for (TypeProjection projection : type.getArguments()) {
     if (containsErrorType(projection.getType())) return true;
   }
   return false;
 }
Beispiel #5
0
 public static boolean dependsOnTypeConstructors(
     @NotNull KotlinType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
   if (typeParameterConstructors.contains(type.getConstructor())) return true;
   for (TypeProjection typeProjection : type.getArguments()) {
     if (!typeProjection.isStarProjection()
         && dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) {
       return true;
     }
   }
   return false;
 }
 private void appendTypeProjections(
     @NotNull List<TypeProjection> typeProjections, @NotNull StringBuilder builder) {
   for (Iterator<TypeProjection> iterator = typeProjections.iterator(); iterator.hasNext(); ) {
     TypeProjection typeProjection = iterator.next();
     if (typeProjection.getProjectionKind() != Variance.INVARIANT) {
       builder.append(typeProjection.getProjectionKind()).append(" ");
     }
     builder.append(renderType(typeProjection.getType()));
     if (iterator.hasNext()) {
       builder.append(", ");
     }
   }
 }
  private TypeProjection substituteCompoundType(
      TypeProjection originalProjection, int recursionDepth) throws SubstitutionException {
    final JetType type = originalProjection.getType();
    Variance projectionKind = originalProjection.getProjectionKind();
    if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
      // substitution can't change type parameter
      // todo substitute bounds
      return originalProjection;
    }

    List<TypeProjection> substitutedArguments =
        substituteTypeArguments(
            type.getConstructor().getParameters(), type.getArguments(), recursionDepth);

    // Only type parameters of the corresponding class (or captured type parameters of outer
    // declaration) are substituted
    // e.g. for return type Foo of 'add(..)' in 'class Foo { fun <R> add(bar: Bar<R>): Foo }' R
    // shouldn't be substituted in the scope
    TypeSubstitution substitutionFilteringTypeParameters =
        new TypeSubstitution() {
          private final Collection<TypeConstructor> containedOrCapturedTypeParameters =
              TypeUtilsKt.getContainedAndCapturedTypeParameterConstructors(type);

          @Nullable
          @Override
          public TypeProjection get(@NotNull JetType key) {
            return containedOrCapturedTypeParameters.contains(key.getConstructor())
                ? substitution.get(key)
                : null;
          }

          @Override
          public boolean isEmpty() {
            return substitution.isEmpty();
          }
        };
    JetType substitutedType =
        JetTypeImpl.create(
            type.getAnnotations(), // Old annotations. This is questionable
            type.getConstructor(), // The same constructor
            type.isMarkedNullable(), // Same nullability
            substitutedArguments,
            substitutionFilteringTypeParameters,
            new SubstitutingScope(
                type.getMemberScope(), create(substitutionFilteringTypeParameters)),
            type.getCapabilities());
    return new TypeProjectionImpl(projectionKind, substitutedType);
  }
  private Variance calculateArgumentProjectionKindFromSuper(
      @NotNull TypeProjection argument,
      @NotNull List<TypeProjectionAndVariance> projectionsFromSuper) {
    Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet();
    for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) {
      projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind());
    }

    Variance defaultProjectionKind = argument.getProjectionKind();
    if (projectionKindsInSuper.size() == 0) {
      return defaultProjectionKind;
    } else if (projectionKindsInSuper.size() == 1) {
      Variance projectionKindInSuper = projectionKindsInSuper.iterator().next();
      if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) {
        return projectionKindInSuper;
      } else {
        reportError(
            "Incompatible projection kinds in type arguments of super methods' return types: "
                + projectionsFromSuper
                + ", defined in current: "
                + argument);
        return defaultProjectionKind;
      }
    } else {
      reportError(
          "Incompatible projection kinds in type arguments of super methods' return types: "
              + projectionsFromSuper);
      return defaultProjectionKind;
    }
  }
Beispiel #9
0
 public static boolean contains(
     @Nullable KotlinType type, @NotNull Function1<KotlinType, Boolean> isSpecialType) {
   if (type == null) return false;
   if (isSpecialType.invoke(type)) return true;
   Flexibility flexibility = type.getCapability(Flexibility.class);
   if (flexibility != null
       && (contains(flexibility.getLowerBound(), isSpecialType)
           || contains(flexibility.getUpperBound(), isSpecialType))) {
     return true;
   }
   for (TypeProjection projection : type.getArguments()) {
     if (!projection.isStarProjection() && contains(projection.getType(), isSpecialType))
       return true;
   }
   return false;
 }
Beispiel #10
0
  @NotNull
  public static JetType createCorrespondingExtensionFunctionType(
      @NotNull JetType functionType, @NotNull JetType receiverType) {
    assert KotlinBuiltIns.getInstance().isFunctionType(functionType);

    List<TypeProjection> typeArguments = functionType.getArguments();
    assert !typeArguments.isEmpty();

    List<JetType> arguments = Lists.newArrayList();
    // excluding the last type argument of the function type, which is the return type
    int index = 0;
    int lastIndex = typeArguments.size() - 1;
    for (TypeProjection typeArgument : typeArguments) {
      if (index < lastIndex) {
        arguments.add(typeArgument.getType());
      }
      index++;
    }
    JetType returnType = typeArguments.get(lastIndex).getType();
    return KotlinBuiltIns.getInstance()
        .getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType);
  }
  @NotNull
  private List<TypeProjection> getTypeArgsOfType(
      @NotNull JetType autoType,
      @NotNull ClassifierDescriptor classifier,
      @NotNull List<TypeAndVariance> typesFromSuper) {
    List<TypeProjection> autoArguments = autoType.getArguments();

    if (!(classifier instanceof ClassDescriptor)) {
      assert autoArguments.isEmpty()
          : "Unexpected type arguments when type constructor is not ClassDescriptor, type = "
              + autoType;
      return autoArguments;
    }

    List<List<TypeProjectionAndVariance>> typeArgumentsFromSuper =
        calculateTypeArgumentsFromSuper((ClassDescriptor) classifier, typesFromSuper);

    // Modify type arguments using info from typesFromSuper
    List<TypeProjection> resultArguments = Lists.newArrayList();
    for (TypeParameterDescriptor parameter : classifier.getTypeConstructor().getParameters()) {
      TypeProjection argument = autoArguments.get(parameter.getIndex());

      JetType argumentType = argument.getType();
      List<TypeProjectionAndVariance> projectionsFromSuper =
          typeArgumentsFromSuper.get(parameter.getIndex());
      List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);

      JetType type =
          modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT);
      Variance projectionKind =
          calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);

      resultArguments.add(new TypeProjection(projectionKind, type));
    }
    return resultArguments;
  }
Beispiel #12
0
  /**
   * Determines what constraint (supertype, subtype or equal) should be generated for type parameter
   * {@code T} in a constraint like (in this example subtype one): <br>
   * {@code MyClass<in/out/- A> <: MyClass<in/out/- B>}, where {@code MyClass<in/out/- T>} is
   * declared. <br>
   * The parameters description is given according to the example above.
   *
   * @param typeParameterVariance declared variance of T
   * @param subjectTypeProjection {@code in/out/- A}
   * @param constrainingTypeProjection {@code in/out/- B}
   * @param upperConstraintKind kind of the constraint {@code MyClass<...A> <: MyClass<...B>}
   *     (subtype in this example).
   * @return kind of constraint to be generated: {@code A <: B} (subtype), {@code A >: B}
   *     (supertype) or {@code A = B} (equal).
   */
  @NotNull
  private static ConstraintKind getTypeParameterConstraintKind(
      @NotNull Variance typeParameterVariance,
      @NotNull TypeProjection subjectTypeProjection,
      @NotNull TypeProjection constrainingTypeProjection,
      @NotNull ConstraintKind upperConstraintKind) {
    // If variance of type parameter is non-trivial, it should be taken into consideration to infer
    // result constraint type.
    // Otherwise when type parameter declared as INVARIANT, there might be non-trivial use-site
    // variance of a supertype.
    //
    // Example: Let class MyClass<T> is declared.
    //
    // If super type has 'out' projection:
    // MyClass<A> <: MyClass<out B>,
    // then constraint A <: B can be generated.
    //
    // If super type has 'in' projection:
    // MyClass<A> <: MyClass<in B>,
    // then constraint A >: B can be generated.
    //
    // Otherwise constraint A = B should be generated.

    Variance varianceForTypeParameter;
    if (typeParameterVariance != INVARIANT) {
      varianceForTypeParameter = typeParameterVariance;
    } else if (upperConstraintKind == SUPER_TYPE) {
      varianceForTypeParameter = constrainingTypeProjection.getProjectionKind();
    } else if (upperConstraintKind == SUB_TYPE) {
      varianceForTypeParameter = subjectTypeProjection.getProjectionKind();
    } else {
      varianceForTypeParameter = INVARIANT;
    }

    return getTypeParameterConstraintKind(varianceForTypeParameter, upperConstraintKind);
  }
 @Nullable
 public JetType substitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
   TypeProjection projection = substitute(new TypeProjectionImpl(howThisTypeIsUsed, type));
   return projection == null ? null : projection.getType();
 }
  @NotNull
  private TypeProjection unsafeSubstitute(
      @NotNull TypeProjection originalProjection, int recursionDepth) throws SubstitutionException {
    assertRecursionDepth(recursionDepth, originalProjection, substitution);

    if (originalProjection.isStarProjection()) return originalProjection;

    // The type is within the substitution range, i.e. T or T?
    JetType type = originalProjection.getType();
    TypeProjection replacement = substitution.get(type);
    Variance originalProjectionKind = originalProjection.getProjectionKind();
    if (replacement == null
        && FlexibleTypesKt.isFlexible(type)
        && !TypeCapabilitiesKt.isCustomTypeVariable(type)) {
      Flexibility flexibility = FlexibleTypesKt.flexibility(type);
      TypeProjection substitutedLower =
          unsafeSubstitute(
              new TypeProjectionImpl(originalProjectionKind, flexibility.getLowerBound()),
              recursionDepth + 1);
      TypeProjection substitutedUpper =
          unsafeSubstitute(
              new TypeProjectionImpl(originalProjectionKind, flexibility.getUpperBound()),
              recursionDepth + 1);

      Variance substitutedProjectionKind = substitutedLower.getProjectionKind();
      assert (substitutedProjectionKind == substitutedUpper.getProjectionKind())
                  && originalProjectionKind == Variance.INVARIANT
              || originalProjectionKind == substitutedProjectionKind
          : "Unexpected substituted projection kind: "
              + substitutedProjectionKind
              + "; original: "
              + originalProjectionKind;

      JetType substitutedFlexibleType =
          DelegatingFlexibleType.create(
              substitutedLower.getType(),
              substitutedUpper.getType(),
              flexibility.getExtraCapabilities());
      return new TypeProjectionImpl(substitutedProjectionKind, substitutedFlexibleType);
    }

    if (KotlinBuiltIns.isNothing(type) || type.isError()) return originalProjection;

    if (replacement != null) {
      VarianceConflictType varianceConflict =
          conflictType(originalProjectionKind, replacement.getProjectionKind());

      // Captured type might be substituted in an opposite projection:
      // out 'Captured (in Int)' = out Int
      // in 'Captured (out Int)' = in Int
      boolean allowVarianceConflict = CapturedTypeConstructorKt.isCaptured(type);
      if (!allowVarianceConflict) {
        //noinspection EnumSwitchStatementWhichMissesCases
        switch (varianceConflict) {
          case OUT_IN_IN_POSITION:
            throw new SubstitutionException("Out-projection in in-position");
          case IN_IN_OUT_POSITION:
            // todo use the right type parameter variance and upper bound
            return new TypeProjectionImpl(
                Variance.OUT_VARIANCE, type.getConstructor().getBuiltIns().getNullableAnyType());
        }
      }
      JetType substitutedType;
      CustomTypeVariable typeVariable = TypeCapabilitiesKt.getCustomTypeVariable(type);
      if (replacement.isStarProjection()) {
        return replacement;
      } else if (typeVariable != null) {
        substitutedType = typeVariable.substitutionResult(replacement.getType());
      } else {
        // this is a simple type T or T?: if it's T, we should just take replacement, if T? - we
        // make replacement nullable
        substitutedType =
            TypeUtils.makeNullableIfNeeded(replacement.getType(), type.isMarkedNullable());
      }

      // substitutionType.annotations = replacement.annotations ++ type.annotations
      if (!type.getAnnotations().isEmpty()) {
        Annotations typeAnnotations = filterOutUnsafeVariance(type.getAnnotations());
        substitutedType =
            TypeUtilsKt.replaceAnnotations(
                substitutedType,
                new CompositeAnnotations(substitutedType.getAnnotations(), typeAnnotations));
      }

      Variance resultingProjectionKind =
          varianceConflict == VarianceConflictType.NO_CONFLICT
              ? combine(originalProjectionKind, replacement.getProjectionKind())
              : originalProjectionKind;
      return new TypeProjectionImpl(resultingProjectionKind, substitutedType);
    }
    // The type is not within the substitution range, i.e. Foo, Bar<T> etc.
    return substituteCompoundType(originalProjection, recursionDepth);
  }
Beispiel #15
0
 public static JetType createWrongVarianceErrorType(TypeProjection value) {
   return createErrorType(value + " is not allowed here", value.getType().getMemberScope());
 }
Beispiel #16
0
  public static boolean canHaveSubtypes(KotlinTypeChecker typeChecker, @NotNull KotlinType type) {
    if (type.isMarkedNullable()) {
      return true;
    }
    if (!type.getConstructor().isFinal()) {
      return true;
    }

    List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
    List<TypeProjection> arguments = type.getArguments();
    for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
      TypeParameterDescriptor parameterDescriptor = parameters.get(i);
      TypeProjection typeProjection = arguments.get(i);
      if (typeProjection.isStarProjection()) return true;

      Variance projectionKind = typeProjection.getProjectionKind();
      KotlinType argument = typeProjection.getType();

      switch (parameterDescriptor.getVariance()) {
        case INVARIANT:
          switch (projectionKind) {
            case INVARIANT:
              if (lowerThanBound(typeChecker, argument, parameterDescriptor)
                  || canHaveSubtypes(typeChecker, argument)) {
                return true;
              }
              break;
            case IN_VARIANCE:
              if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
                return true;
              }
              break;
            case OUT_VARIANCE:
              if (canHaveSubtypes(typeChecker, argument)) {
                return true;
              }
              break;
          }
          break;
        case IN_VARIANCE:
          if (projectionKind != Variance.OUT_VARIANCE) {
            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
              return true;
            }
          } else {
            if (canHaveSubtypes(typeChecker, argument)) {
              return true;
            }
          }
          break;
        case OUT_VARIANCE:
          if (projectionKind != Variance.IN_VARIANCE) {
            if (canHaveSubtypes(typeChecker, argument)) {
              return true;
            }
          } else {
            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
              return true;
            }
          }
          break;
      }
    }
    return false;
  }
 public String toString() {
   return typeProjection.toString();
 }
Beispiel #18
0
  private void addConstraint(
      @NotNull ConstraintKind constraintKind,
      @NotNull JetType subjectType,
      @Nullable JetType constrainingType,
      @NotNull ConstraintPosition constraintPosition) {

    if (constrainingType == TypeUtils.NO_EXPECTED_TYPE
        || constrainingType == DONT_CARE
        || constrainingType == CANT_INFER) {
      return;
    }

    if (constrainingType == null
        || (ErrorUtils.isErrorType(constrainingType)
            && constrainingType != PLACEHOLDER_FUNCTION_TYPE)) {
      hasErrorInConstrainingTypes = true;
      return;
    }

    assert subjectType != TypeUtils.NO_EXPECTED_TYPE
        : "Subject type shouldn't be NO_EXPECTED_TYPE (in position " + constraintPosition + " )";
    if (ErrorUtils.isErrorType(subjectType)) return;

    DeclarationDescriptor subjectTypeDescriptor =
        subjectType.getConstructor().getDeclarationDescriptor();

    KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance();
    if (constrainingType == PLACEHOLDER_FUNCTION_TYPE) {
      if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(subjectType)) {
        if (subjectTypeDescriptor instanceof TypeParameterDescriptor
            && typeParameterConstraints.get(subjectTypeDescriptor) != null) {
          // a constraint binds type parameter and any function type, so there is no new info and no
          // error
          return;
        }
        errorConstraintPositions.add(constraintPosition);
      }
      return;
    }

    // todo temporary hack
    // function literal without declaring receiver type { x -> ... }
    // can be considered as extension function if one is expected
    // (special type constructor for function/ extension function should be introduced like
    // PLACEHOLDER_FUNCTION_TYPE)
    if (constraintKind == SUB_TYPE
        && kotlinBuiltIns.isFunctionType(constrainingType)
        && kotlinBuiltIns.isExtensionFunctionType(subjectType)) {
      constrainingType = createCorrespondingExtensionFunctionType(constrainingType, DONT_CARE);
    }

    DeclarationDescriptor constrainingTypeDescriptor =
        constrainingType.getConstructor().getDeclarationDescriptor();

    if (subjectTypeDescriptor instanceof TypeParameterDescriptor) {
      TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) subjectTypeDescriptor;
      TypeConstraintsImpl typeConstraints = typeParameterConstraints.get(typeParameter);
      if (typeConstraints != null) {
        if (TypeUtils.dependsOnTypeParameterConstructors(
            constrainingType, Collections.singleton(DONT_CARE.getConstructor()))) {
          return;
        }
        if (subjectType.isNullable() && constrainingType.isNullable()) {
          constrainingType = TypeUtils.makeNotNullable(constrainingType);
        }
        typeConstraints.addBound(constraintKind, constrainingType);
        return;
      }
    }
    if (constrainingTypeDescriptor instanceof TypeParameterDescriptor) {
      assert typeParameterConstraints.get(constrainingTypeDescriptor) == null
          : "Constraining type contains type variable " + constrainingTypeDescriptor.getName();
    }
    if (constraintKind == SUB_TYPE && kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) {
      // following constraints are always true:
      // 'Nothing' is a subtype of any type
      if (!constrainingType.isNullable()) return;
      // 'Nothing?' is a subtype of nullable type
      if (subjectType.isNullable()) return;
    }
    if (!(constrainingTypeDescriptor instanceof ClassDescriptor)
        || !(subjectTypeDescriptor instanceof ClassDescriptor)) {
      errorConstraintPositions.add(constraintPosition);
      return;
    }
    switch (constraintKind) {
      case SUB_TYPE:
        {
          if (kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) break;
          JetType correspondingSupertype =
              TypeCheckingProcedure.findCorrespondingSupertype(constrainingType, subjectType);
          if (correspondingSupertype != null) {
            constrainingType = correspondingSupertype;
          }
          break;
        }
      case SUPER_TYPE:
        {
          if (kotlinBuiltIns.isNothingOrNullableNothing(subjectType)) break;
          JetType correspondingSupertype =
              TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType);
          if (correspondingSupertype != null) {
            subjectType = correspondingSupertype;
          }
        }
      case EQUAL: // nothing
    }
    if (constrainingType.getConstructor() != subjectType.getConstructor()) {
      errorConstraintPositions.add(constraintPosition);
      return;
    }
    TypeConstructor typeConstructor = subjectType.getConstructor();
    List<TypeProjection> subjectArguments = subjectType.getArguments();
    List<TypeProjection> constrainingArguments = constrainingType.getArguments();
    List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
    for (int i = 0; i < subjectArguments.size(); i++) {
      Variance typeParameterVariance = parameters.get(i).getVariance();
      TypeProjection subjectArgument = subjectArguments.get(i);
      TypeProjection constrainingArgument = constrainingArguments.get(i);

      ConstraintKind typeParameterConstraintKind =
          getTypeParameterConstraintKind(
              typeParameterVariance, subjectArgument, constrainingArgument, constraintKind);

      addConstraint(
          typeParameterConstraintKind,
          subjectArgument.getType(),
          constrainingArgument.getType(),
          constraintPosition);
    }
  }