diff options
| author | Alan Mackenzie | 2023-02-11 10:45:31 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2023-02-11 10:45:31 +0000 |
| commit | dc3604cadfa8f4bc3e5d9346029e48b4268fcd60 (patch) | |
| tree | 7695f40301539cb9b32c2422d7859410dec1c2d8 | |
| parent | dbe7803aa1e8249bd70f67f25f19aedabeb9cc22 (diff) | |
| download | emacs-dc3604cadfa8f4bc3e5d9346029e48b4268fcd60.tar.gz emacs-dc3604cadfa8f4bc3e5d9346029e48b4268fcd60.zip | |
Make edebug see unused variables when lexical-binding is non-nil
This fixes bug #59213.
* lisp/emacs-lisp/cconv.el (cconv-dont-trim-unused-variables): New variable.
(cconv-fv, cconv-make-interpreted-closure): Add/amend doc strings.
(cconv-make-interpreted-closure): Test cconv-dont-trim-unused-variables, and
if non-nil, don't "optimize" the lexical environment.
* lisp/emacs-lisp/edebug.el (edebug-make-enter-wrapper): Compile a binding of
cconv-dont-trim-unused-variables to t around the call of edebug-enter.
* lisp/emacs-lisp/testconver.el (testcover-analyze-coverage): Add a new arm to
the pcase form to handle the new form of edebug-enter.
| -rw-r--r-- | lisp/emacs-lisp/cconv.el | 31 | ||||
| -rw-r--r-- | lisp/emacs-lisp/edebug.el | 20 | ||||
| -rw-r--r-- | lisp/emacs-lisp/testcover.el | 5 |
3 files changed, 38 insertions, 18 deletions
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el index 570c9e66060..b8121aeba55 100644 --- a/lisp/emacs-lisp/cconv.el +++ b/lisp/emacs-lisp/cconv.el | |||
| @@ -113,6 +113,10 @@ is less than this number.") | |||
| 113 | (defvar cconv--dynbound-variables nil | 113 | (defvar cconv--dynbound-variables nil |
| 114 | "List of variables known to be dynamically bound.") | 114 | "List of variables known to be dynamically bound.") |
| 115 | 115 | ||
| 116 | (defvar cconv-dont-trim-unused-variables nil | ||
| 117 | "When bound to non-nil, don't remove unused variables from the environment. | ||
| 118 | This is intended for use by edebug and similar.") | ||
| 119 | |||
| 116 | ;;;###autoload | 120 | ;;;###autoload |
| 117 | (defun cconv-closure-convert (form &optional dynbound-vars) | 121 | (defun cconv-closure-convert (form &optional dynbound-vars) |
| 118 | "Main entry point for closure conversion. | 122 | "Main entry point for closure conversion. |
| @@ -834,10 +838,13 @@ This function does not return anything but instead fills the | |||
| 834 | (define-obsolete-function-alias 'cconv-analyse-form #'cconv-analyze-form "25.1") | 838 | (define-obsolete-function-alias 'cconv-analyse-form #'cconv-analyze-form "25.1") |
| 835 | 839 | ||
| 836 | (defun cconv-fv (form lexvars dynvars) | 840 | (defun cconv-fv (form lexvars dynvars) |
| 837 | "Return the list of free variables in FORM. | 841 | "Return the free variables used in FORM. |
| 838 | LEXVARS is the list of statically scoped vars in the context | 842 | FORM is usually a function #\\='(lambda ...), but may be any valid |
| 839 | and DYNVARS is the list of dynamically scoped vars in the context. | 843 | form. LEXVARS is a list of symbols, each of which is lexically |
| 840 | Returns a pair (LEXV . DYNV) of those vars actually used by FORM." | 844 | bound in FORM's context. DYNVARS is a list of symbols, each of |
| 845 | which is dynamically bound in FORM's context. | ||
| 846 | Returns a cons (LEXV . DYNV), the car and cdr being lists of the | ||
| 847 | lexically and dynamically bound symbols actually used by FORM." | ||
| 841 | (let* ((fun | 848 | (let* ((fun |
| 842 | ;; Wrap FORM into a function because the analysis code we | 849 | ;; Wrap FORM into a function because the analysis code we |
| 843 | ;; have only computes freevars for functions. | 850 | ;; have only computes freevars for functions. |
| @@ -875,11 +882,19 @@ Returns a pair (LEXV . DYNV) of those vars actually used by FORM." | |||
| 875 | (cons fvs dyns))))) | 882 | (cons fvs dyns))))) |
| 876 | 883 | ||
| 877 | (defun cconv-make-interpreted-closure (fun env) | 884 | (defun cconv-make-interpreted-closure (fun env) |
| 885 | "Make a closure for the interpreter. | ||
| 886 | This function is evaluated both at compile time and run time. | ||
| 887 | FUN, the closure's function, must be a lambda form. | ||
| 888 | ENV, the closure's environment, is a mixture of lexical bindings of the form | ||
| 889 | (SYMBOL . VALUE) and symbols which indicate dynamic bindings of those | ||
| 890 | symbols." | ||
| 878 | (cl-assert (eq (car-safe fun) 'lambda)) | 891 | (cl-assert (eq (car-safe fun) 'lambda)) |
| 879 | (let ((lexvars (delq nil (mapcar #'car-safe env)))) | 892 | (let ((lexvars (delq nil (mapcar #'car-safe env)))) |
| 880 | (if (null lexvars) | 893 | (if (or cconv-dont-trim-unused-variables (null lexvars)) |
| 881 | ;; The lexical environment is empty, so there's no need to | 894 | ;; The lexical environment is empty, or needs to be preserved, |
| 882 | ;; look for free variables. | 895 | ;; so there's no need to look for free variables. |
| 896 | ;; Attempting to replace ,(cdr fun) by a macroexpanded version | ||
| 897 | ;; causes bootstrap to fail. | ||
| 883 | `(closure ,env . ,(cdr fun)) | 898 | `(closure ,env . ,(cdr fun)) |
| 884 | ;; We could try and cache the result of the macroexpansion and | 899 | ;; We could try and cache the result of the macroexpansion and |
| 885 | ;; `cconv-fv' analysis. Not sure it's worth the trouble. | 900 | ;; `cconv-fv' analysis. Not sure it's worth the trouble. |
| @@ -896,7 +911,7 @@ Returns a pair (LEXV . DYNV) of those vars actually used by FORM." | |||
| 896 | (pcase expanded-form | 911 | (pcase expanded-form |
| 897 | (`#'(lambda . ,cdr) cdr) | 912 | (`#'(lambda . ,cdr) cdr) |
| 898 | (_ (cdr fun)))) | 913 | (_ (cdr fun)))) |
| 899 | 914 | ||
| 900 | (dynvars (delq nil (mapcar (lambda (b) (if (symbolp b) b)) env))) | 915 | (dynvars (delq nil (mapcar (lambda (b) (if (symbolp b) b)) env))) |
| 901 | (fvs (cconv-fv expanded-form lexvars dynvars)) | 916 | (fvs (cconv-fv expanded-form lexvars dynvars)) |
| 902 | (newenv (nconc (mapcar (lambda (fv) (assq fv env)) (car fvs)) | 917 | (newenv (nconc (mapcar (lambda (fv) (assq fv env)) (car fvs)) |
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index 2f7d03e9d79..735a358cdba 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el | |||
| @@ -1217,16 +1217,16 @@ purpose by adding an entry to this alist, and setting | |||
| 1217 | (setq edebug-old-def-name nil)) | 1217 | (setq edebug-old-def-name nil)) |
| 1218 | (setq edebug-def-name | 1218 | (setq edebug-def-name |
| 1219 | (or edebug-def-name edebug-old-def-name (gensym "edebug-anon"))) | 1219 | (or edebug-def-name edebug-old-def-name (gensym "edebug-anon"))) |
| 1220 | `(edebug-enter | 1220 | `(let ((cconv-dont-trim-unused-variables t)) |
| 1221 | (quote ,edebug-def-name) | 1221 | (edebug-enter |
| 1222 | ,(if edebug-inside-func | 1222 | (quote ,edebug-def-name) |
| 1223 | `(list | 1223 | ,(if edebug-inside-func |
| 1224 | ;; Doesn't work with more than one def-body!! | 1224 | `(list |
| 1225 | ;; But the list will just be reversed. | 1225 | ;; Doesn't work with more than one def-body!! |
| 1226 | ,@(nreverse edebug-def-args)) | 1226 | ;; But the list will just be reversed. |
| 1227 | 'nil) | 1227 | ,@(nreverse edebug-def-args)) |
| 1228 | (function (lambda () ,@forms)) | 1228 | 'nil) |
| 1229 | )) | 1229 | (function (lambda () ,@forms))))) |
| 1230 | 1230 | ||
| 1231 | 1231 | ||
| 1232 | (defvar edebug-form-begin-marker) ; the mark for def being instrumented | 1232 | (defvar edebug-form-begin-marker) ; the mark for def being instrumented |
diff --git a/lisp/emacs-lisp/testcover.el b/lisp/emacs-lisp/testcover.el index ed31b90ca32..1212905f08a 100644 --- a/lisp/emacs-lisp/testcover.el +++ b/lisp/emacs-lisp/testcover.el | |||
| @@ -442,6 +442,11 @@ or return multiple values." | |||
| 442 | (let ((testcover-vector (get sym 'edebug-coverage))) | 442 | (let ((testcover-vector (get sym 'edebug-coverage))) |
| 443 | (testcover-analyze-coverage-progn body))) | 443 | (testcover-analyze-coverage-progn body))) |
| 444 | 444 | ||
| 445 | (`(let ((cconv-dont-trim-unused-variables t)) | ||
| 446 | (edebug-enter ',sym ,_ (function (lambda nil . ,body)))) | ||
| 447 | (let ((testcover-vector (get sym 'edebug-coverage))) | ||
| 448 | (testcover-analyze-coverage-progn body))) | ||
| 449 | |||
| 445 | (`(edebug-after ,(and before-form | 450 | (`(edebug-after ,(and before-form |
| 446 | (or `(edebug-before ,before-id) before-id)) | 451 | (or `(edebug-before ,before-id) before-id)) |
| 447 | ,after-id ,wrapped-form) | 452 | ,after-id ,wrapped-form) |