Subject: bug#66912: With `require', the byte compiler reports the wrong file for errors.

From: Alan Mackenzie <[email-masked]>
Date: Thu, 7 Nov 2024 12:37:56 +0000

Hello, Stefan.

On Wed, Nov 06, 2024 at 18:14:18 -0500, Stefan Monnier wrote:
> >>     (while (not (equal Vloads_in_progress_of_last_error Vloads_in_progress))
> >>       (setq msg (concat msg " while loading "
> >>                         (pop Vloads_in_progress_of_last_error))))

> > This doesn't make sense in the current implementation (sorry for not
> > sending you a patch), because Vloads_in_progress_at_error is copied from
> > Vloads_in_progress in signal_or_quit.

> I don't understand why you say it doesn't make sense:

> An error in signaled from with a => B, so in `signal_or_quit` you copy
> `Vloads_in_progress` which contains `("B" "A")` to
> `Vloads_in_progress_at_error` and then you throw the error at the
> condition-case which was installed (say) from within the file A so
> when you reach the handler, `Vloads_in_progress` will have been reset to
> `("A")` so the above loop will correctly say that the error occurred
> from within B.

OK, I see what you mean.  But if the error gets handled in a handler-bind
handler, or goes through to the debugger without being intercepted by a
condition-case, the binding stack will not have been unwound.  In that
case the difference between the two lists would be empty.

> >> > I've tried it, and the above problem seems definitely to make it less
> >> > simple than the approach I originally took (which currently works).

> >> AFAIK, your previous approach suffered from the exact same problem, tho
> >> maybe in fewer cases.

> > No, it doesn't.  There, Vloads_still_in_progress is kept in synch with
> > Vloads_in_progress when Fload operations start and end.  When the
> > debugger or error handler outputs a message using Vl_still_i_p, it
> > resets that variable to nil, preventing it getting output again.

> You may be right that the "fewer" case are so few so that there really
> aren't any.  I'm not convinced there cannot be a code path that happens
> not to pass via those settings to nil, but maybe you're right.
> Still, my A => B => compile => C => D examples still stands, which is
> still at heart the same problem IMO, and could be worked around with my
> `while` loop above.

One way to fix this would be to make Vloads_still_in_progress visible to
Lisp, and to bind it to nil in the byte compiler.  But that might get a
bit complicated.

> > At the moment, I think my currently working solution is the best way
> > to go.

> [ As you can guess, I disagree, mostly because I think the problems of
>   my suggested approach are "familiar", since the behavior can be
>   compared to things like the match-data, so we know how to live with
>   its shortcomings, whereas I can't think of something else we already
>   have which follows an approach like yours, ....

Something very similar, if not the same, was the original handling of
byte-compile-form-stack.  There a form was pushed onto the stack at the
start of a byte-compile- function, and popped off again at its end,
without using binding.  In the case of an error, where the binding stack
gets unwound, byte-compile-form-stack retained its value at the time of
the error.  It worked without trouble (as far as I'm aware).

>   .... so we're in new territory and it's harder to see what the
>   problems could be and what workarounds to use.  ]

> Then you'd be better get cracking at the documentation of "survives
> unbinding" 🙂

I will do that.

>         Stefan

-- 
Alan Mackenzie (Nuremberg, Germany).