unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#27016: possible bug in `defsetf'
@ 2017-05-22  6:39 Rafael D Sorkin
  2017-05-22 12:11 ` npostavs
                   ` (7 more replies)
  0 siblings, 8 replies; 42+ messages in thread
From: Rafael D Sorkin @ 2017-05-22  6:39 UTC (permalink / raw)
  To: 27016; +Cc: Rafael D Sorkin

Hi, 

The second behavior below seems like a bug to me.  It was not
present in emacs 23.1

Best wishes, 
Rafael Sorkin


emacs-version				; 23.1.1
(setq pair (cons 3 4))			; (3 . 4)
(foobar pair)				; Symbol's function definition is void: foobar
(setf (foobar pair) 0)			; No setf-method known for foobar 
(unless t
  (defalias 'foobar 'cons)
  (defsetf foobar setcar))		; nil 
(foobar pair)				; same as above
(setf (foobar pair) 0)			; same as above
pair					; (3 . 4)


emacs-version				; 24.5.1
(setq pair (cons 3 4))			; (3 . 4)
(foobar pair)				; Symbol's function definition is void: foobar
(setf (foobar pair) 0)			; (foobar pair) is not a valid place expression 
(unless t
  (defalias 'foobar 'cons)
  (defsetf foobar setcar))		; nil 
(foobar pair)				; same as above
(setf (foobar pair) 0)			; 0       !
pair					; (0 . 4) !


~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 Rafael Sorkin
 Perimeter Institute for Theoretical Physics
 31 Caroline Street North
 Waterloo, ON  N2L 2Y5
 Canada
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-






^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
@ 2017-05-22 12:11 ` npostavs
  2017-05-22 20:25 ` Rafael D Sorkin
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 42+ messages in thread
From: npostavs @ 2017-05-22 12:11 UTC (permalink / raw)
  To: Rafael D Sorkin; +Cc: 27016

tags 27016 unreproducible
quit

Rafael D Sorkin <rsorkin@perimeterinstitute.ca> writes:

> emacs-version				; 24.5.1
> (setq pair (cons 3 4))			; (3 . 4)
> (foobar pair)				; Symbol's function definition is void: foobar
> (setf (foobar pair) 0)			; (foobar pair) is not a valid place expression 
> (unless t
>   (defalias 'foobar 'cons)
>   (defsetf foobar setcar))		; nil 
> (foobar pair)				; same as above
> (setf (foobar pair) 0)			; 0       !
> pair					; (0 . 4) !

I'm not able to reproduce this behaviour on 24.5, the second setf throws
an error just like the first.  How are you evaluating these exactly
(starting from emacs -Q)?  I tried C-x C-e on each sexp in turn.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
  2017-05-22 12:11 ` npostavs
@ 2017-05-22 20:25 ` Rafael D Sorkin
  2017-05-22 21:18   ` npostavs
  2017-05-22 22:03 ` Rafael D Sorkin
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 42+ messages in thread
From: Rafael D Sorkin @ 2017-05-22 20:25 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin

Hi Noam,

Following your suggestion I tried starting with "emacs -Q" and
got the same results as you did.  However if I (require 'cl)
then the bug returns.  (I normally require CL automatically on
starting emacs.)  So perhaps it's an incompatibility between CL
and the new way that defsetf is implemented.

- Rafael

 > Sender: Noam Postavsky <npostavs@gmail.com>
 > From: npostavs@users.sourceforge.net
 > To: Rafael D Sorkin <rsorkin@perimeterinstitute.ca>
 > Cc: 27016@debbugs.gnu.org
 > Subject: Re: bug#27016: possible bug in `defsetf'
 > Date: Mon, 22 May 2017 08:11:25 -0400
 > In-Reply-To: <E1dCh04-0001Bd-Ec@mars.pi.local> (Rafael D. Sorkin's message of
 >  "Mon, 22 May 2017 02:39:28 -0400")
 > User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux)
 > 
 > tags 27016 unreproducible
 > quit
 > 
 > Rafael D Sorkin <rsorkin@perimeterinstitute.ca> writes:
 > 
 > > emacs-version				; 24.5.1
 > > (setq pair (cons 3 4))			; (3 . 4)
 > > (foobar pair)				; Symbol's function definition is void: foobar
 > > (setf (foobar pair) 0)			; (foobar pair) is not a valid place expression 
 > > (unless t
 > >   (defalias 'foobar 'cons)
 > >   (defsetf foobar setcar))		; nil 
 > > (foobar pair)				; same as above
 > > (setf (foobar pair) 0)			; 0       !
 > > pair					; (0 . 4) !
 > 
 > I'm not able to reproduce this behaviour on 24.5, the second setf throws
 > an error just like the first.  How are you evaluating these exactly
 > (starting from emacs -Q)?  I tried C-x C-e on each sexp in turn.

~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 Rafael Sorkin
 Perimeter Institute for Theoretical Physics
 31 Caroline Street North
 Waterloo, ON  N2L 2Y5
 Canada
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22 20:25 ` Rafael D Sorkin
@ 2017-05-22 21:18   ` npostavs
  2017-05-22 23:10     ` Michael Heerdegen
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-05-22 21:18 UTC (permalink / raw)
  To: Rafael D Sorkin; +Cc: 27016

tags 27016 - unreproducible
found 27016 24.4
found 27016 25.2
quit

Rafael D Sorkin <rsorkin@perimeterinstitute.ca> writes:

> Following your suggestion I tried starting with "emacs -Q" and
> got the same results as you did.  However if I (require 'cl)
> then the bug returns.  (I normally require CL automatically on
> starting emacs.)  So perhaps it's an incompatibility between CL
> and the new way that defsetf is implemented.

Oh, right, I see it now.  It happens in 24.4 and later.  I'm not sure
it's a bug though.  My guess is that the difference is eager
macroexpansion.  When I compile, then I get the same behaviour with 24.3
(that's my earliest working Emacs build) as well.

    $ emacs -Q -batch -l cl -f batch-byte-compile bug-27016-defsetf.el 

    In toplevel form:
    bug-27016-defsetf.el:1:1:Warning: cl package required at runtime
    bug-27016-defsetf.el:3:1:Warning: global/dynamic var `pair' lacks a prefix
    Wrote /home/npostavs/src/emacs/bug-27016-defsetf.elc
    $ emacs -Q -batch -l bug-27016-defsetf.elc
    pair: (0 . 4)

where bug-27016-defsetf.el has contents:

    (require 'cl)

    (defvar pair nil)
    (setq pair (cons 3 4))                  ; (3 . 4)
    (unless t
      (defalias 'foobar 'cons)
      (defsetf foobar setcar))              ; nil
    (setf (foobar pair) 0)                  ; 0       !

    (message "pair: %S" pair)






^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
  2017-05-22 12:11 ` npostavs
  2017-05-22 20:25 ` Rafael D Sorkin
@ 2017-05-22 22:03 ` Rafael D Sorkin
  2017-05-22 23:15   ` npostavs
  2017-05-24  4:52 ` Rafael D Sorkin
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 42+ messages in thread
From: Rafael D Sorkin @ 2017-05-22 22:03 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin

Thanks, I was wondering about that myself.  Is there a standard
for elisp (or common lisp) that would determine whether eager
macro expansion is an error in this case?

I would expect that a `defun' or `defsetf' etc which is within a
conditional would not be executed until it was known whether the
condition was satisfied.  The opposite behavior seems
counter-intuitive to me.

But if you decide that this behavior is not a bug, then please
let me know, so that I can adapt to it in the future.

 > tags 27016 - unreproducible
 > found 27016 24.4
 > found 27016 25.2
 > quit
 > 
 > Rafael D Sorkin <rsorkin@perimeterinstitute.ca> writes:
 > 
 > > Following your suggestion I tried starting with "emacs -Q" and
 > > got the same results as you did.  However if I (require 'cl)
 > > then the bug returns.  (I normally require CL automatically on
 > > starting emacs.)  So perhaps it's an incompatibility between CL
 > > and the new way that defsetf is implemented.
 > 
 > Oh, right, I see it now.  It happens in 24.4 and later.  I'm not sure
 > it's a bug though.  My guess is that the difference is eager
 > macroexpansion.  When I compile, then I get the same behaviour with 24.3
 > (that's my earliest working Emacs build) as well.
 > 
 >     $ emacs -Q -batch -l cl -f batch-byte-compile bug-27016-defsetf.el 
 > 
 >     In toplevel form:
 >     bug-27016-defsetf.el:1:1:Warning: cl package required at runtime
 >     bug-27016-defsetf.el:3:1:Warning: global/dynamic var `pair' lacks a prefix
 >     Wrote /home/npostavs/src/emacs/bug-27016-defsetf.elc
 >     $ emacs -Q -batch -l bug-27016-defsetf.elc
 >     pair: (0 . 4)
 > 
 > where bug-27016-defsetf.el has contents:
 > 
 >     (require 'cl)
 > 
 >     (defvar pair nil)
 >     (setq pair (cons 3 4))                  ; (3 . 4)
 >     (unless t
 >       (defalias 'foobar 'cons)
 >       (defsetf foobar setcar))              ; nil
 >     (setf (foobar pair) 0)                  ; 0       !
 > 
 >     (message "pair: %S" pair)

~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 Rafael Sorkin
 Perimeter Institute for Theoretical Physics
 31 Caroline Street North
 Waterloo, ON  N2L 2Y5
 Canada
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22 21:18   ` npostavs
@ 2017-05-22 23:10     ` Michael Heerdegen
  2017-05-22 23:23       ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Heerdegen @ 2017-05-22 23:10 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin

npostavs@users.sourceforge.net writes:

> Oh, right, I see it now.  It happens in 24.4 and later.  I'm not sure
> it's a bug though.  My guess is that the difference is eager
> macroexpansion.  When I compile, then I get the same behaviour with 24.3
> (that's my earliest working Emacs build) as well.

(require 'cl)

(macroexpand-1 (macroexpand-1 (macroexpand-1 '(defsetf foobar setcar))))
==>

#+begin_src emacs-lisp
(gv-define-expander foobar
  (lambda
    (do &rest args)
    (gv--defsetter 'foobar
                   (lambda
                     (val &rest args)
                     `(,'setcar ,@args ,val))
                   do args)))
#+end_src

A comment in the definition of `gv-define-expander' says:

  ;; Use eval-and-compile so the method can be used in the same file as it
  ;; is defined.
  ;; FIXME: Just like byte-compile-macro-environment, we should have something
  ;; like byte-compile-symbolprop-environment so as to handle these things
  ;; cleanly without affecting the running Emacs.

Anyway, the above expands to

(macroexpand-1 (macroexpand-1 (macroexpand-1 (macroexpand-1 '(defsetf foobar setcar)))))
==>

#+begin_src emacs-lisp
(eval-and-compile
  (put 'foobar 'gv-expander
       (lambda
         (do &rest args)
         (gv--defsetter 'foobar
                        (lambda
                          (val &rest args)
                          `(,'setcar ,@args ,val))
                        do args))))
#+end_src

The `put' is evaluated when the `defsetf' macro call is expanded.
That's what's causing the issue.

AFAIK we don't say that `defsetf' is only allowed at top level, so I
would say (without any judgement) that it's a bug.  And it's not limited
to `defsetf' in "cl".


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22 22:03 ` Rafael D Sorkin
@ 2017-05-22 23:15   ` npostavs
  0 siblings, 0 replies; 42+ messages in thread
From: npostavs @ 2017-05-22 23:15 UTC (permalink / raw)
  To: Rafael D Sorkin; +Cc: 27016

Rafael D Sorkin <rsorkin@perimeterinstitute.ca> writes:

> Thanks, I was wondering about that myself.  Is there a standard
> for elisp (or common lisp) that would determine whether eager
> macro expansion is an error in this case?

CLTL says this[1]:

    The evaluator is typically implemented as an interpreter that traverses
    the given form recursively, performing each step of the computation as
    it goes. An interpretive implementation is not required, however. A
    permissible alternative approach is for the evaluator first to
    completely compile the form into machine-executable code and then invoke
    the resulting code. This technique virtually eliminates
    incompatibilities between interpreted and compiled code but also renders
    the evalhook mechanism relatively useless. Various mixed strategies are
    also possible. All of these approaches should produce the same results
    when executing a correct program but may produce different results for
    incorrect programs. For example, the approaches may differ as to when
    macro calls are expanded; macro definitions should not depend on the
    time at which they are expanded. Implementors should document the
    evaluation strategy for each implementation.

and this[2] specifically about defsetf:

    X3J13 voted in March 1989 (DEFINING-MACROS-NON-TOP-LEVEL) to clarify
    that, while defining forms normally appear at top level, it is
    meaningful to place them in non-top-level contexts; the complex form of
    defsetf must define the expander function within the enclosing lexical
    environment, not within the global environment.

I'm not sure whether (unless ...) counts as an "enclosing lexical
environment" though.

> I would expect that a `defun' or `defsetf' etc which is within a
> conditional would not be executed until it was known whether the
> condition was satisfied.  The opposite behavior seems
> counter-intuitive to me.

`defun' takes effect at runtime (or rather it expands to `defalias'
which operates at runtime), whereas `defsetf' has to affect subsequent
compilation, so waiting until runtime to decide whether the condition is
true could not really work.

> But if you decide that this behavior is not a bug, then please
> let me know, so that I can adapt to it in the future.

I *think* it's not a bug, or at least not one worth fixing.  If you wrap
your (unless ...) form in (eval-when-compile ...) then you get your
expected behaviour.

[1]: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node179.html
[2]: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node80.html





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22 23:10     ` Michael Heerdegen
@ 2017-05-22 23:23       ` npostavs
  2017-05-23  0:45         ` Michael Heerdegen
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-05-22 23:23 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Rafael D Sorkin

Michael Heerdegen <michael_heerdegen@web.de> writes:

> A comment in the definition of `gv-define-expander' says:
>
>   ;; Use eval-and-compile so the method can be used in the same file as it
>   ;; is defined.
>   ;; FIXME: Just like byte-compile-macro-environment, we should have something
>   ;; like byte-compile-symbolprop-environment so as to handle these things
>   ;; cleanly without affecting the running Emacs.

I think fixing that would not fix this bug, because the (setf (foobar
pair) 0) would still be compiled according to
byte-compile-symbolprop-environment.  It would just mean that compiling
the file containing (defsetf foobar setcar) would not affect other files
in the compiler's session.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22 23:23       ` npostavs
@ 2017-05-23  0:45         ` Michael Heerdegen
  2017-05-23  0:51           ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Heerdegen @ 2017-05-23  0:45 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin

npostavs@users.sourceforge.net writes:

> I think fixing that would not fix this bug, because the (setf (foobar
> pair) 0) would still be compiled according to
> byte-compile-symbolprop-environment.  It would just mean that compiling
> the file containing (defsetf foobar setcar) would not affect other files
> in the compiler's session.

Yes, there is probably no reasonable backward-compatible fix at all.


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-23  0:45         ` Michael Heerdegen
@ 2017-05-23  0:51           ` npostavs
  2017-05-23  1:18             ` Michael Heerdegen
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-05-23  0:51 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Rafael D Sorkin

Michael Heerdegen <michael_heerdegen@web.de> writes:
>
> Yes, there is probably no reasonable backward-compatible fix at all.

Apologies if I'm misreading you, but do you have a non
backwards-compatible fix in mind?  Because I don't see one of those
either.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-23  0:51           ` npostavs
@ 2017-05-23  1:18             ` Michael Heerdegen
  0 siblings, 0 replies; 42+ messages in thread
From: Michael Heerdegen @ 2017-05-23  1:18 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin

npostavs@users.sourceforge.net writes:

> Apologies if I'm misreading you, but do you have a non
> backwards-compatible fix in mind?  Because I don't see one of those
> either.

I wondered whether we could handle top-level setter definitions
specially (i.e. like now) and give up the magic for the rest.  But
that's probably a too drastic change, and I'm not sure if it would be a
good change either.


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
                   ` (2 preceding siblings ...)
  2017-05-22 22:03 ` Rafael D Sorkin
@ 2017-05-24  4:52 ` Rafael D Sorkin
  2017-05-24 22:51   ` Michael Heerdegen
  2017-05-25  4:59 ` Rafael D Sorkin
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 42+ messages in thread
From: Rafael D Sorkin @ 2017-05-24  4:52 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin


 > `defun' takes effect at runtime (or rather it expands to
 > `defalias' which operates at runtime), whereas `defsetf' has
 > to affect subsequent compilation, so waiting until runtime to
 > decide whether the condition is true could not really work.

Well the way I was using it, everything used to work fine.  I
found the bug when it stopped working and I was unable to figure
out why.

I had a defsetf inside a conditional in a file that was to be
loaded and/or compiled and then loaded.  (Compilation isn't
really the issue.)  Before loading that file I set a "switch"
which the conditional referred to.  That way a defsetf done
before loading the file could be either overridden or not, as
desired.

I found the ability to control the defsetf this way to be
useful.  However, as I wrote before, I only used this device a
few times, not so many that I couldn't adapt to losing it.

~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 Rafael Sorkin
 Perimeter Institute for Theoretical Physics
 31 Caroline Street North
 Waterloo, ON  N2L 2Y5
 Canada
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-24  4:52 ` Rafael D Sorkin
@ 2017-05-24 22:51   ` Michael Heerdegen
  2017-05-25  1:50     ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Heerdegen @ 2017-05-24 22:51 UTC (permalink / raw)
  To: Rafael D Sorkin; +Cc: 27016, npostavs

Rafael D Sorkin <rsorkin@perimeterinstitute.ca> writes:

> I had a defsetf inside a conditional in a file that was to be
> loaded and/or compiled and then loaded.  (Compilation isn't
> really the issue.)  Before loading that file I set a "switch"
> which the conditional referred to.  That way a defsetf done
> before loading the file could be either overridden or not, as
> desired.

Can't you just `defsetf' unconditionally to a named function, and change
that function's definition when appropriate (in a conditional)?


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-24 22:51   ` Michael Heerdegen
@ 2017-05-25  1:50     ` npostavs
  0 siblings, 0 replies; 42+ messages in thread
From: npostavs @ 2017-05-25  1:50 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Rafael D Sorkin

tags 27016 wontfix
close 27016
quit

> Can't you just `defsetf' unconditionally to a named function, and change
> that function's definition when appropriate (in a conditional)?

Or just

    (eval-and-compile
      (unless t
        (defsetf foobar setcar)))

Anyway, I don't see any likely solutions to make this work exactly as
before, so I'm going to close this as wontfix, but feel free to continue
discussing (and/or say that I'm wrong).





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
                   ` (3 preceding siblings ...)
  2017-05-24  4:52 ` Rafael D Sorkin
@ 2017-05-25  4:59 ` Rafael D Sorkin
  2017-05-25  5:01 ` Rafael D Sorkin
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 42+ messages in thread
From: Rafael D Sorkin @ 2017-05-25  4:59 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Rafael D Sorkin, npostavs

 > > I had a defsetf inside a conditional in a file that was to be
 > > loaded and/or compiled and then loaded.  (Compilation isn't
 > > really the issue.)  Before loading that file I set a "switch"
 > > which the conditional referred to.  That way a defsetf done
 > > before loading the file could be either overridden or not, as
 > > desired.
 > 
 > Can't you just `defsetf' unconditionally to a named function,
 > and change that function's definition when appropriate (in a
 > conditional)?
 > 
 > 
 > Michael.

Thanks for the suggestion, Michael.  I think it would work, but
the function I'm aliasing to is `symbol-value', and I would feel
slightly uncomfortable to insert an intermediate function which
would have to either call `symbol-value' or be redefined to be
it.  Fortunately, I hadn't used defsetf inside a conditional
more than a couple of times, and for those it was easy to devise
adequate workarounds (once I understood what the problem was).

For the future, I have resolved to use `defsetf' only at top
level.

- Rafael

~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 Rafael Sorkin
 Perimeter Institute for Theoretical Physics
 31 Caroline Street North
 Waterloo, ON  N2L 2Y5
 Canada
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
                   ` (4 preceding siblings ...)
  2017-05-25  4:59 ` Rafael D Sorkin
@ 2017-05-25  5:01 ` Rafael D Sorkin
  2017-05-25 10:38   ` npostavs
  2017-05-26  3:50 ` Stefan Monnier
  2017-05-26  5:05 ` Rafael D Sorkin
  7 siblings, 1 reply; 42+ messages in thread
From: Rafael D Sorkin @ 2017-05-25  5:01 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

 > tags 27016 wontfix
 > close 27016
 > quit
 > 
 > > Can't you just `defsetf' unconditionally to a named
 > > function, and change that function's definition when
 > > appropriate (in a conditional)?
 > 
 > Or just
 > 
 >     (eval-and-compile
 >       (unless t
 >         (defsetf foobar setcar)))
 > 
 > Anyway, I don't see any likely solutions to make this work
 > exactly as before, so I'm going to close this as wontfix, but
 > feel free to continue discussing (and/or say that I'm wrong).

One problem is that, as far as I know, common lisp doesn't have
`eval-and-compile', and my code is meant to work with both elisp
and common lisp.  In any case, as I wrote to Michael, I plan now
to use defsetf only at top level.  So thanks for the suggestion,
and do feel free to keep this bug closed as "wontfix".

- Rafael
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 Rafael Sorkin
 Perimeter Institute for Theoretical Physics
 31 Caroline Street North
 Waterloo, ON  N2L 2Y5
 Canada
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-






^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-25  5:01 ` Rafael D Sorkin
@ 2017-05-25 10:38   ` npostavs
  2017-05-25 20:26     ` Michael Heerdegen
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-05-25 10:38 UTC (permalink / raw)
  To: Rafael D Sorkin; +Cc: Michael Heerdegen, 27016

Rafael D Sorkin <rsorkin@perimeterinstitute.ca> writes:

>  >     (eval-and-compile
>  >       (unless t
>  >         (defsetf foobar setcar)))
>  > 
> One problem is that, as far as I know, common lisp doesn't have
> `eval-and-compile', and my code is meant to work with both elisp
> and common lisp.

Oh, I think `eval-when' should be equivalent:

    (eval-when (compile load eval)
      (unless t
        (defsetf foobar setcar)))





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-25 10:38   ` npostavs
@ 2017-05-25 20:26     ` Michael Heerdegen
  2017-05-25 20:42       ` Noam Postavsky
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Heerdegen @ 2017-05-25 20:26 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin

npostavs@users.sourceforge.net writes:

> Oh, I think `eval-when' should be equivalent:
>
>     (eval-when (compile load eval)
>       (unless t
>         (defsetf foobar setcar)))

FWIW, I don't understand.  Doesn't that just expand to the same code as
before when evaluated?  That code is just evaluated under even more
circumstances.

I would rather try something like

#+begin_src emacs-lisp
(unless t
  (eval '(progn (defalias 'foobar 'cons)
                (defsetf foobar setcar))))
#+end_src

to avoid the eager macro expansion unless the code is actually run.


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-25 20:26     ` Michael Heerdegen
@ 2017-05-25 20:42       ` Noam Postavsky
  2017-05-25 21:31         ` Michael Heerdegen
  0 siblings, 1 reply; 42+ messages in thread
From: Noam Postavsky @ 2017-05-25 20:42 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Rafael D Sorkin

On Thu, May 25, 2017 at 4:26 PM, Michael Heerdegen
<michael_heerdegen@web.de> wrote:
> npostavs@users.sourceforge.net writes:
>
>> Oh, I think `eval-when' should be equivalent:
>>
>>     (eval-when (compile load eval)
>>       (unless t
>>         (defsetf foobar setcar)))
>
> FWIW, I don't understand.  Doesn't that just expand to the same code as
> before when evaluated?  That code is just evaluated under even more
> circumstances.

Hmm, I thought it would cause the 'unless t' to happen in the
macroexpansion phase as well, but I was wrong. Apparently 'eval-when'
doesn't have this effect, only eval-when-compile or eval-and-compile
will do the trick.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-25 20:42       ` Noam Postavsky
@ 2017-05-25 21:31         ` Michael Heerdegen
  2017-05-25 23:03           ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Heerdegen @ 2017-05-25 21:31 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 27016, Rafael D Sorkin

Noam Postavsky <npostavs@users.sourceforge.net> writes:

> Hmm, I thought it would cause the 'unless t' to happen in the
> macroexpansion phase as well, but I was wrong. Apparently 'eval-when'
> doesn't have this effect, only eval-when-compile or eval-and-compile
> will do the trick.

That also doesn't work.  Apart from the fact that you would have the
`defsetf' executed at compile time as side effect,

#+begin_src emacs-lisp
(macroexpand '(defsetf foo bar))
==>
'(lambda
   (do &rest args)
   (gv--defsetter 'foo
                  (lambda
                    (val &rest args)
                    `(,'bar ,@args ,val))
                  do args))
#+end_src

(i.e. a constant!).

When you compile a file with this content:

#+begin_src emacs-lisp
(eval-and-compile
  (unless nil
    (defsetf foo bar)))
#+end_src

you get an empty .elc.

Isn't that strange?


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-25 21:31         ` Michael Heerdegen
@ 2017-05-25 23:03           ` npostavs
  2017-05-25 23:40             ` Michael Heerdegen
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-05-25 23:03 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Rafael D Sorkin

Michael Heerdegen <michael_heerdegen@web.de> writes:

> Noam Postavsky <npostavs@users.sourceforge.net> writes:
>
>> Hmm, I thought it would cause the 'unless t' to happen in the
>> macroexpansion phase as well, but I was wrong. Apparently 'eval-when'
>> doesn't have this effect, only eval-when-compile or eval-and-compile
>> will do the trick.
>
> That also doesn't work.

Oh, hmm, I only checked by evaluating, I didn't actually try compiling
to a separate file.

> #+begin_src emacs-lisp
> (macroexpand '(defsetf foo bar))
> ==>
> '(lambda
>    (do &rest args)
>    (gv--defsetter 'foo
>                   (lambda
>                     (val &rest args)
>                     `(,'bar ,@args ,val))
>                   do args))
> #+end_src

I don't understand where that quote comes from.  I guess I don't really
understand what's going on here as well as I thought.

> When you compile a file with this content:
>
> #+begin_src emacs-lisp
> (eval-and-compile
>   (unless nil
>     (defsetf foo bar)))
> #+end_src
>
> you get an empty .elc.
>
> Isn't that strange?

Yeah, even stranger...






^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-25 23:03           ` npostavs
@ 2017-05-25 23:40             ` Michael Heerdegen
  0 siblings, 0 replies; 42+ messages in thread
From: Michael Heerdegen @ 2017-05-25 23:40 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin, Stefan Monnier

Hello,

I wonder now if the definition of `eval-and-compile' as defmacro is
correct.  Maybe Stefan can help (I CC'd him), he may also want to look
at the rest of the report...

npostavs@users.sourceforge.net writes:

> > #+begin_src emacs-lisp
> > (macroexpand '(defsetf foo bar))
> > ==>
> > '(lambda
> >    (do &rest args)
> >    (gv--defsetter 'foo
> >                   (lambda
> >                     (val &rest args)
> >                     `(,'bar ,@args ,val))
> >                   do args))
> > #+end_src
>
> I don't understand where that quote comes from.

The `defsetf' expands to an `eval-and-compile'.  The `eval-and-compile'
expands to a quoted constant, see its definition (as defmacro).


> > When you compile a file with this content:
> >
> > #+begin_src emacs-lisp
> > (eval-and-compile
> >   (unless nil
> >     (defsetf foo bar)))
> > #+end_src
> >
> > you get an empty .elc.
> >
> > Isn't that strange?
>
> Yeah, even stranger...

AFAIU, when compiled, `eval-and-compile' macroexpands its body (see the
defconst of `byte-compile-initial-macro-environment').  So what is
compiled is essentially

#+begin_src emacs-lisp
(if nil nil
  '(closure
    (t)
    (do &rest args)
    (gv--defsetter 'foo
                   (lambda
                     (val &rest args)
                     `(,'bar ,@args ,val))
                   do args)))
#+end_src

and that's just discarded.


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
                   ` (5 preceding siblings ...)
  2017-05-25  5:01 ` Rafael D Sorkin
@ 2017-05-26  3:50 ` Stefan Monnier
  2017-05-26 22:51   ` npostavs
  2017-05-26  5:05 ` Rafael D Sorkin
  7 siblings, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-05-26  3:50 UTC (permalink / raw)
  To: Rafael D Sorkin; +Cc: 27016

> (unless t
>   (defalias 'foobar 'cons)
>   (defsetf foobar setcar))		; nil 
> (foobar pair)				; same as above
> (setf (foobar pair) 0)			; 0       !

I can confirm that it's a bug.  It's perfectly correct for the defsetf
to be macroexpanded, but not to be evaluated.
Not sure how best to get that behavior.  The naive/straightforward way
might be to introduce some sort of eval-and-compile-when-at-toplevel,
but there's probably a better way.  The first thing to do is to look at
how it was done in Emacs-23.


        Stefan





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
                   ` (6 preceding siblings ...)
  2017-05-26  3:50 ` Stefan Monnier
@ 2017-05-26  5:05 ` Rafael D Sorkin
  7 siblings, 0 replies; 42+ messages in thread
From: Rafael D Sorkin @ 2017-05-26  5:05 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Rafael D Sorkin, npostavs

 > I would rather try something like
 > 
 > #+begin_src emacs-lisp
 > (unless t
 >   (eval '(progn (defalias 'foobar 'cons)
 >                 (defsetf foobar setcar))))
 > #+end_src
 > 
 > to avoid the eager macro expansion unless the code is actually run.

That looks like it would have to work.  I will keep it mind in
case of future need.  Thanks.

~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 Rafael Sorkin
 Perimeter Institute for Theoretical Physics
 31 Caroline Street North
 Waterloo, ON  N2L 2Y5
 Canada
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-26  3:50 ` Stefan Monnier
@ 2017-05-26 22:51   ` npostavs
  2017-05-28 20:45     ` Stefan Monnier
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-05-26 22:51 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 27016, Rafael D Sorkin

reopen 27016
tag 27016 - wontfix
quit

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> (unless t
>>   (defalias 'foobar 'cons)
>>   (defsetf foobar setcar))		; nil 
>> (foobar pair)				; same as above
>> (setf (foobar pair) 0)			; 0       !
>
> I can confirm that it's a bug.  It's perfectly correct for the defsetf
> to be macroexpanded, but not to be evaluated.
> Not sure how best to get that behavior.  The naive/straightforward way
> might be to introduce some sort of eval-and-compile-when-at-toplevel,
> but there's probably a better way.  The first thing to do is to look at
> how it was done in Emacs-23.

Is the difference in Emacs-23 not just eager macroexpansion?

Both the Emacs-23 and the current code seem to expand to (put 'foobar
...).





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-26 22:51   ` npostavs
@ 2017-05-28 20:45     ` Stefan Monnier
  2017-07-02 20:47       ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-05-28 20:45 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Rafael D Sorkin

> Is the difference in Emacs-23 not just eager macroexpansion?

Could be.  But I'm more worried about the byte-compiled case.

> Both the Emacs-23 and the current code seem to expand to (put 'foobar
> ...).

Beware: there's macro-expansion and then there's macro-expansion.
[ See byte-compile-macro-environment.  ]


        Stefan





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-05-28 20:45     ` Stefan Monnier
@ 2017-07-02 20:47       ` npostavs
  2017-07-03 11:25         ` Michael Heerdegen
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-07-02 20:47 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 27016, Rafael D Sorkin

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Is the difference in Emacs-23 not just eager macroexpansion?
>
> Could be.  But I'm more worried about the byte-compiled case.

I hope someone will correct me if I've gotten mixed up again, but I
believe the byte-compiled case already works fine:

    ~/src/emacs$ cat bug-27016-defsetf.el
    (require 'cl)

    (defvar pair nil)
    (setq pair (cons 3 4))
    (when nil
      (defalias 'foobar 'cons)
      (defsetf foobar setcar))
    ~/src/emacs$ emacs -Q -batch -f batch-byte-compile bug-27016-defsetf.el

    In toplevel form:
    bug-27016-defsetf.el:1:1:Warning: cl package required at runtime
    bug-27016-defsetf.el:3:1:Warning: global/dynamic var ‘pair’ lacks a prefix
    ~/src/emacs$ emacs -Q -batch -l bug-27016-defsetf.elc --eval '(setf (foobar pair) 0)'
    Symbol’s function definition is void: \(setf\ foobar\)






^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-02 20:47       ` npostavs
@ 2017-07-03 11:25         ` Michael Heerdegen
  2017-07-09 20:13           ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Heerdegen @ 2017-07-03 11:25 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Stefan Monnier, Rafael D Sorkin

npostavs@users.sourceforge.net writes:

> I hope someone will correct me if I've gotten mixed up again, but I
> believe the byte-compiled case already works fine:
>
>     ~/src/emacs$ cat bug-27016-defsetf.el
>     (require 'cl)
>
>     (defvar pair nil)
>     (setq pair (cons 3 4))
>     (when nil
>       (defalias 'foobar 'cons)
>       (defsetf foobar setcar))
>     ~/src/emacs$ emacs -Q -batch -f batch-byte-compile bug-27016-defsetf.el
>
>     In toplevel form:
>     bug-27016-defsetf.el:1:1:Warning: cl package required at runtime
>     bug-27016-defsetf.el:3:1:Warning: global/dynamic var ‘pair’ lacks a prefix
>     ~/src/emacs$ emacs -Q -batch -l bug-27016-defsetf.elc --eval '(setf (foobar pair) 0)'
>     Symbol’s function definition is void: \(setf\ foobar\)

Yes - if you use two separate Emacs instances.  The defsetf gets
evaluated in the Emacs that is used to compile the code
(unconditionally).

So what you state is not suspicious for a problem with a surprising side
effect when performing macroexpansion, right?


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-03 11:25         ` Michael Heerdegen
@ 2017-07-09 20:13           ` npostavs
  2017-07-10  0:26             ` Michael Heerdegen
  2017-07-11 16:21             ` Stefan Monnier
  0 siblings, 2 replies; 42+ messages in thread
From: npostavs @ 2017-07-09 20:13 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Stefan Monnier, Rafael D Sorkin

[-- Attachment #1: Type: text/plain, Size: 1702 bytes --]

tags 27016 + patch
quit

Michael Heerdegen <michael_heerdegen@web.de> writes:

> npostavs@users.sourceforge.net writes:
>
>> I hope someone will correct me if I've gotten mixed up again, but I
>> believe the byte-compiled case already works fine:
>>
>>     ~/src/emacs$ cat bug-27016-defsetf.el
>>     (require 'cl)
>>
>>     (defvar pair nil)
>>     (setq pair (cons 3 4))
>>     (when nil
>>       (defalias 'foobar 'cons)
>>       (defsetf foobar setcar))
>>     ~/src/emacs$ emacs -Q -batch -f batch-byte-compile bug-27016-defsetf.el
>>
>>     In toplevel form:
>>     bug-27016-defsetf.el:1:1:Warning: cl package required at runtime
>>     bug-27016-defsetf.el:3:1:Warning: global/dynamic var ‘pair’ lacks a prefix
>>     ~/src/emacs$ emacs -Q -batch -l bug-27016-defsetf.elc --eval '(setf (foobar pair) 0)'
>>     Symbol’s function definition is void: \(setf\ foobar\)
>
> Yes - if you use two separate Emacs instances.  The defsetf gets
> evaluated in the Emacs that is used to compile the code
> (unconditionally).
>
> So what you state is not suspicious for a problem with a surprising side
> effect when performing macroexpansion, right?

Right.

    ~/src/emacs$ emacs -Q -batch --eval '(byte-compile-file "bug-27016-defsetf.el")' -l bug-27016-defsetf.elc --eval  '(progn (setf (foobar pair) 0) (print pair))'

    In toplevel form:
    bug-27016-defsetf.el:1:1:Warning: cl package required at runtime
    bug-27016-defsetf.el:3:1:Warning: global/dynamic var ‘pair’ lacks a prefix

    (0 . 4)

You were indeed correct to point to that FIXME comment in
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27016#28

Here's a patch for it:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 2591 bytes --]

From 1c6585f06ce87b62c505a575661554b6d6b961c8 Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Sun, 9 Jul 2017 15:56:50 -0400
Subject: [PATCH] Don't define gv expanders in compiler session (Bug#27016)

This prevents definitions being compiled from leaking into the current
Emacs doing the compilation.
* lisp/emacs-lisp/gv.el (gv-define-expander): Push the expander
definition into `byte-compile-macro-environment' instead of evaluating
at compile time.
(gv-get): Check `byte-compile-macro-environment' for gv-expander
definitions.
---
 lisp/emacs-lisp/gv.el | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index c5c12a6414..b916dda731 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -91,7 +91,10 @@ (defun gv-get (place do)
    ((not (consp place)) (signal 'gv-invalid-place (list place)))
    (t
     (let* ((head (car place))
-           (gf (function-get head 'gv-expander 'autoload)))
+           (gf (or (alist-get head (alist-get :gv-expands
+                                              (bound-and-true-p
+                                               byte-compile-macro-environment)))
+                   (function-get head 'gv-expander 'autoload))))
       (if gf (apply gf do (cdr place))
         (let ((me (macroexpand-1 place
                                  ;; (append macroexpand-all-environment
@@ -146,12 +149,15 @@ (defmacro gv-define-expander (name handler)
 HANDLER is a function which takes an argument DO followed by the same
 arguments as NAME.  DO is a function as defined in `gv-get'."
   (declare (indent 1) (debug (sexp form)))
-  ;; Use eval-and-compile so the method can be used in the same file as it
-  ;; is defined.
-  ;; FIXME: Just like byte-compile-macro-environment, we should have something
-  ;; like byte-compile-symbolprop-environment so as to handle these things
-  ;; cleanly without affecting the running Emacs.
-  `(eval-and-compile (put ',name 'gv-expander ,handler)))
+  ;; Push onto `byte-compile-macro-environment' so the method can be
+  ;; used in the same file as it is defined.
+  (when (boundp 'byte-compile-macro-environment)
+    (push (cons :gv-expanders
+                (cons (cons name handler)
+                      (cdr (assq :gv-expanders
+                                 byte-compile-macro-environment))))
+          byte-compile-macro-environment))
+  `(put ',name 'gv-expander ,handler))
 
 ;;;###autoload
 (defun gv--defun-declaration (symbol name args handler &optional fix)
-- 
2.11.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-09 20:13           ` npostavs
@ 2017-07-10  0:26             ` Michael Heerdegen
  2017-07-11  1:45               ` npostavs
  2017-07-11 16:21             ` Stefan Monnier
  1 sibling, 1 reply; 42+ messages in thread
From: Michael Heerdegen @ 2017-07-10  0:26 UTC (permalink / raw)
  To: npostavs; +Cc: 27016, Stefan Monnier, Rafael D Sorkin

npostavs@users.sourceforge.net writes:

> Here's a patch for it: [...]

Thanks for working on this.  AFAIU I think it should work.

> @@ -146,12 +149,15 @@ (defmacro gv-define-expander (name handler)
>  HANDLER is a function which takes an argument DO followed by the same
>  arguments as NAME.  DO is a function as defined in `gv-get'."
>    (declare (indent 1) (debug (sexp form)))
> -  ;; Use eval-and-compile so the method can be used in the same file as it
> -  ;; is defined.
> -  ;; FIXME: Just like byte-compile-macro-environment, we should have something
> -  ;; like byte-compile-symbolprop-environment so as to handle these things
> -  ;; cleanly without affecting the running Emacs.
> -  `(eval-and-compile (put ',name 'gv-expander ,handler)))
> +  ;; Push onto `byte-compile-macro-environment' so the method can be
> +  ;; used in the same file as it is defined.
> +  (when (boundp 'byte-compile-macro-environment)
> +    (push (cons :gv-expanders
> +                (cons (cons name handler)
> +                      (cdr (assq :gv-expanders
> +                                 byte-compile-macro-environment))))
> +          byte-compile-macro-environment))
> +  `(put ',name 'gv-expander ,handler))

Is it intended to add an :gv-expanders entry to
byte-compile-macro-environment more than once?


Michael.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-10  0:26             ` Michael Heerdegen
@ 2017-07-11  1:45               ` npostavs
  0 siblings, 0 replies; 42+ messages in thread
From: npostavs @ 2017-07-11  1:45 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: 27016, Stefan Monnier, Rafael D Sorkin

[-- Attachment #1: Type: text/plain, Size: 556 bytes --]

Michael Heerdegen <michael_heerdegen@web.de> writes:

> Is it intended to add an :gv-expanders entry to
> byte-compile-macro-environment more than once?

Hmm, not entirely consciously, I was following the same pattern I had
used for cl-symbol-macrolet, but in that case we're establishing a
let-binding so it's important to be able to pop back to the old binding.
It's not needed here though.

Also, I had a typo in gv-get (:gv-expands instead of :gv-expanders),
because I didn't actually test the positive case.  Here's a working(?)
version, with tests:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 7685 bytes --]

From b48af25eb5c18cb45d9e431076df767718efa0ec Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Mon, 10 Jul 2017 21:42:05 -0400
Subject: [PATCH v2] Don't define gv expanders in compiler session (Bug#27016)

This prevents definitions being compiled from leaking into the current
Emacs doing the compilation.
* lisp/emacs-lisp/gv.el (gv-define-expander): Push the expander
definition into `byte-compile-macro-environment' instead of evaluating
at compile time.
(gv-get): Check `byte-compile-macro-environment' for gv-expander
definitions.
* test/lisp/emacs-lisp/gv-tests.el: New tests.
---
 lisp/emacs-lisp/gv.el            |  23 ++++++---
 test/lisp/emacs-lisp/gv-tests.el | 103 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+), 7 deletions(-)
 create mode 100644 test/lisp/emacs-lisp/gv-tests.el

diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index c5c12a6414..fa8ae27e1f 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -91,7 +91,10 @@ (defun gv-get (place do)
    ((not (consp place)) (signal 'gv-invalid-place (list place)))
    (t
     (let* ((head (car place))
-           (gf (function-get head 'gv-expander 'autoload)))
+           (gf (or (alist-get head (alist-get :gv-expanders
+                                              (bound-and-true-p
+                                               byte-compile-macro-environment)))
+                   (function-get head 'gv-expander 'autoload))))
       (if gf (apply gf do (cdr place))
         (let ((me (macroexpand-1 place
                                  ;; (append macroexpand-all-environment
@@ -146,12 +149,18 @@ (defmacro gv-define-expander (name handler)
 HANDLER is a function which takes an argument DO followed by the same
 arguments as NAME.  DO is a function as defined in `gv-get'."
   (declare (indent 1) (debug (sexp form)))
-  ;; Use eval-and-compile so the method can be used in the same file as it
-  ;; is defined.
-  ;; FIXME: Just like byte-compile-macro-environment, we should have something
-  ;; like byte-compile-symbolprop-environment so as to handle these things
-  ;; cleanly without affecting the running Emacs.
-  `(eval-and-compile (put ',name 'gv-expander ,handler)))
+  ;; Push onto `byte-compile-macro-environment' so the method can be
+  ;; used in the same file as it is defined.
+  (when (boundp 'byte-compile-macro-environment)
+    (let* ((expanders (assq :gv-expanders byte-compile-macro-environment))
+           (expander (assq name (cdr expanders)))
+           (new-expander (cons name handler)))
+      (cond (expander (setcdr expander handler))
+            (expanders (setcdr expanders (cons new-expander (cdr expanders))))
+            (t (setq byte-compile-macro-environment
+                     (cons (cons :gv-expanders (list new-expander))
+                           byte-compile-macro-environment))))))
+  `(put ',name 'gv-expander ,handler))
 
 ;;;###autoload
 (defun gv--defun-declaration (symbol name args handler &optional fix)
diff --git a/test/lisp/emacs-lisp/gv-tests.el b/test/lisp/emacs-lisp/gv-tests.el
new file mode 100644
index 0000000000..affc7ce455
--- /dev/null
+++ b/test/lisp/emacs-lisp/gv-tests.el
@@ -0,0 +1,103 @@
+;;; gv-tests.el --- tests for gv.el  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2017 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(eval-when-compile (require 'cl-lib))
+
+(cl-defmacro gv-tests--in-temp-dir ((elvar elcvar)
+                                    (&rest filebody)
+                                    &rest body)
+  (declare (indent 2))
+  `(let ((default-directory (make-temp-file "gv-test" t)))
+     (unwind-protect
+         (let ((,elvar "gv-test-deffoo.el")
+               (,elcvar "gv-test-deffoo.elc"))
+           (with-temp-file ,elvar
+             (insert ";; -*- lexical-binding: t; -*-\n")
+             (dolist (form ',filebody)
+               (pp form (current-buffer))))
+           ,@body)
+       (delete-directory default-directory t))))
+
+(ert-deftest gv-define-expander-in-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((gv-define-setter gv-test-foo (newval cons)
+         `(setcar ,cons ,newval))
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (message "%d" (car gv-test-pair)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string) "99\n")))))
+
+(ert-deftest gv-dont-define-expander-in-file ()
+  ;; The expander is defined while we are compiling the file, even
+  ;; though it's inside (when nil ...).
+  :expected-result :failed
+  (gv-tests--in-temp-dir (el elc)
+      ((when nil (gv-define-setter gv-test-foo (newval cons)
+                   `(setcar ,cons ,newval)))
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (message "%d" (car gv-test-pair)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string)
+                     "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
+
+(ert-deftest gv-define-expander-out-of-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((gv-define-setter gv-test-foo (newval cons)
+         `(setcar ,cons ,newval))
+       (defvar gv-test-pair (cons 1 2)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc
+                    "--eval"
+                    (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99)
+                                             (message "%d" (car gv-test-pair)))))
+      (should (equal (buffer-string) "99\n")))))
+
+(ert-deftest gv-dont-define-expander-other-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((if nil (gv-define-setter gv-test-foo (newval cons)
+                 `(setcar ,cons ,newval)))
+       (defvar gv-test-pair (cons 1 2)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc
+                    "--eval"
+                    (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99)
+                                             (message "%d" (car gv-test-pair)))))
+      (should (equal (buffer-string)
+                     "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
+
+;;; gv-tests.el ends here
-- 
2.11.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-09 20:13           ` npostavs
  2017-07-10  0:26             ` Michael Heerdegen
@ 2017-07-11 16:21             ` Stefan Monnier
  2017-07-12  0:55               ` npostavs
  1 sibling, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-07-11 16:21 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

> -           (gf (function-get head 'gv-expander 'autoload)))
> +           (gf (or (alist-get head (alist-get :gv-expands
> +                                              (bound-and-true-p
> +                                               byte-compile-macro-environment)))
> +                   (function-get head 'gv-expander 'autoload))))

I think a better avenue would be to change function-put and function-get
to DTRT.


        Stefan





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-11 16:21             ` Stefan Monnier
@ 2017-07-12  0:55               ` npostavs
  2017-07-12  2:01                 ` Stefan Monnier
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-07-12  0:55 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> I think a better avenue would be to change function-put and function-get
> to DTRT.

I can see how that might work for function-get:

    (defun function-get (f prop &optional autoload)
      ...
   +  (or
   +   (if (eq prop 'gv-expander)
   +       (alist-get f (alist-get :gv-expanders
   +                               (bound-and-true-p
   +                                byte-compile-macro-environment))))
       (let ((val nil))
         (while (and (symbolp f)
                     (null (setq val (get f prop)))
         ;; etc...

But how can I make function-put do the right thing for both a macro
calling it and keep it's normal role?





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-12  0:55               ` npostavs
@ 2017-07-12  2:01                 ` Stefan Monnier
  2017-07-13  4:46                   ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-07-12  2:01 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

> I can see how that might work for function-get:
>
>     (defun function-get (f prop &optional autoload)
>       ...
>    +  (or
>    +   (if (eq prop 'gv-expander)
>    +       (alist-get f (alist-get :gv-expanders
>    +                               (bound-and-true-p
>    +                                byte-compile-macro-environment))))
>        (let ((val nil))
>          (while (and (symbolp f)
>                      (null (setq val (get f prop)))
>          ;; etc...

Why limit this to `gv-expander`?
Also, we should probably move the test within the subsequent `while`
loop, so that it interacts correctly with aliases.

> But how can I make function-put do the right thing for both a macro
> calling it and keep it's normal role?

I don't know what to do when a macro calls it (I can't think of any
reason we'd want to do that), but I know how to handle the case where
a macro outputs code that uses it: Add (byte-defop-compiler-1
function-put) as well as a byte-compile-function-put function.
See byte-compile-autoload and byte-compile-make-obsolete-variable
for examples.


        Stefan





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-12  2:01                 ` Stefan Monnier
@ 2017-07-13  4:46                   ` npostavs
  2017-07-13 14:25                     ` Stefan Monnier
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-07-13  4:46 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

[-- Attachment #1: Type: text/plain, Size: 434 bytes --]

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> I don't know what to do when a macro calls it (I can't think of any
> reason we'd want to do that), but I know how to handle the case where
> a macro outputs code that uses it: Add (byte-defop-compiler-1
> function-put) as well as a byte-compile-function-put function.
> See byte-compile-autoload and byte-compile-make-obsolete-variable
> for examples.

Oh, I think I get it now.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 3652 bytes --]

From 565dd64e74b78f56982bd7ca92f34ab71e6d669a Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Thu, 13 Jul 2017 00:40:35 -0400
Subject: [PATCH v3 1/2] Let `function-put' affect compilation of the current
 file

* lisp/emacs-lisp/bytecomp.el (byte-compile-plist-environment): New
variable.
(byte-compile-close-variables): Let-bind it to nil.
(byte-compile-function-put): New byte-defop-compiler.
* lisp/subr.el (function-get): Consult
`byte-compile-plist-environment'.
---
 lisp/emacs-lisp/bytecomp.el | 18 ++++++++++++++++++
 lisp/subr.el                |  7 ++++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index e5b9b47b1d..028efbce26 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -498,6 +498,10 @@ (defvar byte-compile-macro-environment byte-compile-initial-macro-environment
 Each element looks like (MACRONAME . DEFINITION).  It is
 \(MACRONAME . nil) when a macro is redefined as a function.")
 
+(defvar byte-compile-plist-environment nil
+  "Alist of property lists defined in the file being compiled.
+Each element looks like (SYMBOL . PLIST).")
+
 (defvar byte-compile-function-environment nil
   "Alist of functions defined in the file being compiled.
 This is so we can inline them when necessary.
@@ -1585,6 +1589,7 @@ (defmacro byte-compile-close-variables (&rest body)
           ;; macroenvironment.
           (copy-alist byte-compile-initial-macro-environment))
          (byte-compile--outbuffer nil)
+         (byte-compile-plist-environment nil)
          (byte-compile-function-environment nil)
          (byte-compile-bound-variables nil)
          (byte-compile-lexical-variables nil)
@@ -4577,6 +4582,7 @@ (byte-defop-compiler-1 defvar)
 (byte-defop-compiler-1 defconst byte-compile-defvar)
 (byte-defop-compiler-1 autoload)
 (byte-defop-compiler-1 lambda byte-compile-lambda-form)
+(byte-defop-compiler-1 function-put)
 
 ;; If foo.el declares `toto' as obsolete, it is likely that foo.el will
 ;; actually use `toto' in order for this obsolete variable to still work
@@ -4725,6 +4731,18 @@ (put 'make-variable-buffer-local
      'byte-hunk-handler 'byte-compile-form-make-variable-buffer-local)
 (defun byte-compile-form-make-variable-buffer-local (form)
   (byte-compile-keep-pending form 'byte-compile-normal-call))
+
+(defun byte-compile-function-put (form)
+  (pcase form
+    (`(,_ (,(or 'quote 'function) ,(and fun (guard (symbolp fun))))
+          ',prop ,(or `#',value (and value (guard (functionp value)))))
+     (let ((fplist (assq fun byte-compile-plist-environment)))
+       (if fplist
+           (setcdr fplist (plist-put (cdr fplist) prop value))
+         (push (cons fun (list prop value))
+               byte-compile-plist-environment)))))
+  (byte-compile-normal-call form))
+
 \f
 ;;; tags
 
diff --git a/lisp/subr.el b/lisp/subr.el
index 42b4e1c211..3e4a3dedf5 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2971,7 +2971,12 @@ (defun function-get (f prop &optional autoload)
 if it's an autoloaded macro."
   (let ((val nil))
     (while (and (symbolp f)
-                (null (setq val (get f prop)))
+                (null (setq val (or (plist-get
+                                     (alist-get
+                                      f (bound-and-true-p
+                                         byte-compile-plist-environment))
+                                     prop)
+                                    (get f prop))))
                 (fboundp f))
       (let ((fundef (symbol-function f)))
         (if (and autoload (autoloadp fundef)
-- 
2.11.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: patch --]
[-- Type: text/x-diff, Size: 6275 bytes --]

From bb2165c72cc7fa436ab911ab756cacec6384927d Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Thu, 13 Jul 2017 00:42:38 -0400
Subject: [PATCH v3 2/2] Don't define gv expanders in compiler's runtime
 (Bug#27016)

This prevents definitions being compiled from leaking into the current
Emacs doing the compilation.
* lisp/emacs-lisp/gv.el (gv-define-expander): Use function-put instead
of `put' with `eval-and-compile'.
* test/lisp/emacs-lisp/gv-tests.el: New tests.
---
 lisp/emacs-lisp/gv.el            |   7 +--
 test/lisp/emacs-lisp/gv-tests.el | 103 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+), 6 deletions(-)
 create mode 100644 test/lisp/emacs-lisp/gv-tests.el

diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index c5c12a6414..54105f89af 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -146,12 +146,7 @@ (defmacro gv-define-expander (name handler)
 HANDLER is a function which takes an argument DO followed by the same
 arguments as NAME.  DO is a function as defined in `gv-get'."
   (declare (indent 1) (debug (sexp form)))
-  ;; Use eval-and-compile so the method can be used in the same file as it
-  ;; is defined.
-  ;; FIXME: Just like byte-compile-macro-environment, we should have something
-  ;; like byte-compile-symbolprop-environment so as to handle these things
-  ;; cleanly without affecting the running Emacs.
-  `(eval-and-compile (put ',name 'gv-expander ,handler)))
+  `(function-put ',name 'gv-expander ,handler))
 
 ;;;###autoload
 (defun gv--defun-declaration (symbol name args handler &optional fix)
diff --git a/test/lisp/emacs-lisp/gv-tests.el b/test/lisp/emacs-lisp/gv-tests.el
new file mode 100644
index 0000000000..affc7ce455
--- /dev/null
+++ b/test/lisp/emacs-lisp/gv-tests.el
@@ -0,0 +1,103 @@
+;;; gv-tests.el --- tests for gv.el  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2017 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(eval-when-compile (require 'cl-lib))
+
+(cl-defmacro gv-tests--in-temp-dir ((elvar elcvar)
+                                    (&rest filebody)
+                                    &rest body)
+  (declare (indent 2))
+  `(let ((default-directory (make-temp-file "gv-test" t)))
+     (unwind-protect
+         (let ((,elvar "gv-test-deffoo.el")
+               (,elcvar "gv-test-deffoo.elc"))
+           (with-temp-file ,elvar
+             (insert ";; -*- lexical-binding: t; -*-\n")
+             (dolist (form ',filebody)
+               (pp form (current-buffer))))
+           ,@body)
+       (delete-directory default-directory t))))
+
+(ert-deftest gv-define-expander-in-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((gv-define-setter gv-test-foo (newval cons)
+         `(setcar ,cons ,newval))
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (message "%d" (car gv-test-pair)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string) "99\n")))))
+
+(ert-deftest gv-dont-define-expander-in-file ()
+  ;; The expander is defined while we are compiling the file, even
+  ;; though it's inside (when nil ...).
+  :expected-result :failed
+  (gv-tests--in-temp-dir (el elc)
+      ((when nil (gv-define-setter gv-test-foo (newval cons)
+                   `(setcar ,cons ,newval)))
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (message "%d" (car gv-test-pair)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string)
+                     "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
+
+(ert-deftest gv-define-expander-out-of-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((gv-define-setter gv-test-foo (newval cons)
+         `(setcar ,cons ,newval))
+       (defvar gv-test-pair (cons 1 2)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc
+                    "--eval"
+                    (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99)
+                                             (message "%d" (car gv-test-pair)))))
+      (should (equal (buffer-string) "99\n")))))
+
+(ert-deftest gv-dont-define-expander-other-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((if nil (gv-define-setter gv-test-foo (newval cons)
+                 `(setcar ,cons ,newval)))
+       (defvar gv-test-pair (cons 1 2)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc
+                    "--eval"
+                    (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99)
+                                             (message "%d" (car gv-test-pair)))))
+      (should (equal (buffer-string)
+                     "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
+
+;;; gv-tests.el ends here
-- 
2.11.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-13  4:46                   ` npostavs
@ 2017-07-13 14:25                     ` Stefan Monnier
  2017-07-14  0:39                       ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-07-13 14:25 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

> Oh, I think I get it now.

Looks about right.  A few comments below.


        Stefan


> @@ -4577,6 +4582,7 @@ (byte-defop-compiler-1 defvar)
>  (byte-defop-compiler-1 defconst byte-compile-defvar)
>  (byte-defop-compiler-1 autoload)
>  (byte-defop-compiler-1 lambda byte-compile-lambda-form)
> +(byte-defop-compiler-1 function-put)
> 
>  ;; If foo.el declares `toto' as obsolete, it is likely that foo.el will
>  ;; actually use `toto' in order for this obsolete variable to still work

I know it's not how it's done everywhere now, but I like to put the
byte-defop-compiler-1 next to the handler function.

> @@ -4725,6 +4731,18 @@ (put 'make-variable-buffer-local
>       'byte-hunk-handler 'byte-compile-form-make-variable-buffer-local)
>  (defun byte-compile-form-make-variable-buffer-local (form)
>    (byte-compile-keep-pending form 'byte-compile-normal-call))
> +
> +(defun byte-compile-function-put (form)
> +  (pcase form
> +    (`(,_ (,(or 'quote 'function) ,(and fun (guard (symbolp fun))))
> +          ',prop ,(or `#',value (and value (guard (functionp value)))))

The value doesn't have to be `functionp` (it is in the case of
gv-expander, but it depends on the property).

> +     (let ((fplist (assq fun byte-compile-plist-environment)))
> +       (if fplist
> +           (setcdr fplist (plist-put (cdr fplist) prop value))
> +         (push (cons fun (list prop value))
> +               byte-compile-plist-environment)))))

I'd just unconditionally use `push`:

         (push (cons fun `(,prop ,value . ,fplist))
               byte-compile-plist-environment)))))





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-13 14:25                     ` Stefan Monnier
@ 2017-07-14  0:39                       ` npostavs
  2017-07-14  3:48                         ` Stefan Monnier
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-07-14  0:39 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> Looks about right.

Except that it isn't.  While compiling map.el, I get

../../emacs-master/lisp/emacs-lisp/map.el:292:1:Error: Symbol’s function definition is void: internal-make-closure

I can fix this with

@@ -146,7 +146,7 @@ (defmacro gv-define-expander (name handler)
 HANDLER is a function which takes an argument DO followed by the same
 arguments as NAME.  DO is a function as defined in `gv-get'."
   (declare (indent 1) (debug (sexp form)))
-  `(function-put ',name 'gv-expander ,handler))
+  `(function-put ',name 'gv-expander (eval-when-compile ,handler)))

But that doesn't look like the right thing.

> I know it's not how it's done everywhere now, but I like to put the
> byte-defop-compiler-1 next to the handler function.

Makes sense.

>> +(defun byte-compile-function-put (form)
>> +  (pcase form
>> +    (`(,_ (,(or 'quote 'function) ,(and fun (guard (symbolp fun))))
>> +          ',prop ,(or `#',value (and value (guard (functionp value)))))
>
> The value doesn't have to be `functionp` (it is in the case of
> gv-expander, but it depends on the property).

Right.  I got a bit turned around with the quoting levels.  And given
the error above, I'm still not sure I have it worked out correctly.

>> +     (let ((fplist (assq fun byte-compile-plist-environment)))
>> +       (if fplist
>> +           (setcdr fplist (plist-put (cdr fplist) prop value))
>> +         (push (cons fun (list prop value))
>> +               byte-compile-plist-environment)))))
>
> I'd just unconditionally use `push`:
>
>          (push (cons fun `(,prop ,value . ,fplist))
>                byte-compile-plist-environment)))))

Yeah, that is simpler.





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-14  0:39                       ` npostavs
@ 2017-07-14  3:48                         ` Stefan Monnier
  2017-07-14  4:32                           ` Stefan Monnier
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-07-14  3:48 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

> Except that it isn't.  While compiling map.el, I get
>
> ../../emacs-master/lisp/emacs-lisp/map.el:292:1:Error: Symbol’s function definition is void: internal-make-closure

Hmm... yes ... interesting ... I see the problem: byte-compile-function-put
receives a form that's been preprocessed.  These look very much like
Elisp, but fundamentally, they're really just a different intermediate
representation, which includes things like `internal-make-closure', so
they can't be used as Elisp expressions (e.g. passed to `eval`): they
need to be passed through the rest of the compiler before they can be used.

I'm not sure yet how best way to solve this.


        Stefan





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-14  3:48                         ` Stefan Monnier
@ 2017-07-14  4:32                           ` Stefan Monnier
  2017-07-15 14:51                             ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-07-14  4:32 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

> I'm not sure yet how best way to solve this.

I believe the patch below does the right thing.  It's kind of a bummer
that we have to byte-compile the function call by hand, tho.  I tested
it only lightly, so please give it a more thorough testing and then feel
free to push it.


        Stefan


diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index e5b9b47b1d..e6f90e044b 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -498,6 +498,10 @@ byte-compile-macro-environment
 Each element looks like (MACRONAME . DEFINITION).  It is
 \(MACRONAME . nil) when a macro is redefined as a function.")
 
+(defvar byte-compile-plist-environment nil
+  "Alist of property lists defined in the file being compiled.
+Each element looks like (SYMBOL . PLIST).")
+
 (defvar byte-compile-function-environment nil
   "Alist of functions defined in the file being compiled.
 This is so we can inline them when necessary.
@@ -1585,6 +1589,7 @@ byte-compile-close-variables
           ;; macroenvironment.
           (copy-alist byte-compile-initial-macro-environment))
          (byte-compile--outbuffer nil)
+         (byte-compile-plist-environment nil)
          (byte-compile-function-environment nil)
          (byte-compile-bound-variables nil)
          (byte-compile-lexical-variables nil)
@@ -4695,7 +4700,7 @@ byte-compile-file-form-defalias
              (if (null fun)
                  (message "Macro %s unrecognized, won't work in file" name)
                (message "Macro %s partly recognized, trying our luck" name)
-               (push (cons name (eval fun))
+               (push (cons name (eval fun t))
                      byte-compile-macro-environment)))
            (byte-compile-keep-pending form))))
 
@@ -4725,6 +4730,33 @@ byte-compile-make-variable-buffer-local
      'byte-hunk-handler 'byte-compile-form-make-variable-buffer-local)
 (defun byte-compile-form-make-variable-buffer-local (form)
   (byte-compile-keep-pending form 'byte-compile-normal-call))
+
+(put 'function-put 'byte-hunk-handler 'byte-compile-function-put)
+(defun byte-compile-function-put (form)
+  (pcase form
+    ((and `(,op ,fun ,prop ,val)
+          (guard (and (macroexp-const-p fun)
+                      (macroexp-const-p prop)
+                      (or (macroexp-const-p val)
+                          ;; Also accept anonymous functions, since
+                          ;;  we're at top-level which implies they're
+                          ;;  also constants.
+                          (pcase val (`(function (lambda . ,_)) t))))))
+     (byte-compile-push-constant op)
+     (byte-compile-form fun)
+     (byte-compile-form prop)
+     (let* ((fun (eval fun t))
+            (prop (eval prop t))
+            (val (if (macroexp-const-p val)
+                     (eval val t)
+                   (byte-compile-lambda (cadr val)))))
+       (push (cons fun `(,prop ,val
+                         . ,(assq fun byte-compile-plist-environment)))
+             byte-compile-plist-environment)
+       (byte-compile-push-constant val)
+       (byte-compile-out 'byte-call 3)))
+
+    (_ (byte-compile-keep-pending form))))
 \f
 ;;; tags
 





^ permalink raw reply related	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-14  4:32                           ` Stefan Monnier
@ 2017-07-15 14:51                             ` npostavs
  2017-07-16  1:03                               ` Stefan Monnier
  0 siblings, 1 reply; 42+ messages in thread
From: npostavs @ 2017-07-15 14:51 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

[-- Attachment #1: Type: text/plain, Size: 661 bytes --]

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> @@ -4695,7 +4700,7 @@ byte-compile-file-form-defalias
>               (if (null fun)
>                   (message "Macro %s unrecognized, won't work in file" name)
>                 (message "Macro %s partly recognized, trying our luck" name)
> -               (push (cons name (eval fun))
> +               (push (cons name (eval fun t))

What does this do?  Should it be `lexical-binding' instead of `t'?

> +       (push (cons fun `(,prop ,val
> +                         . ,(assq fun byte-compile-plist-environment)))

That should be alist-get instead of assq.  I've fixed that and added a
test for it.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 5964 bytes --]

From 8ae4c8b840070c025fc7a9b24ab7fcff38683191 Mon Sep 17 00:00:00 2001
From: Stefan Monnier <monnier@IRO.UMontreal.CA>
Date: Fri, 14 Jul 2017 00:32:34 -0400
Subject: [PATCH v4 1/2] Let function-put take effect during compilation

* lisp/emacs-lisp/bytecomp.el (byte-compile-plist-environment): New
variable.
* lisp/emacs-lisp/bytecomp.el (byte-compile--outbuffer): Let-bind it to
nil.
* lisp/emacs-lisp/bytecomp.el (byte-compile-function-put): New
function, handles compilation of top-level `function-put' calls.
* lisp/subr.el (function-get): Consult byte-compile-plist-environment.

Co-authored-by: Noam Postavsky <npostavs@gmail.com>
---
 lisp/emacs-lisp/bytecomp.el            | 34 +++++++++++++++++++++++++++++++++-
 lisp/subr.el                           |  7 ++++++-
 test/lisp/emacs-lisp/bytecomp-tests.el | 17 +++++++++++++++++
 3 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index fdd4276e4e..ee474f9527 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -498,6 +498,10 @@ (defvar byte-compile-macro-environment byte-compile-initial-macro-environment
 Each element looks like (MACRONAME . DEFINITION).  It is
 \(MACRONAME . nil) when a macro is redefined as a function.")
 
+(defvar byte-compile-plist-environment nil
+  "Alist of property lists defined in the file being compiled.
+Each element looks like (SYMBOL . PLIST).")
+
 (defvar byte-compile-function-environment nil
   "Alist of functions defined in the file being compiled.
 This is so we can inline them when necessary.
@@ -1572,6 +1576,7 @@ (defmacro byte-compile-close-variables (&rest body)
           ;; macroenvironment.
           (copy-alist byte-compile-initial-macro-environment))
          (byte-compile--outbuffer nil)
+         (byte-compile-plist-environment nil)
          (byte-compile-function-environment nil)
          (byte-compile-bound-variables nil)
          (byte-compile-lexical-variables nil)
@@ -4682,7 +4687,7 @@ (defun byte-compile-file-form-defalias (form)
              (if (null fun)
                  (message "Macro %s unrecognized, won't work in file" name)
                (message "Macro %s partly recognized, trying our luck" name)
-               (push (cons name (eval fun))
+               (push (cons name (eval fun t))
                      byte-compile-macro-environment)))
            (byte-compile-keep-pending form))))
 
@@ -4712,6 +4717,33 @@ (put 'make-variable-buffer-local
      'byte-hunk-handler 'byte-compile-form-make-variable-buffer-local)
 (defun byte-compile-form-make-variable-buffer-local (form)
   (byte-compile-keep-pending form 'byte-compile-normal-call))
+
+(put 'function-put 'byte-hunk-handler 'byte-compile-function-put)
+(defun byte-compile-function-put (form)
+  (pcase form
+    ((and `(,op ,fun ,prop ,val)
+          (guard (and (macroexp-const-p fun)
+                      (macroexp-const-p prop)
+                      (or (macroexp-const-p val)
+                          ;; Also accept anonymous functions, since
+                          ;;  we're at top-level which implies they're
+                          ;;  also constants.
+                          (pcase val (`(function (lambda . ,_)) t))))))
+     (byte-compile-push-constant op)
+     (byte-compile-form fun)
+     (byte-compile-form prop)
+     (let* ((fun (eval fun t))
+            (prop (eval prop t))
+            (val (if (macroexp-const-p val)
+                     (eval val t)
+                   (byte-compile-lambda (cadr val)))))
+       (push `(,fun
+               . (,prop ,val ,@(alist-get fun byte-compile-plist-environment)))
+             byte-compile-plist-environment)
+       (byte-compile-push-constant val)
+       (byte-compile-out 'byte-call 3)))
+
+    (_ (byte-compile-keep-pending form))))
 \f
 ;;; tags
 
diff --git a/lisp/subr.el b/lisp/subr.el
index a9edff6166..0c7e52c7a7 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2962,7 +2962,12 @@ (defun function-get (f prop &optional autoload)
 if it's an autoloaded macro."
   (let ((val nil))
     (while (and (symbolp f)
-                (null (setq val (get f prop)))
+                (null (setq val (or (plist-get
+                                     (alist-get
+                                      f (bound-and-true-p
+                                         byte-compile-plist-environment))
+                                     prop)
+                                    (get f prop))))
                 (fboundp f))
       (let ((fundef (symbol-function f)))
         (if (and autoload (autoloadp fundef)
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el
index d15bd8b6e6..8ef2ce7025 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -545,6 +545,23 @@ (ert-deftest bytecomp-tests--old-style-backquotes ()
 This functionality has been obsolete for more than 10 years already
 and will be removed soon.  See (elisp)Backquote in the manual.")))))))
 
+
+(ert-deftest bytecomp-tests-function-put ()
+  "Check `function-put' operates during compilation."
+  (should (boundp 'lread--old-style-backquotes))
+  (bytecomp-tests--with-temp-file source
+    (dolist (form '((function-put 'bytecomp-tests--foo 'foo 1)
+                    (function-put 'bytecomp-tests--foo 'bar 2)
+                    (defmacro bytecomp-tests--foobar ()
+                      `(cons ,(function-get 'bytecomp-tests--foo 'foo)
+                             ,(function-get 'bytecomp-tests--foo 'bar)))
+                    (defvar bytecomp-tests--foobar 1)
+                    (setq bytecomp-tests--foobar (bytecomp-tests--foobar))))
+      (print form (current-buffer)))
+    (write-region (point-min) (point-max) source nil 'silent)
+    (byte-compile-file source t)
+    (should (equal bytecomp-tests--foobar (cons 1 2)))))
+
 ;; Local Variables:
 ;; no-byte-compile: t
 ;; End:
-- 
2.11.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: patch --]
[-- Type: text/x-diff, Size: 7855 bytes --]

From ee889d6bb0e36d8852ab122cfbcf2782dc12f74e Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Thu, 13 Jul 2017 00:42:38 -0400
Subject: [PATCH v4 2/2] Don't define gv expanders in compiler's runtime
 (Bug#27016)

This prevents definitions being compiled from leaking into the current
Emacs doing the compilation.
* lisp/emacs-lisp/gv.el (gv-define-expander): Use function-put instead
of `put' with `eval-and-compile'.
* test/lisp/emacs-lisp/gv-tests.el: New tests.
---
 lisp/emacs-lisp/gv.el            |   7 +-
 test/lisp/emacs-lisp/gv-tests.el | 140 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 141 insertions(+), 6 deletions(-)
 create mode 100644 test/lisp/emacs-lisp/gv-tests.el

diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index c5c12a6414..54105f89af 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -146,12 +146,7 @@ (defmacro gv-define-expander (name handler)
 HANDLER is a function which takes an argument DO followed by the same
 arguments as NAME.  DO is a function as defined in `gv-get'."
   (declare (indent 1) (debug (sexp form)))
-  ;; Use eval-and-compile so the method can be used in the same file as it
-  ;; is defined.
-  ;; FIXME: Just like byte-compile-macro-environment, we should have something
-  ;; like byte-compile-symbolprop-environment so as to handle these things
-  ;; cleanly without affecting the running Emacs.
-  `(eval-and-compile (put ',name 'gv-expander ,handler)))
+  `(function-put ',name 'gv-expander ,handler))
 
 ;;;###autoload
 (defun gv--defun-declaration (symbol name args handler &optional fix)
diff --git a/test/lisp/emacs-lisp/gv-tests.el b/test/lisp/emacs-lisp/gv-tests.el
new file mode 100644
index 0000000000..b15a3de8cc
--- /dev/null
+++ b/test/lisp/emacs-lisp/gv-tests.el
@@ -0,0 +1,140 @@
+;;; gv-tests.el --- tests for gv.el  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2017 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(eval-when-compile (require 'cl-lib))
+
+(cl-defmacro gv-tests--in-temp-dir ((elvar elcvar)
+                                    (&rest filebody)
+                                    &rest body)
+  (declare (indent 2))
+  `(let ((default-directory (make-temp-file "gv-test" t)))
+     (unwind-protect
+         (let ((,elvar "gv-test-deffoo.el")
+               (,elcvar "gv-test-deffoo.elc"))
+           (with-temp-file ,elvar
+             (insert ";; -*- lexical-binding: t; -*-\n")
+             (dolist (form ',filebody)
+               (pp form (current-buffer))))
+           ,@body)
+       (delete-directory default-directory t))))
+
+(ert-deftest gv-define-expander-in-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((gv-define-setter gv-test-foo (newval cons)
+         `(setcar ,cons ,newval))
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (message "%d" (car gv-test-pair)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string) "99\n")))))
+
+(ert-deftest gv-define-expander-in-file-twice ()
+  (gv-tests--in-temp-dir (el elc)
+      ((gv-define-setter gv-test-foo (newval cons)
+         `(setcar ,cons ,newval))
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (gv-define-setter gv-test-foo (newval cons)
+         `(setcdr ,cons ,newval))
+       (setf (gv-test-foo gv-test-pair) 42)
+       (message "%S" gv-test-pair))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string) "(99 . 42)\n")))))
+
+(ert-deftest gv-dont-define-expander-in-file ()
+  ;; The expander is defined while we are compiling the file, even
+  ;; though it's inside (when nil ...) because the compiler won't
+  ;; analyze the conditional.
+  :expected-result :failed
+  (gv-tests--in-temp-dir (el elc)
+      ((when nil (gv-define-setter gv-test-foo (newval cons)
+                   `(setcar ,cons ,newval)))
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (message "%d" (car gv-test-pair)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string)
+                     "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
+
+(ert-deftest gv-define-expander-in-function ()
+  ;; The expander is not defined while we are compiling the file, the
+  ;; compiler won't handle gv definitions not at top-level.
+  :expected-result :failed
+  (gv-tests--in-temp-dir (el elc)
+      ((defun foo ()
+         (gv-define-setter gv-test-foo (newval cons)
+           `(setcar ,cons ,newval))
+         t)
+       (defvar gv-test-pair (cons 1 2))
+       (setf (gv-test-foo gv-test-pair) 99)
+       (message "%d" (car gv-test-pair)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc)
+      (should (equal (buffer-string) "99\n")))))
+
+(ert-deftest gv-define-expander-out-of-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((gv-define-setter gv-test-foo (newval cons)
+         `(setcar ,cons ,newval))
+       (defvar gv-test-pair (cons 1 2)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc
+                    "--eval"
+                    (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99)
+                                             (message "%d" (car gv-test-pair)))))
+      (should (equal (buffer-string) "99\n")))))
+
+(ert-deftest gv-dont-define-expander-other-file ()
+  (gv-tests--in-temp-dir (el elc)
+      ((if nil (gv-define-setter gv-test-foo (newval cons)
+                 `(setcar ,cons ,newval)))
+       (defvar gv-test-pair (cons 1 2)))
+    (with-temp-buffer
+      (call-process (concat invocation-directory invocation-name)
+                    nil '(t t) nil
+                    "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+                    "-l" elc
+                    "--eval"
+                    (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99)
+                                             (message "%d" (car gv-test-pair)))))
+      (should (equal (buffer-string)
+                     "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
+
+;;; gv-tests.el ends here
-- 
2.11.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-15 14:51                             ` npostavs
@ 2017-07-16  1:03                               ` Stefan Monnier
  2017-08-08  1:18                                 ` npostavs
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Monnier @ 2017-07-16  1:03 UTC (permalink / raw)
  To: npostavs; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

>> +               (push (cons name (eval fun t))
> What does this do?  Should it be `lexical-binding' instead of `t'?

Sorry, part of an unrelated experiment.

>> +       (push (cons fun `(,prop ,val
>> +                         . ,(assq fun byte-compile-plist-environment)))
> That should be alist-get instead of assq.

Good catch.

> +     (let* ((fun (eval fun t))
> +            (prop (eval prop t))

These should likely be just (eval fun) without the `t` either.
Tho it doesn't really matter in any case: all those `eval`s just strip
off the quote in front of a sexp and should do the same regardless of
lexical-binding.


        Stefan





^ permalink raw reply	[flat|nested] 42+ messages in thread

* bug#27016: possible bug in `defsetf'
  2017-07-16  1:03                               ` Stefan Monnier
@ 2017-08-08  1:18                                 ` npostavs
  0 siblings, 0 replies; 42+ messages in thread
From: npostavs @ 2017-08-08  1:18 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Michael Heerdegen, 27016, Rafael D Sorkin

tags 27016 fixed
close 27016 26.1
quit

This should be fix in master now.

[1: 79a74568e9]: 2017-08-07 18:54:49 -0400
  Don't define gv expanders in compiler's runtime (Bug#27016)
  http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=79a74568e9166f63a12adb30f54edcd57a6405a3

[2: cc30d77ecd]: 2017-08-07 18:54:49 -0400
  Let `define-symbol-prop' take effect during compilation
  http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=cc30d77ecdd1b9155ade3d0656a84a0839ee2795





^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2017-08-08  1:18 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-22  6:39 bug#27016: possible bug in `defsetf' Rafael D Sorkin
2017-05-22 12:11 ` npostavs
2017-05-22 20:25 ` Rafael D Sorkin
2017-05-22 21:18   ` npostavs
2017-05-22 23:10     ` Michael Heerdegen
2017-05-22 23:23       ` npostavs
2017-05-23  0:45         ` Michael Heerdegen
2017-05-23  0:51           ` npostavs
2017-05-23  1:18             ` Michael Heerdegen
2017-05-22 22:03 ` Rafael D Sorkin
2017-05-22 23:15   ` npostavs
2017-05-24  4:52 ` Rafael D Sorkin
2017-05-24 22:51   ` Michael Heerdegen
2017-05-25  1:50     ` npostavs
2017-05-25  4:59 ` Rafael D Sorkin
2017-05-25  5:01 ` Rafael D Sorkin
2017-05-25 10:38   ` npostavs
2017-05-25 20:26     ` Michael Heerdegen
2017-05-25 20:42       ` Noam Postavsky
2017-05-25 21:31         ` Michael Heerdegen
2017-05-25 23:03           ` npostavs
2017-05-25 23:40             ` Michael Heerdegen
2017-05-26  3:50 ` Stefan Monnier
2017-05-26 22:51   ` npostavs
2017-05-28 20:45     ` Stefan Monnier
2017-07-02 20:47       ` npostavs
2017-07-03 11:25         ` Michael Heerdegen
2017-07-09 20:13           ` npostavs
2017-07-10  0:26             ` Michael Heerdegen
2017-07-11  1:45               ` npostavs
2017-07-11 16:21             ` Stefan Monnier
2017-07-12  0:55               ` npostavs
2017-07-12  2:01                 ` Stefan Monnier
2017-07-13  4:46                   ` npostavs
2017-07-13 14:25                     ` Stefan Monnier
2017-07-14  0:39                       ` npostavs
2017-07-14  3:48                         ` Stefan Monnier
2017-07-14  4:32                           ` Stefan Monnier
2017-07-15 14:51                             ` npostavs
2017-07-16  1:03                               ` Stefan Monnier
2017-08-08  1:18                                 ` npostavs
2017-05-26  5:05 ` Rafael D Sorkin

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).