leaves the binding with the value 45 (same code as with binding+with-redefs). The problem is that the let binding is somehow inlining the reference to foo. For instance the println statement compiles to:

it looks like the issue is, let binds essentially disappear at runtime
because the ioc macros bind every expression to a name, so let binds
are just mapped to those names at compile time. in that mapping global
names essentially map to themselves, so let bound names that get their
value from a global just disappear and become references to the
global.

If you look at the :symbol case for -item-to-ssa in
ioc_macros.clj, there is a commented out (add-instruction (->Const
x)), if you uncomment out that and comment out the fn above it, I
think what you get out has the behavior you are looking for, at the
cost of creating a local for every global read.

You could do some kind of picking of the behavior based on if the
globals are declared to be dynamic, but that would still leave issues
for with-redefs. In JVM clojure with-redefs works on global names
regardless of if they are dynamic or not. You could generate some kind
of dirty set if you see a set! of a global, and use that to toggle the
behavior, but I think (not sure) that could run in to issues because
the analysis is local in scope.