Allow `letrec` binding without init expression
authorMattias Engdegård <mattiase@acm.org>
Sat, 4 May 2024 12:09:23 +0000 (14:09 +0200)
committerMattias Engdegård <mattiase@acm.org>
Sat, 4 May 2024 12:39:24 +0000 (14:39 +0200)
For example, (letrec (... (x) ...) ...) is now allowed.

* lisp/subr.el (letrec): Allow omitted init expression.
* test/lisp/subr-tests.el (subr--tests-letrec): Add test case.

lisp/subr.el
test/lisp/subr-tests.el

index 92d1e50ab2c8c133b2b623e065ae0a3ab1438479..0ac71560c591dcf9ba0ae6291c7af956090f05b1 100644 (file)
@@ -2281,7 +2281,9 @@ all symbols are bound before any of the VALUEFORMs are evalled."
     (let ((nbody (if (null binders)
                      (macroexp-progn body)
                    `(let ,(mapcar #'car binders)
-                      ,@(mapcar (lambda (binder) `(setq ,@binder)) binders)
+                      ,@(mapcan (lambda (binder)
+                                  (and (cdr binder) (list `(setq ,@binder))))
+                                binders)
                       ,@body))))
       (cond
        ;; All bindings are recursive.
index 4e3f743cc93bfd991e4f685c97844cb5250d08f4..119c124f3a5e423d7d6b2bd37a0ff8c77622c54a 100644 (file)
@@ -744,7 +744,14 @@ See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=19350."
                                  (+ subr-tests-var1 subr-tests-var2)))
                  '(let* ((subr-tests-var1 1)
                          (subr-tests-var2 subr-tests-var1))
-                    (+ subr-tests-var1 subr-tests-var2)))))
+                    (+ subr-tests-var1 subr-tests-var2))))
+  ;; Check that the init expression can be omitted, as in `let'/`let*'.
+  (should (equal (letrec ((a (lambda () (funcall c)))
+                          (b)
+                          (c (lambda () b)))
+                   (setq b 'ok)
+                   (funcall a))
+                 'ok)))
 
 (defvar subr-tests--hook nil)