aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2023-02-11 10:45:31 +0000
committerAlan Mackenzie2023-02-11 10:45:31 +0000
commitdc3604cadfa8f4bc3e5d9346029e48b4268fcd60 (patch)
tree7695f40301539cb9b32c2422d7859410dec1c2d8
parentdbe7803aa1e8249bd70f67f25f19aedabeb9cc22 (diff)
downloademacs-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.el31
-rw-r--r--lisp/emacs-lisp/edebug.el20
-rw-r--r--lisp/emacs-lisp/testcover.el5
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.
118This 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.
838LEXVARS is the list of statically scoped vars in the context 842FORM is usually a function #\\='(lambda ...), but may be any valid
839and DYNVARS is the list of dynamically scoped vars in the context. 843form. LEXVARS is a list of symbols, each of which is lexically
840Returns a pair (LEXV . DYNV) of those vars actually used by FORM." 844bound in FORM's context. DYNVARS is a list of symbols, each of
845which is dynamically bound in FORM's context.
846Returns a cons (LEXV . DYNV), the car and cdr being lists of the
847lexically 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.
886This function is evaluated both at compile time and run time.
887FUN, the closure's function, must be a lambda form.
888ENV, the closure's environment, is a mixture of lexical bindings of the form
889(SYMBOL . VALUE) and symbols which indicate dynamic bindings of those
890symbols."
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)