Since there is no local variable t in your example, your function accesses the global value t (that is: _ENV.t). When your function is called, it accesses the current value of the _ENV variable, then indexes into the "t" index of that _ENV value. Even though the _ENV table does not contain t when the function is defined, when it is later called, it does contain t, and so you are able to access your newly defined table.
local u = {
f = function()
-- Refers to the global variable `t` (that is, _ENV.t).
-- Whenever the function is called, the *current* value of `t` is returned
return t
end
}
print(u) -- prints table: 0xFOOBAR
print(u.f()) -- prints nil
t = u
print(t) --prints table: 0xFOOBAR
print(t.f()) --prints table: 0xFOOBAR
_ENV = {print = print}
print(u.f()) -- prints nil, since _ENV.t is now nil
local _ENV = {print = print, t = u}
print(u.f()) -- still prints nil, because the function definition used the
-- _ENV variable that was lexically visible at the function definition,
-- rather than the new _ENV variable that was just defined.
The use of _ENV means that these examples are only valid for Lua 5.2, but the same principle applies for Lua 5.1.