Search code examples
emacselisp

Infinite loop when byte compile


I'm author of evil-commentary, the full source less than 200 lines can be found in the repo.

Basically I have something like this.

(evil-define-operator evil-commentary (beg end type)
  "Comment or uncomment region that {motion} moves over."
  :move-point nil
  (interactive "<R>")
  (let ((comment-function
         (cdr (assoc major-mode
                     evil-commentary-comment-function-for-mode-alist))))
    (if comment-function (funcall comment-function beg end)
      (comment-or-uncomment-region beg end))))


(defun evil-commentary-comment-for-org (beg end)
  "Comment function for `org-mode'."
  (interactive "r")
  (if (and (fboundp 'org-in-src-block-p)
           (org-in-src-block-p))
      (evil-commentary-do-in-org-src-block beg end
        (call-interactively 'evil-commentary))
    (comment-or-uncomment-region beg end)))

The idea is that evil-commentary will call evil-commentary-comment-for-org in an org file, and if we're in a src block, evil-commentary-comment-for-org will call evil-commentary again in the src-edit buffer (which now has different major-mode)

The setup works just fine, however when I compile the code, I get an infinite loop evil-commentary -> evil-commentary-comment-for-org -> evil-commentary... with Variable binding depth exceeds max-specpdl-size error...

I found that it will work if I compile the code after org is loaded, but that not I wanted because evil-commentary will stop working if an user compile with an old version of org then upgrade it. (A flaw of package.el)

Thank you!


Solution

  • The problem is in this line, which expands to:

      (org-babel-do-in-edit-buffer
       (call-interactively 'evil-commentary))
    

    If you haven't loaded org, the byte compiler doesn't know org-babel-do-in-edit-buffer is a macro, and can't expand it. So it simply compiles a call to an (as of yet unknown) function called org-babel-do-in-edit-buffer.

    When execution reaches that line, the function arguments are evaluated first (as in any other function call) and there you have your infinite loop.

    Try requiring org inside an eval-when-compile block.