Detect control flow in entities nested inside functions (#5336)

Right now, return_scope_stack is being used to determine whether logic
is in a function scope. However, we need to handle nested entities
inside function scopes. For example where this crashes right now:

```
base class C(B:! bool) {}

fn F() {
  class B {
    extend base: C(true or false);
  }
}
```

This is doing a few things to make this kind of code not crash:

- Split `scope_stack().Push` into `PushForDeclName`, `PushForEntity`,
`PushForExpr`, and `PushForFunction` so that better decisions can be
made about behaviors.
- Hide `return_scope_stack` in the API, instead using interfaces to get
at the underlying data.
- Also using `PushForFunction` to update it similar to the other stacks
that `ScopeStack` manages.
- Add `IsInFunctionScope` as the best way to determine presence in
function scope.
- Remove `PeekIsLexicalScope` since destruction really wants function
scope information anyways.
- Clean up `destroy_id_stack` handling to be for function scopes rather
than lexical scopes.
- Return after related `context.TODO`s in a couple more spots, so that
code doesn't proceed to add control flow in spite of the lack of
support.

---------

Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
Jon Ross-Perkins
2025-04-23 19:03:53 +00:00
committed by GitHub
co-authored by Geoff Romer
parent 51498547c9
commit 03e693873b
22 changed files with 476 additions and 391 deletions
+4 -2
View File
@@ -229,7 +229,9 @@ auto CheckUnit::ImportCurrentPackage(SemIR::InstId package_inst_id,
unit_and_imports_->package_imports_map.Lookup(PackageNameId::None);
if (!import_map_lookup) {
// Push the scope; there are no names to add.
context_.scope_stack().Push(package_inst_id, SemIR::NameScopeId::Package);
context_.scope_stack().PushForEntity(
package_inst_id, SemIR::NameScopeId::Package, SemIR::SpecificId::None,
/*lexical_lookup_has_load_error=*/false);
return;
}
PackageImports& self_import =
@@ -244,7 +246,7 @@ auto CheckUnit::ImportCurrentPackage(SemIR::InstId package_inst_id,
CollectTransitiveImports(self_import.import_decl_id, &self_import,
/*api_imports=*/nullptr));
context_.scope_stack().Push(
context_.scope_stack().PushForEntity(
package_inst_id, SemIR::NameScopeId::Package, SemIR::SpecificId::None,
context_.name_scopes().Get(SemIR::NameScopeId::Package).has_error());
}