diff options
| author | Stefan Monnier | 2022-01-31 11:07:06 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2022-01-31 11:07:26 -0500 |
| commit | 1d1b664fbb9232aa40d8daa54a689cfd63d38aa9 (patch) | |
| tree | 164ad10242c8566c3c8fa1d0c12c50804f82d791 /src | |
| parent | 90bbf27f02b1e7bf9cc0f0206313795c210c565b (diff) | |
| download | emacs-1d1b664fbb9232aa40d8daa54a689cfd63d38aa9.tar.gz emacs-1d1b664fbb9232aa40d8daa54a689cfd63d38aa9.zip | |
(function-history): New symbol property (bug#53632)
Rework the code we have in Fdefalias that tries to keep track
of definitions so as to be able to undo them later.
We used to store in `load-history` when an autoload is redefined as
a non-autoload and in the `autoload` symbol property we used to store
the autoload data that used to be used before it got overriden.
Instead, store the history of the function definition of
a symbol in its `function-history` symbol property.
To make this list cheap in the default case, the latest value is not stored
in the list (since it's in the `symbol-function`) and neither is the first
file. So if there's only been a single definition (the most common case),
the list is empty and the property is just not present at all.
The patch also gets rid of the `autoload` vs `defun` distinction in
`load-history` which seems unnecessary (a significant part of the
motivation for this patch was to get rid of the special handling of
autoloads in this part of the code).
* src/data.c (add_to_function_history): New function.
(defalias): Use it. Don't add the `t` entries for autoloads and always
use `defun` regardless of the kind of definition.
Change `Vautoload_queue` to only hold the function
symbols since the rest is now available from `function-history`.
* src/eval.c (un_autoload): Adjust accordingly.
* src/lread.c (load-history): Udate docstring.
* lisp/loadhist.el (loadhist-unload-filename): New var.
(unload-feature): Bind it.
(loadhist-unload-element): Document its availability.
(loadhist--restore-autoload): Delete var.
(loadhist--unload-function): Delete function.
(loadhist-unload-element): Delete the `t` and `autoload` methods.
Rewrite the `defun` method using `function-history`.
* lisp/help-fns.el: Require `seq`.
(help-fns--autoloaded-p): Rewrite.
(help-fns-function-description-header): Adjust call accordingly.
* doc/lispref/loading.texi (Where Defined): Remove `autoload` and `t`
entries from `load-history` since we don't generate them any more.
Document the `function-history` which replaces the `autoload` property.
(Unloading): Adjust symbol property name accordingly.
* test/lisp/loadhist-resources/loadhist--bar.el:
* test/lisp/loadhist-resources/loadhist--foo.el: New files.
* test/lisp/loadhist-tests.el (loadhist-tests-unload-feature-nested)
(loadhist-tests-unload-feature-notnested): New tests.
Diffstat (limited to 'src')
| -rw-r--r-- | src/data.c | 62 | ||||
| -rw-r--r-- | src/eval.c | 14 | ||||
| -rw-r--r-- | src/lread.c | 9 |
3 files changed, 58 insertions, 27 deletions
diff --git a/src/data.c b/src/data.c index a5a76a27554..95d29ac9e98 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -859,6 +859,43 @@ DEFUN ("fset", Ffset, Sfset, 2, 2, 0, | |||
| 859 | return definition; | 859 | return definition; |
| 860 | } | 860 | } |
| 861 | 861 | ||
| 862 | static void | ||
| 863 | add_to_function_history (Lisp_Object symbol, Lisp_Object olddef) | ||
| 864 | { | ||
| 865 | eassert (!NILP (olddef)); | ||
| 866 | |||
| 867 | Lisp_Object past = Fget (symbol, Qfunction_history); | ||
| 868 | Lisp_Object file = Qnil; | ||
| 869 | /* FIXME: Sadly, `Vload_file_name` gives less precise information | ||
| 870 | (it's sometimes non-nil when it shoujld be nil). */ | ||
| 871 | Lisp_Object tail = Vcurrent_load_list; | ||
| 872 | FOR_EACH_TAIL_SAFE (tail) | ||
| 873 | if (NILP (XCDR (tail)) && STRINGP (XCAR (tail))) | ||
| 874 | file = XCAR (tail); | ||
| 875 | |||
| 876 | Lisp_Object tem = Fplist_member (past, file); | ||
| 877 | if (!NILP (tem)) | ||
| 878 | { /* New def from a file used before. | ||
| 879 | Overwrite the previous record associated with this file. */ | ||
| 880 | if (EQ (tem, past)) | ||
| 881 | /* The new def is from the same file as the last change, so | ||
| 882 | there's nothing to do: unloading the file should revert to | ||
| 883 | the status before the last change rather than before this load. */ | ||
| 884 | return; | ||
| 885 | Lisp_Object pastlen = Flength (past); | ||
| 886 | Lisp_Object temlen = Flength (tem); | ||
| 887 | EMACS_INT tempos = XFIXNUM (pastlen) - XFIXNUM (temlen); | ||
| 888 | eassert (tempos > 1); | ||
| 889 | Lisp_Object prev = Fnthcdr (make_fixnum (tempos - 2), past); | ||
| 890 | /* Remove the previous info for this file. | ||
| 891 | E.g. change `hist` from (... OTHERFILE DEF3 THISFILE DEF2 ...) | ||
| 892 | to (... OTHERFILE DEF2). */ | ||
| 893 | XSETCDR (prev, XCDR (tem)); | ||
| 894 | } | ||
| 895 | /* Push new def from new file. */ | ||
| 896 | Fput (symbol, Qfunction_history, Fcons (file, Fcons (olddef, past))); | ||
| 897 | } | ||
| 898 | |||
| 862 | void | 899 | void |
| 863 | defalias (Lisp_Object symbol, Lisp_Object definition) | 900 | defalias (Lisp_Object symbol, Lisp_Object definition) |
| 864 | { | 901 | { |
| @@ -866,19 +903,19 @@ defalias (Lisp_Object symbol, Lisp_Object definition) | |||
| 866 | bool autoload = AUTOLOADP (definition); | 903 | bool autoload = AUTOLOADP (definition); |
| 867 | if (!will_dump_p () || !autoload) | 904 | if (!will_dump_p () || !autoload) |
| 868 | { /* Only add autoload entries after dumping, because the ones before are | 905 | { /* Only add autoload entries after dumping, because the ones before are |
| 869 | not useful and else we get loads of them from the loaddefs.el. */ | 906 | not useful and else we get loads of them from the loaddefs.el. |
| 870 | Lisp_Object function = XSYMBOL (symbol)->u.s.function; | 907 | That saves us about 110KB in the pdmp file (Jan 2022). */ |
| 871 | 908 | LOADHIST_ATTACH (Fcons (Qdefun, symbol)); | |
| 872 | if (AUTOLOADP (function)) | 909 | } |
| 873 | /* Remember that the function was already an autoload. */ | 910 | } |
| 874 | LOADHIST_ATTACH (Fcons (Qt, symbol)); | ||
| 875 | LOADHIST_ATTACH (Fcons (autoload ? Qautoload : Qdefun, symbol)); | ||
| 876 | |||
| 877 | if (!NILP (Vautoload_queue) && !NILP (function)) | ||
| 878 | Vautoload_queue = Fcons (Fcons (symbol, function), Vautoload_queue); | ||
| 879 | 911 | ||
| 880 | if (AUTOLOADP (function)) | 912 | { |
| 881 | Fput (symbol, Qautoload, XCDR (function)); | 913 | Lisp_Object olddef = XSYMBOL (symbol)->u.s.function; |
| 914 | if (!NILP (olddef)) | ||
| 915 | { | ||
| 916 | if (!NILP (Vautoload_queue)) | ||
| 917 | Vautoload_queue = Fcons (symbol, Vautoload_queue); | ||
| 918 | add_to_function_history (symbol, olddef); | ||
| 882 | } | 919 | } |
| 883 | } | 920 | } |
| 884 | 921 | ||
| @@ -4171,6 +4208,7 @@ syms_of_data (void) | |||
| 4171 | 4208 | ||
| 4172 | DEFSYM (Qinteractive_form, "interactive-form"); | 4209 | DEFSYM (Qinteractive_form, "interactive-form"); |
| 4173 | DEFSYM (Qdefalias_fset_function, "defalias-fset-function"); | 4210 | DEFSYM (Qdefalias_fset_function, "defalias-fset-function"); |
| 4211 | DEFSYM (Qfunction_history, "function-history"); | ||
| 4174 | 4212 | ||
| 4175 | DEFSYM (Qbyte_code_function_p, "byte-code-function-p"); | 4213 | DEFSYM (Qbyte_code_function_p, "byte-code-function-p"); |
| 4176 | 4214 | ||
diff --git a/src/eval.c b/src/eval.c index b083a00a791..1076985d097 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -2250,21 +2250,17 @@ this does nothing and returns nil. */) | |||
| 2250 | static void | 2250 | static void |
| 2251 | un_autoload (Lisp_Object oldqueue) | 2251 | un_autoload (Lisp_Object oldqueue) |
| 2252 | { | 2252 | { |
| 2253 | Lisp_Object queue, first, second; | ||
| 2254 | |||
| 2255 | /* Queue to unwind is current value of Vautoload_queue. | 2253 | /* Queue to unwind is current value of Vautoload_queue. |
| 2256 | oldqueue is the shadowed value to leave in Vautoload_queue. */ | 2254 | oldqueue is the shadowed value to leave in Vautoload_queue. */ |
| 2257 | queue = Vautoload_queue; | 2255 | Lisp_Object queue = Vautoload_queue; |
| 2258 | Vautoload_queue = oldqueue; | 2256 | Vautoload_queue = oldqueue; |
| 2259 | while (CONSP (queue)) | 2257 | while (CONSP (queue)) |
| 2260 | { | 2258 | { |
| 2261 | first = XCAR (queue); | 2259 | Lisp_Object first = XCAR (queue); |
| 2262 | second = Fcdr (first); | 2260 | if (CONSP (first) && EQ (XCAR (first), make_fixnum (0))) |
| 2263 | first = Fcar (first); | 2261 | Vfeatures = XCDR (first); |
| 2264 | if (EQ (first, make_fixnum (0))) | ||
| 2265 | Vfeatures = second; | ||
| 2266 | else | 2262 | else |
| 2267 | Ffset (first, second); | 2263 | Ffset (first, Fcar (Fcdr (Fget (first, Qfunction_history)))); |
| 2268 | queue = XCDR (queue); | 2264 | queue = XCDR (queue); |
| 2269 | } | 2265 | } |
| 2270 | } | 2266 | } |
diff --git a/src/lread.c b/src/lread.c index 9910db27de7..713c03243cb 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -5240,12 +5240,9 @@ for symbols and features not associated with any file. | |||
| 5240 | The remaining ENTRIES in the alist element describe the functions and | 5240 | The remaining ENTRIES in the alist element describe the functions and |
| 5241 | variables defined in that file, the features provided, and the | 5241 | variables defined in that file, the features provided, and the |
| 5242 | features required. Each entry has the form `(provide . FEATURE)', | 5242 | features required. Each entry has the form `(provide . FEATURE)', |
| 5243 | `(require . FEATURE)', `(defun . FUNCTION)', `(autoload . SYMBOL)', | 5243 | `(require . FEATURE)', `(defun . FUNCTION)', `(defface . SYMBOL)', |
| 5244 | `(defface . SYMBOL)', `(define-type . SYMBOL)', | 5244 | `(define-type . SYMBOL)', or `(cl-defmethod METHOD SPECIALIZERS)'. |
| 5245 | `(cl-defmethod METHOD SPECIALIZERS)', or `(t . SYMBOL)'. | 5245 | In addition, entries may also be single symbols, |
| 5246 | Entries like `(t . SYMBOL)' may precede a `(defun . FUNCTION)' entry, | ||
| 5247 | and mean that SYMBOL was an autoload before this file redefined it | ||
| 5248 | as a function. In addition, entries may also be single symbols, | ||
| 5249 | which means that symbol was defined by `defvar' or `defconst'. | 5246 | which means that symbol was defined by `defvar' or `defconst'. |
| 5250 | 5247 | ||
| 5251 | During preloading, the file name recorded is relative to the main Lisp | 5248 | During preloading, the file name recorded is relative to the main Lisp |