Function: byte-optimize-let-form

byte-optimize-let-form is a byte-compiled function defined in byte-opt.el.gz.

Signature

(byte-optimize-let-form HEAD FORM FOR-EFFECT)

Source Code

;; Defined in /usr/src/emacs/lisp/emacs-lisp/byte-opt.el.gz
(defun byte-optimize-let-form (head form for-effect)
  ;; Recursively enter the optimizer for the bindings and body
  ;; of a let or let*.  This for depth-firstness: forms that
  ;; are more deeply nested are optimized first.
  (if lexical-binding
      (let* ((byte-optimize--lexvars byte-optimize--lexvars)
             (byte-optimize--aliased-vars byte-optimize--aliased-vars)
             (new-lexvars nil)
             (let-vars nil)
             (body (cdr form))
             (bindings (car form)))
        (while bindings
          (let* ((binding (car bindings))
                 (name (car binding))
                 (expr (byte-optimize-form (cadr binding) nil)))
            (setq bindings (cdr bindings))
            (when (and (eq head 'let*)
                       (assq name byte-optimize--aliased-vars))
              ;; New variable shadows an aliased variable -- α-rename
              ;; it in this and all subsequent bindings.
              (let ((new-name (make-symbol (symbol-name name))))
                (setq bindings
                      (mapcar (lambda (b)
                                (list (byte-optimize--rename-var
                                       name new-name (car b))
                                      (byte-optimize--rename-var
                                       name new-name (cadr b))))
                              bindings))
                (setq body (byte-optimize--rename-var-body name new-name body))
                (setq name new-name)))
            (let* ((aliased
                    ;; Aliasing another lexvar.
                    (and (symbolp expr) (assq expr byte-optimize--lexvars)))
                   (value (and (or aliased
                                   (byte-optimize--substitutable-p expr))
                               (list expr)))
                   (lexical (not (or (special-variable-p name)
                                     (memq name byte-compile-bound-variables)
                                     (memq name byte-optimize--dynamic-vars))))
                   (lexinfo (and lexical (cons name (cons nil value)))))
              (push (cons name (cons expr (cdr lexinfo))) let-vars)
              (when lexinfo
                (push lexinfo (if (eq head 'let*)
                                  byte-optimize--lexvars
                                new-lexvars))
                (when aliased
                  (push (cons expr lexinfo) byte-optimize--aliased-vars))))))

        (when (and (eq head 'let) byte-optimize--aliased-vars)
          ;; Find new variables that shadow aliased variables.
          (let ((shadowing-vars nil))
            (dolist (lexvar new-lexvars)
              (let ((name (car lexvar)))
                (when (and (assq name byte-optimize--aliased-vars)
                           (not (memq name shadowing-vars)))
                  (push name shadowing-vars))))
            ;; α-rename them
            (dolist (name shadowing-vars)
              (let ((new-name (make-symbol (symbol-name name))))
                (setq new-lexvars
                      (mapcar (lambda (lexvar)
                                (if (eq (car lexvar) name)
                                    (cons new-name (cdr lexvar))
                                  lexvar))
                              new-lexvars))
                (setq let-vars
                      (mapcar (lambda (v)
                                (if (eq (car v) name)
                                    (cons new-name (cdr v))
                                  v))
                              let-vars))
                (setq body (byte-optimize--rename-var-body
                            name new-name body))))))
        (setq byte-optimize--lexvars
              (append new-lexvars byte-optimize--lexvars))
        ;; Walk the body expressions, which may mutate some of the records,
        ;; and generate new bindings that exclude unused variables.
        (let* ((byte-optimize--dynamic-vars byte-optimize--dynamic-vars)
               (opt-body (byte-optimize-body body for-effect))
               (bindings nil))
          (dolist (var let-vars)
            ;; VAR is (NAME EXPR [KEEP [VALUE]])
            (when (or (not (nthcdr 3 var)) (nth 2 var)
                      byte-optimize--inhibit-outside-loop-constprop)
              ;; Value not present, or variable marked to be kept,
              ;; or we are in the loop discovery phase: keep the binding.
              (push (list (nth 0 var) (nth 1 var)) bindings)))
          (cons bindings opt-body)))

    ;; With dynamic binding, no substitutions are in effect.
    (let ((byte-optimize--lexvars nil))
      (cons
       (mapcar (lambda (binding)
                 (list (car binding)
		       (byte-optimize-form (nth 1 binding) nil)))
	       (car form))
       (byte-optimize-body (cdr form) for-effect)))))