Restructure return declaration handling (#7076)

- A function with a return declaration always has exactly one
`ReturnSlotPattern`, representing the whole return declaration (whereas
previously that was omitted for value and reference returns).
- The `ReturnSlotPattern` always has a subpattern with the same form.
`OutParamPattern` already plays that role for initializing forms, and
`TuplePattern` will play that role for tuple forms. This change
introduces `ValueReturnPattern` and `RefReturnPattern` to represent
value and reference return forms.
- As before, the `ReturnSlotPattern` has a corresponding `ReturnSlot`
that represents the output that is initialized by a `return` statement.
Its structure parallels the structure of the `ReturnSlotPattern`, so we
need `ValueReturn` and `RefReturn` insts that correspond to
`ValueReturnPattern` and `RefReturnPattern`.

This is a step toward supporting generic return forms, where the
`ReturnSlotPattern`'s subpattern may be an action: this change ensures
that evaluating the action for a specific form produces the same SemIR
as if the form were concrete to begin with. More speculatively, this
should simplify the implementation of `return` statements with compound
return forms.

---------

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This commit is contained in:
Geoff Romer
2026-04-22 23:38:21 +00:00
committed by GitHub
co-authored by Chandler Carruth
parent 3abc334c42
commit 49c7288619
40 changed files with 598 additions and 390 deletions
+9 -9
View File
@@ -61,8 +61,8 @@ static auto HandleReturnDecl(Context& context, Parse::AnyReturnDeclId node_id)
}
}();
context.PushReturnForm(form_expr);
auto return_patterns_id = AddReturnPatterns(context, node_id, form_expr);
context.node_stack().Push(node_id, return_patterns_id);
context.node_stack().Push(node_id,
AddReturnPattern(context, node_id, form_expr));
return true;
}
@@ -173,7 +173,7 @@ static auto MergeFunctionRedecl(Context& context,
prev_function.call_params_id = new_function.call_params_id;
prev_function.return_type_inst_id = new_function.return_type_inst_id;
prev_function.return_form_inst_id = new_function.return_form_inst_id;
prev_function.return_patterns_id = new_function.return_patterns_id;
prev_function.return_pattern_id = new_function.return_pattern_id;
prev_function.self_param_id = new_function.self_param_id;
}
if (prev_import_ir_id.has_value()) {
@@ -500,20 +500,20 @@ static auto BuildFunctionDecl(Context& context,
Parse::AnyFunctionDeclId node_id,
bool is_definition)
-> std::pair<SemIR::FunctionId, SemIR::InstId> {
auto return_patterns_id = SemIR::InstBlockId::None;
auto return_pattern_id = SemIR::InstId::None;
auto return_type_inst_id = SemIR::TypeInstId::None;
auto return_form_inst_id = SemIR::InstId::None;
if (auto [return_node, maybe_return_patterns_id] =
if (auto [return_node, maybe_return_pattern_id] =
context.node_stack()
.PopWithNodeIdIf<Parse::NodeCategory::ReturnDecl>();
maybe_return_patterns_id) {
return_patterns_id = *maybe_return_patterns_id;
maybe_return_pattern_id) {
return_pattern_id = *maybe_return_pattern_id;
auto return_form = context.PopReturnForm();
return_type_inst_id = return_form.type_component_inst_id;
return_form_inst_id = return_form.form_inst_id;
}
auto name = PopNameComponent(context, return_patterns_id);
auto name = PopNameComponent(context, return_pattern_id);
auto name_context = context.decl_name_stack().FinishName(name);
context.node_stack()
@@ -550,7 +550,7 @@ static auto BuildFunctionDecl(Context& context,
.call_param_ranges = name.param_ranges,
.return_type_inst_id = return_type_inst_id,
.return_form_inst_id = return_form_inst_id,
.return_patterns_id = return_patterns_id,
.return_pattern_id = return_pattern_id,
.virtual_modifier = virtual_modifier,
.evaluation_mode = evaluation_mode,
.self_param_id = self_param_id}};