Model the return slot as an output parameter (#4432)

Also fix `Param` insts to have meaningful names in pretty-printing, to
help clarify relationship with return slot.
This commit is contained in:
Geoff Romer
2024-10-23 16:53:34 +00:00
committed by GitHub
parent 5038218cea
commit 9266f867f9
463 changed files with 7401 additions and 4939 deletions
+18 -12
View File
@@ -44,9 +44,15 @@ auto HandleParseNode(Context& context, Parse::ReturnTypeId node_id) -> bool {
// Propagate the type expression.
auto [type_node_id, type_inst_id] = context.node_stack().PopExprWithNodeId();
auto type_id = ExprAsType(context, type_node_id, type_inst_id).type_id;
// TODO: Use a dedicated instruction rather than VarStorage here.
context.AddInstAndPush<SemIR::VarStorage>(
node_id, {.type_id = type_id, .name_id = SemIR::NameId::ReturnSlot});
auto return_slot_id = context.AddPatternInst<SemIR::ReturnSlotPattern>(
node_id, {.type_id = type_id, .type_inst_id = type_inst_id});
// TODO: Use a separate inst kind here and for the corresponding Param,
// to capture the fact that the corresponding Param is not a value expression.
auto param_pattern_id = context.AddPatternInst<SemIR::ParamPattern>(
node_id, {.type_id = type_id,
.subpattern_id = return_slot_id,
.runtime_index = SemIR::RuntimeParamIndex::Unknown});
context.node_stack().Push(node_id, param_pattern_id);
return true;
}
@@ -97,7 +103,7 @@ static auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
// Track the signature from the definition, so that IDs in the body
// match IDs in the signature.
prev_function.MergeDefinition(new_function);
prev_function.return_storage_id = new_function.return_storage_id;
prev_function.return_slot_id = new_function.return_slot_id;
}
if ((prev_import_ir_id.is_valid() && !new_is_import)) {
ReplacePrevInstForMerge(context, new_function.parent_scope_id,
@@ -170,14 +176,14 @@ static auto BuildFunctionDecl(Context& context,
Parse::AnyFunctionDeclId node_id,
bool is_definition)
-> std::pair<SemIR::FunctionId, SemIR::InstId> {
auto return_storage_id = SemIR::InstId::Invalid;
if (auto [return_node, maybe_return_storage_id] =
auto return_slot_pattern_id = SemIR::InstId::Invalid;
if (auto [return_node, maybe_return_slot_pattern_id] =
context.node_stack().PopWithNodeIdIf<Parse::NodeKind::ReturnType>();
maybe_return_storage_id) {
return_storage_id = *maybe_return_storage_id;
maybe_return_slot_pattern_id) {
return_slot_pattern_id = *maybe_return_slot_pattern_id;
}
auto name = PopNameComponent(context);
auto name = PopNameComponent(context, return_slot_pattern_id);
if (!name.params_id.is_valid()) {
context.TODO(node_id, "function with positional parameters");
name.params_id = SemIR::InstBlockId::Empty;
@@ -232,7 +238,7 @@ static auto BuildFunctionDecl(Context& context,
auto function_info =
SemIR::Function{{name_context.MakeEntityWithParamsBase(
name, decl_id, is_extern, introducer.extern_library)},
{.return_storage_id = return_storage_id,
{.return_slot_id = name.return_slot_id,
.virtual_modifier = virtual_modifier}};
if (is_definition) {
function_info.definition_id = decl_id;
@@ -332,7 +338,7 @@ static auto HandleFunctionDefinitionAfterSignature(
context.AddCurrentCodeBlockToFunction();
// Check the return type is complete.
CheckFunctionReturnType(context, function.return_storage_id, function,
CheckFunctionReturnType(context, function.return_slot_id, function,
SemIR::SpecificId::Invalid);
// Check the parameter types are complete.
@@ -397,7 +403,7 @@ auto HandleParseNode(Context& context, Parse::FunctionDefinitionId node_id)
// If the `}` of the function is reachable, reject if we need a return value
// and otherwise add an implicit `return;`.
if (context.is_current_position_reachable()) {
if (context.functions().Get(function_id).return_storage_id.is_valid()) {
if (context.functions().Get(function_id).return_slot_id.is_valid()) {
CARBON_DIAGNOSTIC(
MissingReturnStatement, Error,
"missing `return` at end of function with declared return type");