You're thinking of old elisp. Elisp hasn't been dynamically bound since around 2014. In modern elisp, every function is a closure.
If you pass your examples to `(eval ... t)`, you'll see what I mean. Or run `(setq-local lexical-binding t)` before evaluating them in the scratch buffer.
> (setq g (lambda (x)
(lambda ()
(progn
(setq x (+ x 1))
x))))
(setq f (funcall g 1))
(funcall f)
2
> f
(closure ((x . 2) t) nil (progn (setq x (+ x 1)) x))
> (setq x 20)
20
> (funcall f)
3
If you pass your examples to `(eval ... t)`, you'll see what I mean. Or run `(setq-local lexical-binding t)` before evaluating them in the scratch buffer.