private void addConstraint(
      @NotNull NapileType subjectType,
      @Nullable NapileType constrainingType,
      @NotNull ConstraintPosition constraintPosition) {
    if (constrainingType == null
        || (ErrorUtils.isErrorType(constrainingType) && constrainingType != DONT_CARE)) {
      hasErrorInConstrainingTypes = true;
      return;
    }

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

    if (constrainingType == DONT_CARE
        || ErrorUtils.isErrorType(subjectType)
        || constrainingType == TypeUtils.NO_EXPECTED_TYPE) return;

    DeclarationDescriptor subjectTypeDescriptor =
        subjectType.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(constrainingType);
        return;
      }
    }

    NapileType correspondingSupertype =
        TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType);
    if (correspondingSupertype != null) subjectType = correspondingSupertype;

    List<NapileType> subjectArguments = subjectType.getArguments();
    List<NapileType> constrainingArguments = constrainingType.getArguments();
    if (subjectArguments.size() != constrainingArguments.size()) return;

    for (int i = 0; i < subjectArguments.size(); i++)
      addConstraint(subjectArguments.get(i), constrainingArguments.get(i), constraintPosition);
  }
 @Nullable
 @Override
 public NapileType getType(@NotNull NapileScope napileScope) {
   return TypeUtils.getTypeOfClassOrErrorType(napileScope, NapileLangPackage.CHAR, false);
 }