summaryrefslogtreecommitdiff
path: root/lisp/loadhist.el
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2022-01-31 11:07:06 -0500
committerStefan Monnier <monnier@iro.umontreal.ca>2022-01-31 11:07:26 -0500
commit1d1b664fbb9232aa40d8daa54a689cfd63d38aa9 (patch)
tree164ad10242c8566c3c8fa1d0c12c50804f82d791 /lisp/loadhist.el
parent90bbf27f02b1e7bf9cc0f0206313795c210c565b (diff)
downloademacs-1d1b664fbb9232aa40d8daa54a689cfd63d38aa9.tar.gz
emacs-1d1b664fbb9232aa40d8daa54a689cfd63d38aa9.tar.bz2
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 'lisp/loadhist.el')
-rw-r--r--lisp/loadhist.el54
1 files changed, 26 insertions, 28 deletions
diff --git a/lisp/loadhist.el b/lisp/loadhist.el
index 48058f40535..39481ab0684 100644
--- a/lisp/loadhist.el
+++ b/lisp/loadhist.el
@@ -157,38 +157,35 @@ documentation of `unload-feature' for details.")
;; mode, or proposed is not nil and not major-mode, and so we use it.
(funcall (or proposed 'fundamental-mode)))))))
+(defvar loadhist-unload-filename nil)
+
(cl-defgeneric loadhist-unload-element (x)
- "Unload an element from the `load-history'."
+ "Unload an element from the `load-history'.
+The variable `loadhist-unload-filename' holds the name of the file we're
+unloading."
(message "Unexpected element %S in load-history" x))
-;; In `load-history', the definition of a previously autoloaded
-;; function is represented by 2 entries: (t . SYMBOL) comes before
-;; (defun . SYMBOL) and says we should restore SYMBOL's autoload when
-;; we undefine it.
-;; So we use this auxiliary variable to keep track of the last (t . SYMBOL)
-;; that occurred.
-(defvar loadhist--restore-autoload nil
- "If non-nil, is a symbol for which to try to restore a previous autoload.")
-
-(cl-defmethod loadhist-unload-element ((x (head t)))
- (setq loadhist--restore-autoload (cdr x)))
-
-(defun loadhist--unload-function (x)
- (let ((fun (cdr x)))
- (when (fboundp fun)
- (when (fboundp 'ad-unadvise)
- (ad-unadvise fun))
- (let ((aload (get fun 'autoload)))
- (defalias fun
- (if (and aload (eq fun loadhist--restore-autoload))
- (cons 'autoload aload)
- nil)))))
- (setq loadhist--restore-autoload nil))
-
(cl-defmethod loadhist-unload-element ((x (head defun)))
- (loadhist--unload-function x))
-(cl-defmethod loadhist-unload-element ((x (head autoload)))
- (loadhist--unload-function x))
+ (let* ((fun (cdr x))
+ (hist (get fun 'function-history)))
+ (cond
+ ((null hist)
+ (defalias fun nil)
+ ;; Override the change that `defalias' just recorded.
+ (put fun 'function-history nil))
+ ((equal (car hist) loadhist-unload-filename)
+ (defalias fun (cadr hist))
+ ;; Set the history afterwards, to override the change that
+ ;; `defalias' records otherwise.
+ (put fun 'function-history (cddr hist)))
+ (t
+ ;; Unloading a file whose definition is "inactive" (i.e. has been
+ ;; overridden by another file): just remove it from the history,
+ ;; so future unloading of that other file has a chance to DTRT.
+ (let* ((tmp (plist-member hist loadhist-unload-filename))
+ (pos (- (length hist) (length tmp))))
+ (cl-assert (> pos 1))
+ (setcdr (nthcdr (- pos 2) hist) (cdr tmp)))))))
(cl-defmethod loadhist-unload-element ((_ (head require))) nil)
(cl-defmethod loadhist-unload-element ((_ (head defface))) nil)
@@ -257,6 +254,7 @@ something strange, such as redefining an Emacs function."
(prin1-to-string dependents) file))))
(let* ((unload-function-defs-list (feature-symbols feature))
(file (pop unload-function-defs-list))
+ (loadhist-unload-filename file)
(name (symbol-name feature))
(unload-hook (intern-soft (concat name "-unload-hook")))
(unload-func (intern-soft (concat name "-unload-function"))))