mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-11-15 07:28:31 +00:00
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:
1 parent
bb6486b553
commit
d50576ca16
94 files changed
+3394
-1293
No files matched your search
@@ -54,6 +54,7 @@ auto ScopeStack::VerifyNextCompileTimeBindIndex(llvm::StringLiteral label,
|
||||
auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
|
||||
SemIR::SpecificId specific_id,
|
||||
CleanupScopeKind cleanup_scope_kind,
|
||||
NonConstantAccess non_constant_access,
|
||||
bool lexical_lookup_has_load_error) -> void {
|
||||
// If this scope doesn't have a specific of its own, it lives in the enclosing
|
||||
// scope's specific, if any.
|
||||
@@ -73,6 +74,7 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
|
||||
.lexical_lookup_has_load_error =
|
||||
LexicalLookupHasLoadError() || lexical_lookup_has_load_error,
|
||||
.cleanup_scope_kind = cleanup_scope_kind,
|
||||
.non_constant_access = non_constant_access,
|
||||
.cleanup_scope_depth = CleanupScopeDepth(destroy_id_stack_.size())});
|
||||
if (scope_stack_.back().is_lexical_scope()) {
|
||||
// For lexical lookups, unqualified lookup doesn't know how to find the
|
||||
@@ -100,9 +102,11 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
|
||||
VerifyNextCompileTimeBindIndex("Push", scope_stack_.back());
|
||||
}
|
||||
|
||||
auto ScopeStack::PushForDeclName() -> void {
|
||||
auto ScopeStack::PushForDeclName(NonConstantAccess non_constant_access)
|
||||
-> void {
|
||||
Push(SemIR::InstId::None, SemIR::NameScopeId::None, SemIR::SpecificId::None,
|
||||
CleanupScopeKind::None, /*lexical_lookup_has_load_error=*/false);
|
||||
CleanupScopeKind::None, non_constant_access,
|
||||
/*lexical_lookup_has_load_error=*/false);
|
||||
MarkNestingIfInReturnScope();
|
||||
}
|
||||
|
||||
@@ -113,11 +117,12 @@ auto ScopeStack::PushForEntity(SemIR::InstId scope_inst_id,
|
||||
CARBON_CHECK(scope_inst_id.has_value());
|
||||
CARBON_DCHECK(!sem_ir().insts().Is<SemIR::FunctionDecl>(scope_inst_id));
|
||||
Push(scope_inst_id, scope_id, specific_id, CleanupScopeKind::None,
|
||||
lexical_lookup_has_load_error);
|
||||
NonConstantAccess::Disallowed, lexical_lookup_has_load_error);
|
||||
MarkNestingIfInReturnScope();
|
||||
}
|
||||
|
||||
auto ScopeStack::PushForSameRegion(CleanupScopeKind cleanup_scope_kind)
|
||||
auto ScopeStack::PushForSameRegion(CleanupScopeKind cleanup_scope_kind,
|
||||
NonConstantAccess non_constant_access)
|
||||
-> void {
|
||||
if (cleanup_scope_kind == CleanupScopeKind::Inherited &&
|
||||
Peek().cleanup_scope_kind == CleanupScopeKind::None) {
|
||||
@@ -125,7 +130,8 @@ auto ScopeStack::PushForSameRegion(CleanupScopeKind cleanup_scope_kind)
|
||||
}
|
||||
|
||||
Push(SemIR::InstId::None, SemIR::NameScopeId::None, SemIR::SpecificId::None,
|
||||
cleanup_scope_kind, /*lexical_lookup_has_load_error=*/false);
|
||||
cleanup_scope_kind, non_constant_access,
|
||||
/*lexical_lookup_has_load_error=*/false);
|
||||
}
|
||||
|
||||
auto ScopeStack::PushForFunctionBody(SemIR::InstId scope_inst_id) -> void {
|
||||
@@ -134,7 +140,8 @@ auto ScopeStack::PushForFunctionBody(SemIR::InstId scope_inst_id) -> void {
|
||||
const auto& function = sem_ir().functions().Get(function_decl.function_id);
|
||||
auto self_specific = sem_ir().generics().GetSelfSpecific(function.generic_id);
|
||||
Push(scope_inst_id, SemIR::NameScopeId::None, self_specific,
|
||||
CleanupScopeKind::Owned, /*lexical_lookup_has_load_error=*/false);
|
||||
CleanupScopeKind::Owned, NonConstantAccess::Permitted,
|
||||
/*lexical_lookup_has_load_error=*/false);
|
||||
|
||||
return_scope_stack_.push_back(
|
||||
{.decl_id = scope_inst_id, .cleanup_scope_depth = cleanup_scope_depth()});
|
||||
@@ -278,7 +285,7 @@ auto ScopeStack::LookupInLexicalScopesWithin(SemIR::NameId name_id,
|
||||
auto ScopeStack::LookupInLexicalScopes(SemIR::NameId name_id,
|
||||
SemIR::LocId use_loc_id,
|
||||
bool is_reachable)
|
||||
-> std::pair<SemIR::InstId, llvm::ArrayRef<NonLexicalScope>> {
|
||||
-> std::pair<LexicalResult, llvm::ArrayRef<NonLexicalScope>> {
|
||||
// Find the results from lexical scopes. These will be combined with results
|
||||
// from non-lexical scopes such as namespaces and classes.
|
||||
llvm::ArrayRef<LexicalLookup::Result> lexical_results =
|
||||
@@ -286,8 +293,9 @@ auto ScopeStack::LookupInLexicalScopes(SemIR::NameId name_id,
|
||||
|
||||
// If we have no lexical results, check all non-lexical scopes.
|
||||
if (lexical_results.empty()) {
|
||||
return {LexicalLookupHasLoadError() ? SemIR::ErrorInst::InstId
|
||||
: SemIR::InstId::None,
|
||||
return {{.inst_id = LexicalLookupHasLoadError() ? SemIR::ErrorInst::InstId
|
||||
: SemIR::InstId::None,
|
||||
.scope_index = ScopeIndex::None},
|
||||
non_lexical_scope_stack_};
|
||||
}
|
||||
|
||||
@@ -302,10 +310,24 @@ auto ScopeStack::LookupInLexicalScopes(SemIR::NameId name_id,
|
||||
return scope.scope_index < index;
|
||||
});
|
||||
return {
|
||||
lexical_results.back().inst_id,
|
||||
{.inst_id = lexical_results.back().inst_id,
|
||||
.scope_index = lexical_results.back().scope_index},
|
||||
llvm::ArrayRef(first_non_lexical_scope, non_lexical_scope_stack_.end())};
|
||||
}
|
||||
|
||||
auto ScopeStack::GetNonConstantAccess(ScopeIndex target_scope_index) const
|
||||
-> NonConstantAccess {
|
||||
for (const auto& entry : llvm::reverse(scope_stack_)) {
|
||||
if (entry.index <= target_scope_index) {
|
||||
break;
|
||||
}
|
||||
if (entry.non_constant_access != NonConstantAccess::Permitted) {
|
||||
return entry.non_constant_access;
|
||||
}
|
||||
}
|
||||
return NonConstantAccess::Permitted;
|
||||
}
|
||||
|
||||
auto ScopeStack::LookupOrAddName(SemIR::NameId name_id, SemIR::InstId target_id,
|
||||
ScopeIndex scope_index, bool is_decl_reachable)
|
||||
-> SemIR::InstId {
|
||||
|
||||
Reference in new issue
Block a user