Destructuring is handled by the clojure.core/destructure
function. It's public, so we can call it ourselves and extract the names of all locals, including those naming intermediate results used in destructuring:
(defmacro and-let [bindings & tests]
(let [destructured (destructure bindings)]
`(let ~destructured
(and ~@(take-nth 2 destructured)
~@tests))))
Seems to work:
(let [foo nil]
(and-let [a 1
[b c] [2 3]]
(nil? foo)))
;= true