5

On startup I'm getting this message:

Eager macro-expansion failure: (wrong-number-of-arguments (3 . 3) 2)

How can I find whats causing the warning? --debug-init doesn't do anything in this case as it does with many other errors.

Drew
  • 75,699
  • 9
  • 109
  • 225
ideasman42
  • 8,375
  • 1
  • 28
  • 105
  • 1
    You find [`internal-macroexpand-for-load` in `macroexp.el`](https://github.com/jwiegley/emacs-release/blob/adfd5933358fdf6715423dee8169eb3cd7d982db/lisp/emacs-lisp/macroexp.el#L405-L434). You could copy the code to the beginning of your init-file (maybe early-init file) and include the `form` argument and the load file in the message string, i.e., `(message "Eager macro-expansion failure: %S form: %S load file: %S" err form load-file-name)`. Maybe that helps to identify the problem. – Tobias Dec 19 '19 at 15:07
  • If starting Emacs using `emacs -Q` doesn't show the problem then blame your init file. The easiest approach to finding a problem in your init file is to bisect your init file. That's a binary search - very quick to do. – Drew Dec 19 '19 at 15:41
  • @Drew It depends on the situation whether bisection is really the best way to go. My init file `~/.emacs` loads 60 files `~/.emacs.d/[0-9][0-9]*.el`. That does not include the libraries that are loaded from those. I've got some mechanism that allows me to select just a bunch of those files if I have problems. Even so this is not enjoyable and a direct hint on what goes wrong is really nice. – Tobias Dec 19 '19 at 20:45
  • @Tobias: Even if your init file loads 60,000 files, it's still the quickest way. Unless, of course, you already have a good idea where the problem likely lies. If not, then cutting the search space in half for each quick test is as good as it gets. (And all too often we can *think* we have a good idea where the problem might lie, and end up wasting time going down rabbit holes.) No, it's not always the best approach. Yes, it's the best approach, every thing else being equal (i.e., no good knowledge). – Drew Dec 19 '19 at 21:00
  • 2
    @Tobias: OP wants to trace eager macroexpansion - a legitimate aim/question in its own right. Not necessarily the quickest way to solve the given wrong-args problem, but good to know - a good question - in any case. – Drew Dec 19 '19 at 21:03
  • 1
    @Drew You said: "Unless, of course, you already have a good idea where the problem likely lies." My [first comment](https://emacs.stackexchange.com/questions/54455/how-to-get-a-stack-trace-for-eager-macro-expansion-failure?noredirect=1#comment85086_54455) aims at getting more information for building up that "good idea". You are clearly right that if the occurrence probability is evenly distributed over the full domain then bisection is the best approach. – Tobias Dec 19 '19 at 21:14

1 Answers1

1

This error message comes from the macroexp.el function, internal-macroexpand-for-load. It should go a little something like this (I have simplified the t portion of a cond, where most code will end up):

    (condition-case err
        (let ((macroexp--pending-eager-loads
               (cons load-file-name macroexp--pending-eager-loads)))
          (if full-p
              (macroexpand-all form)
            (macroexpand form)))
      (error
       ;; Hopefully this shouldn't happen thanks to the cycle detection,
       ;; but in case it does happen, let's catch the error and give the
       ;; code a chance to macro-expand later.
       (message "Eager macro-expansion failure: %S" err)
       form))

As you can see, it essentially swallows up the error. It's pretty hard to get at this, since the function will simply note the problem, eat the error, and return the original form. There is hope, though: debug-on-signal plus debug-on-error.

The error message you showed indicates that err in this condition-case is a signal: wrong-number-of-arguments. So if we instruct Emacs to first debug on any errors (by doing something like (setq debug-on-error t)), and then on any signal (with (setq debug-on-signal t)), we end up getting into the debugger with the stack trace ready to examine. If you don't mark debug-on-error, nothing will happen, so you need to have bot set to t.

FWIW, I reproduced the behavior you mentioned with this obviously wrong code:

(defun bad-defun (str)
  (rx (eval (substring str 1))))

...and M-x evaluate-buffer, then observed that I got a stack trace after executing M-: (setq debug-on-signal t) and M-: (setq debug-on-error t), so some similar combination may work for you. Perhaps setting it at the top of your initialization file, or passing it on the Emacs command line.

Caveat: Once you encounter the error, you should probably turn off debug-on-signal, because it will pop up when you are in the middle of something, any time a function reports an error or warning!

cyberbisson
  • 887
  • 1
  • 6
  • 17