private static String getInlineName(
      @NotNull CodegenContext codegenContext,
      @NotNull DeclarationDescriptor currentDescriptor,
      @NotNull JetTypeMapper typeMapper,
      @NotNull JvmFileClassesProvider fileClassesProvider) {
    if (currentDescriptor instanceof PackageFragmentDescriptor) {
      PsiFile file = getContainingFile(codegenContext);

      Type implementationOwnerType;
      if (file == null) {
        implementationOwnerType =
            CodegenContextUtil.getImplementationOwnerClassType(codegenContext);
      } else {
        implementationOwnerType =
            FileClassesPackage.getFileClassType(fileClassesProvider, (JetFile) file);
      }

      if (implementationOwnerType == null) {
        DeclarationDescriptor contextDescriptor = codegenContext.getContextDescriptor();
        //noinspection ConstantConditions
        throw new RuntimeException(
            "Couldn't find declaration for "
                + contextDescriptor.getContainingDeclaration().getName()
                + "."
                + contextDescriptor.getName()
                + "; context: "
                + codegenContext);
      }

      return implementationOwnerType.getInternalName();
    } else if (currentDescriptor instanceof ClassifierDescriptor) {
      Type type = typeMapper.mapType((ClassifierDescriptor) currentDescriptor);
      return type.getInternalName();
    } else if (currentDescriptor instanceof FunctionDescriptor) {
      ClassDescriptor descriptor =
          typeMapper
              .getBindingContext()
              .get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor);
      if (descriptor != null) {
        Type type = typeMapper.mapType(descriptor);
        return type.getInternalName();
      }
    }

    // TODO: add suffix for special case
    String suffix =
        currentDescriptor.getName().isSpecial() ? "" : currentDescriptor.getName().asString();

    //noinspection ConstantConditions
    return getInlineName(
            codegenContext,
            currentDescriptor.getContainingDeclaration(),
            typeMapper,
            fileClassesProvider)
        + "$"
        + suffix;
  }
  @NotNull
  public static List<FieldInfo> calculateConstructorParameters(
      @NotNull JetTypeMapper typeMapper,
      @NotNull CalculatedClosure closure,
      @NotNull Type ownerType) {
    BindingContext bindingContext = typeMapper.getBindingContext();
    List<FieldInfo> args = Lists.newArrayList();
    ClassDescriptor captureThis = closure.getCaptureThis();
    if (captureThis != null) {
      Type type = typeMapper.mapType(captureThis);
      args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
    }
    JetType captureReceiverType = closure.getCaptureReceiverType();
    if (captureReceiverType != null) {
      args.add(
          FieldInfo.createForHiddenField(
              ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
    }

    for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
      if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
        Type sharedVarType = typeMapper.getSharedVarType(descriptor);

        Type type =
            sharedVarType != null
                ? sharedVarType
                : typeMapper.mapType((VariableDescriptor) descriptor);
        args.add(
            FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString()));
      } else if (DescriptorUtils.isLocalFunction(descriptor)) {
        Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
        args.add(
            FieldInfo.createForHiddenField(
                ownerType, classType, "$" + descriptor.getName().asString()));
      } else if (descriptor instanceof FunctionDescriptor) {
        assert captureReceiverType != null;
      }
    }
    return args;
  }