mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 18:41:03 +01:00
Allow incomplete return types in function declarations. (#3875)
Move completeness check to the point where the function is defined or first called. This means we also defer deciding whether the function has a return slot until that point. Instead of storing a return slot per function, store the location of the return storage, which may or may not be used, and compute and store a separate flag saying whether to use it at the point of first use or definition. This is the final piece in supporting simple `Make` functions in classes as a replacement for constructors.
This commit is contained in:
@@ -294,6 +294,28 @@ static auto CheckIsAllowedRedecl(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the return slot usage for a function given the computed usage for two
|
||||
// different declarations of the function.
|
||||
static auto MergeReturnSlot(SemIR::Function::ReturnSlot a,
|
||||
SemIR::Function::ReturnSlot b)
|
||||
-> SemIR::Function::ReturnSlot {
|
||||
if (a == SemIR::Function::ReturnSlot::NotComputed) {
|
||||
return b;
|
||||
}
|
||||
if (b == SemIR::Function::ReturnSlot::NotComputed) {
|
||||
return a;
|
||||
}
|
||||
if (a == SemIR::Function::ReturnSlot::Error) {
|
||||
return b;
|
||||
}
|
||||
if (b == SemIR::Function::ReturnSlot::Error) {
|
||||
return a;
|
||||
}
|
||||
CARBON_CHECK(a == b)
|
||||
<< "Different return slot usage computed for the same function.";
|
||||
return a;
|
||||
}
|
||||
|
||||
auto MergeFunctionRedecl(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::Function& new_function, bool new_is_import,
|
||||
bool new_is_definition,
|
||||
@@ -315,8 +337,11 @@ auto MergeFunctionRedecl(Context& context, SemIR::LocId loc_id,
|
||||
prev_function.implicit_param_refs_id = new_function.implicit_param_refs_id;
|
||||
prev_function.param_refs_id = new_function.param_refs_id;
|
||||
prev_function.return_type_id = new_function.return_type_id;
|
||||
prev_function.return_slot_id = new_function.return_slot_id;
|
||||
prev_function.return_storage_id = new_function.return_storage_id;
|
||||
}
|
||||
// The new function might have return slot information if it was imported.
|
||||
prev_function.return_slot =
|
||||
MergeReturnSlot(prev_function.return_slot, new_function.return_slot);
|
||||
if ((prev_import_ir_inst_id.is_valid() && !new_is_import) ||
|
||||
(prev_function.is_extern && !new_function.is_extern)) {
|
||||
prev_function.is_extern = new_function.is_extern;
|
||||
@@ -327,4 +352,39 @@ auto MergeFunctionRedecl(Context& context, SemIR::LocId loc_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
|
||||
SemIR::Function& function) -> void {
|
||||
// If we have already checked the return type, we have nothing to do.
|
||||
if (function.return_slot != SemIR::Function::ReturnSlot::NotComputed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!function.return_type_id.is_valid()) {
|
||||
// Implicit `-> ()` has no return slot.
|
||||
function.return_slot = SemIR::Function::ReturnSlot::Absent;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the return type is complete. Only diagnose incompleteness if we've
|
||||
// not already done so.
|
||||
auto diagnose_incomplete_return_type = [&] {
|
||||
CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error,
|
||||
"Function returns incomplete type `{0}`.", SemIR::TypeId);
|
||||
return context.emitter().Build(loc, IncompleteTypeInFunctionReturnType,
|
||||
function.return_type_id);
|
||||
};
|
||||
if (!context.TryToCompleteType(
|
||||
function.return_type_id,
|
||||
function.return_slot == SemIR::Function::ReturnSlot::Error
|
||||
? std::nullopt
|
||||
: std::optional(diagnose_incomplete_return_type))) {
|
||||
function.return_slot = SemIR::Function::ReturnSlot::Error;
|
||||
} else if (SemIR::GetInitRepr(context.sem_ir(), function.return_type_id)
|
||||
.has_return_slot()) {
|
||||
function.return_slot = SemIR::Function::ReturnSlot::Present;
|
||||
} else {
|
||||
function.return_slot = SemIR::Function::ReturnSlot::Absent;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
Reference in New Issue
Block a user