private void computeTypeParameters(List<TypeParameterDescriptor> typeParameters) {
    if (typeParameters.size() != altFunDeclaration.getTypeParameters().size()) {
      throw new AlternativeSignatureMismatchException(
          "Method signature has %d type parameters, but alternative signature has %d",
          typeParameters.size(), altFunDeclaration.getTypeParameters().size());
    }

    altTypeParameters = new ArrayList<TypeParameterDescriptor>();

    for (int i = 0, size = typeParameters.size(); i < size; i++) {
      TypeParameterDescriptor originalTypeParamDescriptor = typeParameters.get(i);

      TypeParameterDescriptorImpl altParamDescriptor =
          originalToAltTypeParameters.get(originalTypeParamDescriptor);
      JetTypeParameter altTypeParameter = altFunDeclaration.getTypeParameters().get(i);

      int upperBoundIndex = 0;
      for (JetType upperBound : originalTypeParamDescriptor.getUpperBounds()) {
        JetTypeElement altTypeElement;

        if (upperBoundIndex == 0) {
          JetTypeReference extendsBound = altTypeParameter.getExtendsBound();
          if (extendsBound == null) { // default upper bound
            assert originalTypeParamDescriptor.getUpperBounds().size() == 1;
            altParamDescriptor.addDefaultUpperBound();
            break;
          } else {
            altTypeElement = extendsBound.getTypeElement();
          }
        } else {
          JetTypeConstraint constraint =
              findTypeParameterConstraint(
                  altFunDeclaration, originalTypeParamDescriptor.getName(), upperBoundIndex);
          if (constraint == null) {
            throw new AlternativeSignatureMismatchException(
                "Upper bound #%d for type parameter %s is missing",
                upperBoundIndex, originalTypeParamDescriptor.getName());
          }
          //noinspection ConstantConditions
          altTypeElement = constraint.getBoundTypeReference().getTypeElement();
        }

        assert (altTypeElement != null);

        altParamDescriptor.addUpperBound(
            TypeTransformingVisitor.computeType(
                altTypeElement, upperBound,
                originalToAltTypeParameters, UPPER_BOUND));
        upperBoundIndex++;
      }

      if (findTypeParameterConstraint(
              altFunDeclaration, originalTypeParamDescriptor.getName(), upperBoundIndex)
          != null) {
        throw new AlternativeSignatureMismatchException(
            "Extra upper bound #%d for type parameter %s",
            upperBoundIndex, originalTypeParamDescriptor.getName());
      }

      altParamDescriptor.setInitialized();
      altTypeParameters.add(altParamDescriptor);
    }
  }
  private void computeValueParameters(
      @NotNull List<ValueParameterDescriptor> parameterDescriptors) {
    if (parameterDescriptors.size() != altFunDeclaration.getValueParameters().size()) {
      throw new AlternativeSignatureMismatchException(
          "Method signature has %d value parameters, but alternative signature has %d",
          parameterDescriptors.size(), altFunDeclaration.getValueParameters().size());
    }

    List<ValueParameterDescriptor> altParamDescriptors = new ArrayList<ValueParameterDescriptor>();
    for (int i = 0, size = parameterDescriptors.size(); i < size; i++) {
      ValueParameterDescriptor originalParameterDescriptor = parameterDescriptors.get(i);
      JetParameter annotationValueParameter = altFunDeclaration.getValueParameters().get(i);

      //noinspection ConstantConditions
      JetTypeElement alternativeTypeElement =
          annotationValueParameter.getTypeReference().getTypeElement();
      assert alternativeTypeElement != null;

      JetType alternativeType;
      JetType alternativeVarargElementType;

      JetType originalParamVarargElementType = originalParameterDescriptor.getVarargElementType();
      if (originalParamVarargElementType == null) {
        if (annotationValueParameter.isVarArg()) {
          throw new AlternativeSignatureMismatchException(
              "Parameter in method signature is not vararg, but in alternative signature it is vararg");
        }

        alternativeType =
            TypeTransformingVisitor.computeType(
                alternativeTypeElement,
                originalParameterDescriptor.getType(),
                originalToAltTypeParameters,
                MEMBER_SIGNATURE_CONTRAVARIANT);
        alternativeVarargElementType = null;
      } else {
        if (!annotationValueParameter.isVarArg()) {
          throw new AlternativeSignatureMismatchException(
              "Parameter in method signature is vararg, but in alternative signature it is not");
        }

        alternativeVarargElementType =
            TypeTransformingVisitor.computeType(
                alternativeTypeElement, originalParamVarargElementType,
                originalToAltTypeParameters, MEMBER_SIGNATURE_CONTRAVARIANT);
        alternativeType = KotlinBuiltIns.getInstance().getArrayType(alternativeVarargElementType);
      }

      Name altName = annotationValueParameter.getNameAsName();

      altParamDescriptors.add(
          new ValueParameterDescriptorImpl(
              originalParameterDescriptor.getContainingDeclaration(),
              null,
              originalParameterDescriptor.getIndex(),
              originalParameterDescriptor.getAnnotations(),
              altName != null ? altName : originalParameterDescriptor.getName(),
              alternativeType,
              originalParameterDescriptor.declaresDefaultValue(),
              alternativeVarargElementType));
    }

    altValueParameters = altParamDescriptors;
  }