Files
carbon-lang/toolchain/check/full_pattern_stack.cpp
T
Richard Smith d50576ca16 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
2026-11-06 02:53:03 +00:00

50 lines
1.9 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/check/full_pattern_stack.h"
#include "toolchain/check/context.h"
#include "toolchain/check/pattern.h"
namespace Carbon::Check {
auto FullPatternStack::StartPatternInitializer() -> void {
CARBON_CHECK(IsAnyNameBindingDeclKind(kind_stack_.back()));
for (auto& [name_id, inst_id] : bind_name_stack_.PeekArray()) {
CARBON_CHECK(
inst_id == SemIR::InstId::InitTombstone,
"stashing the lookup result would overwrite an existing stash {0}",
inst_id);
auto& lookup_result = lookup_->Get(name_id);
if (!lookup_result.empty()) {
// Temporarily overwrite the result of name lookup for this binding to be
// `InitTombstone`, so that references to it in the initializer are
// diagnosed as errors. The original result of name lookup is stashed in
// `bind_name_stack_` so we can restore it later.
//
// TODO: find a way to preserve location information, so that we can
// provide good diagnostics for a redeclaration of `name_id` in
// the initializer, if that becomes possible.
std::swap(lookup_result.back().inst_id, inst_id);
}
}
next_var_index_stack_.back() = 0;
}
auto FullPatternStack::EndPatternInitializer() -> void {
for (auto& [name_id, inst_id] : bind_name_stack_.PeekArray()) {
auto& lookup_result = lookup_->Get(name_id);
if (!lookup_result.empty()) {
// Restore the original result of name lookup for this binding.
std::swap(lookup_result.back().inst_id, inst_id);
}
CARBON_CHECK(inst_id == SemIR::InstId::InitTombstone,
"name_id resolved to a non-tombstone value {0} during "
"initializer handling",
inst_id);
}
}
} // namespace Carbon::Check