[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: A combination of defmacro, functionp, and quoted lambdas yields diff

From: Stefan Monnier
Subject: Re: A combination of defmacro, functionp, and quoted lambdas yields different results on consecutive evaluations
Date: Sun, 18 Feb 2018 13:02:11 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

>>> We recently ran into a problem in Flycheck that confused us.
>>> Evaluating the following twice yields different results on the first
>>> evaluation (nil) and on the subsequent ones (t):
>>> ;; nil on the first run; t on subsequent ones
>>> (progn
>>>   (defmacro m (f)
>>>     `(function ,f))
>>>   (functionp (m (lambda ()))))
>> Depends what you mean by "evaluating".  At top-level macroexpansion is
>> supposed to be careful to handle the above correctly (i.e. to evaluate
>> the defmacro) before performing the macro-expansion of the (functionp ...).
>> But for that we had to add ad-hoc code both to the byte-compiler and to
>> the lread.c code that does the eager-macroexpansion of non-compiled files.
>> So, how do you "evaluate" the above code in order to see this problem?
> Using C-M-x, or just by putting it in my .emacs.

I guess we could tweak C-M-x to try and make it work as well, but as for
"just putting it in my .emacs" it should already work (and does work for

The code to handle it when loading a file is in
readevalloop_eager_expand_eval (in src/lread.c), and the code to handle
it for the byte-compiler is in byte-compile-recurse-toplevel (in

Hmm... looking further I see that it "should" already work.
There's just a macroexpand-all that gets in the way.
So the patch below (which I pushed to master) makes it work (at least
for the non-edebug case).


diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index e6e55a37a7..935e55c5d7 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -1132,7 +1132,9 @@ elisp--eval-last-sexp
         (eval-expression-get-print-arguments eval-last-sexp-arg-internal)))
     ;; Setup the lexical environment if lexical-binding is enabled.
-     (eval (eval-sexp-add-defvars (elisp--preceding-sexp)) lexical-binding)
+     (eval (macroexpand-all
+            (eval-sexp-add-defvars (elisp--preceding-sexp)))
+           lexical-binding)
      (if insert-value (current-buffer) t) no-truncate char-print-limit)))
 (defun elisp--eval-last-sexp-print-value
@@ -1165,7 +1167,6 @@ elisp--eval-last-sexp-fake-value
 (defun eval-sexp-add-defvars (exp &optional pos)
   "Prepend EXP with all the `defvar's that precede it in the buffer.
 POS specifies the starting position where EXP was found and defaults to point."
-  (setq exp (macroexpand-all exp))      ;Eager macro-expansion.
   (if (not lexical-binding)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]