Handle references to global lets and enclosing locals. (#8061)

When building an expression referencing the result of name lookup, if
the lookup result is non-constant then check we can access it from the
current scope.

* If it is a global, then use a new `GlobalRef` instruction to get the
value of that global. In lowering, create global variables to hold the
values of global `let` bindings so that `GlobalRef` can access those
values.
* If it is a local, walk the lexical scopes between it and the point of
use and ensure it is usable through from all of them. Error if there's
an intervening declarative scope such as a class, add a TODO to handle
captures for intervening functions, and allow `typeof(...)` to name
things it can't read the value of since it's unevaluated.

Global `let`s (which includes `let`s at class scope) now also have their
initializers collected into the global inits block. If the initializer
is non-constant, the wrapper binding also lives in the global inits
block; otherwise it continues to live in the file block and the variable
emitted for it is a global constant.

Assisted-by: Gemini and Claude via Antigravity
This commit is contained in:
Richard Smith authored and GitHub committed 2026-11-06 02:53:03 +00:00
1 parent bb6486b553
commit d50576ca16
94 files changed
+3394 -1293

No files matched your search

+3 -2
View File
@@ -61,11 +61,12 @@ auto DeclNameStack::MakeUnqualifiedName(SemIR::LocId loc_id,
return context;
}
auto DeclNameStack::PushScopeAndStartName() -> void {
auto DeclNameStack::PushScopeAndStartName(
ScopeStack::NonConstantAccess non_constant_access) -> void {
decl_name_stack_.push_back(MakeEmptyNameContext());
// Create a scope for any parameters introduced in this name.
context_->scope_stack().PushForDeclName();
context_->scope_stack().PushForDeclName(non_constant_access);
UpdateAccessContext();
}