Defer parsing of method bodies until the end of a suitable enclosing scope. (#3832)

In parse, form a list of methods that are defined inline, tracking where
they start, where they end, and which other inline methods are nested
within them.

In check, when we reach an inline method body, skip it and add it to a
worklist to be processed later. We also track when we reach the start
and end of a context in which inline method bodies are deferred, so that
we know when to replay the bodies.

When suspending a function definition to be processed later, the
`DeclNameStack` entry is moved to separate storage, including popping
the corresponding scopes from the scope stack and removing the
corresponding lexical names from lexical lookup. Later, when we return
to the function and parse its definition, the `DeclNameStack` entry is
restored. The same is done when we reach the end of a nested context
that can have inline methods, so that we can reenter the nested scope
before processing its members.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2024-04-01 18:25:27 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent d7fb1b287d
commit f9ce0b194d
48 changed files with 1439 additions and 270 deletions
+34 -7
View File
@@ -225,12 +225,12 @@ auto HandleFunctionDecl(Context& context, Parse::FunctionDeclId node_id)
return true;
}
auto HandleFunctionDefinitionStart(Context& context,
Parse::FunctionDefinitionStartId node_id)
-> bool {
// Process the declaration portion of the function.
auto [function_id, decl_id] =
BuildFunctionDecl(context, node_id, /*is_definition=*/true);
// Processes a function definition after a signature for which we have already
// built a function ID. This logic is shared between processing regular function
// definitions and delayed parsing of inline method definitions.
static auto HandleFunctionDefinitionAfterSignature(
Context& context, Parse::FunctionDefinitionStartId node_id,
SemIR::FunctionId function_id, SemIR::InstId decl_id) -> void {
auto& function = context.functions().Get(function_id);
// Create the function scope and the entry block.
@@ -239,7 +239,7 @@ auto HandleFunctionDefinitionStart(Context& context,
context.scope_stack().Push(decl_id);
context.AddCurrentCodeBlockToFunction();
// Bring the implicit and explicit parameters into scope.
// Check the parameter types are complete.
for (auto param_id : llvm::concat<SemIR::InstId>(
context.inst_blocks().Get(function.implicit_param_refs_id),
context.inst_blocks().Get(function.param_refs_id))) {
@@ -264,6 +264,33 @@ auto HandleFunctionDefinitionStart(Context& context,
}
context.node_stack().Push(node_id, function_id);
}
auto HandleFunctionDefinitionSuspend(Context& context,
Parse::FunctionDefinitionStartId node_id)
-> SuspendedFunction {
// Process the declaration portion of the function.
auto [function_id, decl_id] =
BuildFunctionDecl(context, node_id, /*is_definition=*/true);
return {function_id, decl_id, context.decl_name_stack().Suspend()};
}
auto HandleFunctionDefinitionResume(Context& context,
Parse::FunctionDefinitionStartId node_id,
SuspendedFunction sus_fn) -> void {
context.decl_name_stack().Restore(sus_fn.saved_name_state);
HandleFunctionDefinitionAfterSignature(context, node_id, sus_fn.function_id,
sus_fn.decl_id);
}
auto HandleFunctionDefinitionStart(Context& context,
Parse::FunctionDefinitionStartId node_id)
-> bool {
// Process the declaration portion of the function.
auto [function_id, decl_id] =
BuildFunctionDecl(context, node_id, /*is_definition=*/true);
HandleFunctionDefinitionAfterSignature(context, node_id, function_id,
decl_id);
return true;
}