mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 10:01:06 +01:00
Refactor ReturnTypeInfo and InitRepr. (#4169)
Rename `ReturnInfo` to `ReturnTypeInfo`. Move it and `InitRepr` into `type_info.h` alongside `ValueRepr`. Replace `ReturnSlot` with `InitRepr`, and extend `InitRepr` to be able to represent the incomplete-type case instead of CHECK-failing. Remove `has_return_slot` from `InitRepr` and instead only provide that as part of `ReturnTypeInfo`.
This commit is contained in:
@@ -115,7 +115,7 @@ auto PerformCall(Context& context, Parse::NodeId node_id,
|
||||
|
||||
// If there is a return slot, build storage for the result.
|
||||
SemIR::InstId return_storage_id = SemIR::InstId::Invalid;
|
||||
SemIR::ReturnInfo return_info = [&] {
|
||||
SemIR::ReturnTypeInfo return_info = [&] {
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(IncompleteReturnTypeHere, Note,
|
||||
@@ -124,21 +124,23 @@ auto PerformCall(Context& context, Parse::NodeId node_id,
|
||||
});
|
||||
return CheckFunctionReturnType(context, callee_id, callable, specific_id);
|
||||
}();
|
||||
switch (return_info.return_slot) {
|
||||
case SemIR::ReturnSlot::Present:
|
||||
switch (return_info.init_repr.kind) {
|
||||
case SemIR::InitRepr::InPlace:
|
||||
// Tentatively put storage for a temporary in the function's return slot.
|
||||
// This will be replaced if necessary when we perform initialization.
|
||||
return_storage_id = context.AddInst<SemIR::TemporaryStorage>(
|
||||
node_id, {.type_id = return_info.type_id});
|
||||
break;
|
||||
case SemIR::ReturnSlot::Absent:
|
||||
case SemIR::InitRepr::None:
|
||||
// For functions with an implicit return type, the return type is the
|
||||
// empty tuple type.
|
||||
if (!return_info.type_id.is_valid()) {
|
||||
return_info.type_id = context.GetTupleType({});
|
||||
}
|
||||
break;
|
||||
case SemIR::ReturnSlot::Incomplete:
|
||||
case SemIR::InitRepr::ByCopy:
|
||||
break;
|
||||
case SemIR::InitRepr::Incomplete:
|
||||
// Don't form an initializing expression with an incomplete type.
|
||||
// CheckFunctionReturnType will have diagnosed this for us if needed.
|
||||
return_info.type_id = SemIR::TypeId::Error;
|
||||
|
||||
@@ -54,7 +54,8 @@ static auto FindReturnSlotForInitializer(SemIR::File& sem_ir,
|
||||
return init.dest_id;
|
||||
}
|
||||
case CARBON_KIND(SemIR::Call call): {
|
||||
if (!SemIR::GetInitRepr(sem_ir, call.type_id).has_return_slot()) {
|
||||
if (!SemIR::ReturnTypeInfo::ForType(sem_ir, call.type_id)
|
||||
.has_return_slot()) {
|
||||
return SemIR::InstId::Invalid;
|
||||
}
|
||||
if (!call.args_id.is_valid()) {
|
||||
@@ -332,7 +333,7 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
|
||||
bool is_init = target.is_initializer();
|
||||
ConversionTarget::Kind inner_kind =
|
||||
!is_init ? ConversionTarget::Value
|
||||
: SemIR::GetInitRepr(sem_ir, target.type_id).kind ==
|
||||
: SemIR::InitRepr::ForType(sem_ir, target.type_id).kind ==
|
||||
SemIR::InitRepr::InPlace
|
||||
? ConversionTarget::FullInitializer
|
||||
: ConversionTarget::Initializer;
|
||||
@@ -433,7 +434,7 @@ static auto ConvertStructToStructOrClass(Context& context,
|
||||
bool is_init = target.is_initializer();
|
||||
ConversionTarget::Kind inner_kind =
|
||||
!is_init ? ConversionTarget::Value
|
||||
: SemIR::GetInitRepr(sem_ir, target.type_id).kind ==
|
||||
: SemIR::InitRepr::ForType(sem_ir, target.type_id).kind ==
|
||||
SemIR::InitRepr::InPlace
|
||||
? ConversionTarget::FullInitializer
|
||||
: ConversionTarget::Initializer;
|
||||
@@ -734,9 +735,9 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
||||
if (value_cat == SemIR::ExprCategory::Initializing &&
|
||||
IsValidExprCategoryForConversionTarget(SemIR::ExprCategory::Value,
|
||||
target.kind) &&
|
||||
SemIR::GetInitRepr(sem_ir, value_type_id).kind ==
|
||||
SemIR::InitRepr::ForType(sem_ir, value_type_id).kind ==
|
||||
SemIR::InitRepr::ByCopy) {
|
||||
auto value_rep = SemIR::GetValueRepr(sem_ir, value_type_id);
|
||||
auto value_rep = SemIR::ValueRepr::ForType(sem_ir, value_type_id);
|
||||
if (value_rep.kind == SemIR::ValueRepr::Copy &&
|
||||
value_rep.type_id == value_type_id) {
|
||||
// The initializer produces an object representation by copy, and the
|
||||
@@ -890,7 +891,7 @@ static auto PerformCopy(Context& context, SemIR::InstId expr_id)
|
||||
|
||||
// TODO: Directly track on the value representation whether it's a copy of
|
||||
// the object representation.
|
||||
auto value_rep = SemIR::GetValueRepr(context.sem_ir(), type_id);
|
||||
auto value_rep = SemIR::ValueRepr::ForType(context.sem_ir(), type_id);
|
||||
if (value_rep.kind == SemIR::ValueRepr::Copy &&
|
||||
value_rep.aggregate_kind == SemIR::ValueRepr::NotAggregate &&
|
||||
value_rep.type_id == type_id) {
|
||||
@@ -1049,7 +1050,7 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
||||
|
||||
// Perform a final destination store, if necessary.
|
||||
if (target.kind == ConversionTarget::FullInitializer) {
|
||||
if (auto init_rep = SemIR::GetInitRepr(sem_ir, target.type_id);
|
||||
if (auto init_rep = SemIR::InitRepr::ForType(sem_ir, target.type_id);
|
||||
init_rep.kind == SemIR::InitRepr::ByCopy) {
|
||||
target.init_block->InsertHere();
|
||||
expr_id = context.AddInst<SemIR::InitializeFrom>(
|
||||
|
||||
@@ -73,12 +73,13 @@ auto CheckFunctionTypeMatches(Context& context,
|
||||
auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
|
||||
SemIR::Function& function,
|
||||
SemIR::SpecificId specific_id)
|
||||
-> SemIR::ReturnInfo {
|
||||
auto return_info = function.GetReturnInfo(context.sem_ir(), specific_id);
|
||||
-> SemIR::ReturnTypeInfo {
|
||||
auto return_info = SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(),
|
||||
function, specific_id);
|
||||
|
||||
// If we couldn't determine the return information due to the return type
|
||||
// being incomplete, try to complete it now.
|
||||
if (return_info.return_slot == SemIR::ReturnSlot::Incomplete) {
|
||||
if (return_info.init_repr.kind == SemIR::InitRepr::Incomplete) {
|
||||
auto diagnose_incomplete_return_type = [&] {
|
||||
CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error,
|
||||
"Function returns incomplete type `{0}`.",
|
||||
@@ -91,7 +92,8 @@ auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
|
||||
// definition or call to this function.
|
||||
if (context.TryToCompleteType(return_info.type_id,
|
||||
diagnose_incomplete_return_type)) {
|
||||
return_info = function.GetReturnInfo(context.sem_ir(), specific_id);
|
||||
return_info = SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(),
|
||||
function, specific_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ auto CheckFunctionTypeMatches(Context& context,
|
||||
auto CheckFunctionReturnType(Context& context, SemIRLoc loc,
|
||||
SemIR::Function& function,
|
||||
SemIR::SpecificId specific_id)
|
||||
-> SemIR::ReturnInfo;
|
||||
-> SemIR::ReturnTypeInfo;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ auto CheckReturnedVar(Context& context, Parse::NodeId returned_node,
|
||||
Parse::NodeId type_node, SemIR::TypeId type_id)
|
||||
-> SemIR::InstId {
|
||||
auto& function = GetCurrentFunction(context);
|
||||
auto return_info = function.GetReturnInfo(context.sem_ir());
|
||||
auto return_info =
|
||||
SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
|
||||
if (!return_info.is_valid()) {
|
||||
// We already diagnosed this when we started defining the function. Create a
|
||||
// placeholder for error recovery.
|
||||
@@ -131,7 +132,8 @@ auto BuildReturnWithExpr(Context& context, Parse::ReturnStatementId node_id,
|
||||
const auto& function = GetCurrentFunction(context);
|
||||
auto returned_var_id = GetCurrentReturnedVar(context);
|
||||
auto return_slot_id = SemIR::InstId::Invalid;
|
||||
auto return_info = function.GetReturnInfo(context.sem_ir());
|
||||
auto return_info =
|
||||
SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
|
||||
|
||||
if (!return_info.type_id.is_valid()) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
@@ -178,7 +180,8 @@ auto BuildReturnVar(Context& context, Parse::ReturnStatementId node_id)
|
||||
}
|
||||
|
||||
auto return_slot_id = function.return_storage_id;
|
||||
if (!function.GetReturnInfo(context.sem_ir()).has_return_slot()) {
|
||||
if (!SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function)
|
||||
.has_return_slot()) {
|
||||
// If we don't have a return slot, we're returning by value. Convert to a
|
||||
// value expression.
|
||||
returned_var_id = ConvertToValueExpr(context, returned_var_id);
|
||||
|
||||
@@ -82,7 +82,7 @@ auto FileContext::GetGlobal(SemIR::InstId inst_id) -> llvm::Value* {
|
||||
// If we want a pointer to the constant, materialize a global to hold it.
|
||||
// TODO: We could reuse the same global if the constant is used more than
|
||||
// once.
|
||||
auto value_rep = SemIR::GetValueRepr(sem_ir(), inst.type_id());
|
||||
auto value_rep = SemIR::ValueRepr::ForType(sem_ir(), inst.type_id());
|
||||
if (value_rep.kind == SemIR::ValueRepr::Pointer) {
|
||||
// Include both the name of the constant, if any, and the point of use in
|
||||
// the name of the variable.
|
||||
@@ -143,7 +143,8 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id)
|
||||
// TODO: Pass in a specific ID for generic functions.
|
||||
const auto specific_id = SemIR::SpecificId::Invalid;
|
||||
|
||||
const auto return_info = function.GetReturnInfo(sem_ir(), specific_id);
|
||||
const auto return_info =
|
||||
SemIR::ReturnTypeInfo::ForFunction(sem_ir(), function, specific_id);
|
||||
CARBON_CHECK(return_info.is_valid()) << "Should not lower invalid functions.";
|
||||
|
||||
auto implicit_param_refs =
|
||||
@@ -153,11 +154,6 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id)
|
||||
|
||||
auto* return_type =
|
||||
return_info.type_id.is_valid() ? GetType(return_info.type_id) : nullptr;
|
||||
SemIR::InitRepr return_rep =
|
||||
return_info.type_id.is_valid()
|
||||
? SemIR::GetInitRepr(sem_ir(), return_info.type_id)
|
||||
: SemIR::InitRepr{.kind = SemIR::InitRepr::None};
|
||||
CARBON_CHECK(return_rep.has_return_slot() == return_info.has_return_slot());
|
||||
|
||||
llvm::SmallVector<llvm::Type*> param_types;
|
||||
// TODO: Consider either storing `param_inst_ids` somewhere so that we can
|
||||
@@ -178,7 +174,7 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id)
|
||||
auto param_type_id =
|
||||
SemIR::Function::GetParamFromParamRefId(sem_ir(), param_ref_id)
|
||||
.second.type_id;
|
||||
switch (auto value_rep = SemIR::GetValueRepr(sem_ir(), param_type_id);
|
||||
switch (auto value_rep = SemIR::ValueRepr::ForType(sem_ir(), param_type_id);
|
||||
value_rep.kind) {
|
||||
case SemIR::ValueRepr::Unknown:
|
||||
CARBON_FATAL()
|
||||
@@ -197,7 +193,7 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id)
|
||||
// Compute the return type to use for the LLVM function. If the initializing
|
||||
// representation doesn't produce a value, set the return type to void.
|
||||
llvm::Type* function_return_type =
|
||||
return_rep.kind == SemIR::InitRepr::ByCopy
|
||||
return_info.init_repr.kind == SemIR::InitRepr::ByCopy
|
||||
? return_type
|
||||
: llvm::Type::getVoidTy(llvm_context());
|
||||
|
||||
@@ -267,7 +263,8 @@ auto FileContext::BuildFunctionDefinition(SemIR::FunctionId function_id)
|
||||
sem_ir().inst_blocks().GetOrEmpty(function.implicit_param_refs_id);
|
||||
auto param_refs = sem_ir().inst_blocks().GetOrEmpty(function.param_refs_id);
|
||||
int param_index = 0;
|
||||
if (function.GetReturnInfo(sem_ir(), specific_id).has_return_slot()) {
|
||||
if (SemIR::ReturnTypeInfo::ForFunction(sem_ir(), function, specific_id)
|
||||
.has_return_slot()) {
|
||||
function_lowering.SetLocal(function.return_storage_id,
|
||||
llvm_function->getArg(param_index));
|
||||
++param_index;
|
||||
@@ -280,7 +277,7 @@ auto FileContext::BuildFunctionDefinition(SemIR::FunctionId function_id)
|
||||
// Get the value of the parameter from the function argument.
|
||||
auto param_type_id = param.type_id;
|
||||
llvm::Value* param_value = llvm::PoisonValue::get(GetType(param_type_id));
|
||||
if (SemIR::GetValueRepr(sem_ir(), param_type_id).kind !=
|
||||
if (SemIR::ValueRepr::ForType(sem_ir(), param_type_id).kind !=
|
||||
SemIR::ValueRepr::None) {
|
||||
param_value = llvm_function->getArg(param_index);
|
||||
++param_index;
|
||||
|
||||
@@ -133,7 +133,7 @@ auto FunctionContext::MakeSyntheticBlock() -> llvm::BasicBlock* {
|
||||
|
||||
auto FunctionContext::FinishInit(SemIR::TypeId type_id, SemIR::InstId dest_id,
|
||||
SemIR::InstId source_id) -> void {
|
||||
switch (SemIR::GetInitRepr(sem_ir(), type_id).kind) {
|
||||
switch (SemIR::InitRepr::ForType(sem_ir(), type_id).kind) {
|
||||
case SemIR::InitRepr::None:
|
||||
break;
|
||||
case SemIR::InitRepr::InPlace:
|
||||
@@ -146,12 +146,15 @@ auto FunctionContext::FinishInit(SemIR::TypeId type_id, SemIR::InstId dest_id,
|
||||
case SemIR::InitRepr::ByCopy:
|
||||
CopyValue(type_id, source_id, dest_id);
|
||||
break;
|
||||
case SemIR::InitRepr::Incomplete:
|
||||
CARBON_FATAL() << "Lowering aggregate initialization of incomplete type "
|
||||
<< sem_ir().types().GetAsInst(type_id);
|
||||
}
|
||||
}
|
||||
|
||||
auto FunctionContext::CopyValue(SemIR::TypeId type_id, SemIR::InstId source_id,
|
||||
SemIR::InstId dest_id) -> void {
|
||||
switch (auto rep = SemIR::GetValueRepr(sem_ir(), type_id); rep.kind) {
|
||||
switch (auto rep = SemIR::ValueRepr::ForType(sem_ir(), type_id); rep.kind) {
|
||||
case SemIR::ValueRepr::Unknown:
|
||||
CARBON_FATAL() << "Attempt to copy incomplete type";
|
||||
case SemIR::ValueRepr::None:
|
||||
|
||||
@@ -194,7 +194,7 @@ auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
|
||||
auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
|
||||
SemIR::ReturnExpr inst) -> void {
|
||||
auto result_type_id = context.sem_ir().insts().Get(inst.expr_id).type_id();
|
||||
switch (SemIR::GetInitRepr(context.sem_ir(), result_type_id).kind) {
|
||||
switch (SemIR::InitRepr::ForType(context.sem_ir(), result_type_id).kind) {
|
||||
case SemIR::InitRepr::None:
|
||||
// Nothing to return.
|
||||
context.builder().CreateRetVoid();
|
||||
@@ -207,6 +207,9 @@ auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
|
||||
// The expression produces the value representation for the type.
|
||||
context.builder().CreateRet(context.GetValue(inst.expr_id));
|
||||
return;
|
||||
case SemIR::InitRepr::Incomplete:
|
||||
CARBON_FATAL() << "Lowering return of incomplete type "
|
||||
<< context.sem_ir().types().GetAsInst(result_type_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ static auto GetAggregateElement(FunctionContext& context,
|
||||
|
||||
case SemIR::ExprCategory::Value: {
|
||||
auto value_rep =
|
||||
SemIR::GetValueRepr(context.sem_ir(), aggr_inst.type_id());
|
||||
SemIR::ValueRepr::ForType(context.sem_ir(), aggr_inst.type_id());
|
||||
CARBON_CHECK(value_rep.aggregate_kind != SemIR::ValueRepr::NotAggregate)
|
||||
<< "aggregate type should have aggregate value representation";
|
||||
switch (value_rep.kind) {
|
||||
@@ -67,7 +67,8 @@ static auto GetAggregateElement(FunctionContext& context,
|
||||
|
||||
// `elem_ptr` points to a value representation. Load it.
|
||||
auto result_value_type_id =
|
||||
SemIR::GetValueRepr(context.sem_ir(), result_type_id).type_id;
|
||||
SemIR::ValueRepr::ForType(context.sem_ir(), result_type_id)
|
||||
.type_id;
|
||||
return context.builder().CreateLoad(
|
||||
context.GetType(result_value_type_id), elem_ptr, name + ".load");
|
||||
}
|
||||
@@ -123,7 +124,7 @@ static auto EmitAggregateInitializer(FunctionContext& context,
|
||||
llvm::Twine name) -> llvm::Value* {
|
||||
auto* llvm_type = context.GetType(type_id);
|
||||
|
||||
switch (SemIR::GetInitRepr(context.sem_ir(), type_id).kind) {
|
||||
switch (SemIR::InitRepr::ForType(context.sem_ir(), type_id).kind) {
|
||||
case SemIR::InitRepr::None:
|
||||
case SemIR::InitRepr::InPlace:
|
||||
// TODO: Add a helper to poison a value slot.
|
||||
@@ -139,6 +140,10 @@ static auto EmitAggregateInitializer(FunctionContext& context,
|
||||
llvm::PoisonValue::get(llvm_type), context.GetValue(refs[0]), {0},
|
||||
name);
|
||||
}
|
||||
|
||||
case SemIR::InitRepr::Incomplete:
|
||||
CARBON_FATAL() << "Lowering aggregate initialization of incomplete type "
|
||||
<< context.sem_ir().types().GetAsInst(type_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +174,7 @@ auto HandleInst(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
|
||||
static auto EmitAggregateValueRepr(FunctionContext& context,
|
||||
SemIR::TypeId type_id,
|
||||
SemIR::InstBlockId refs_id) -> llvm::Value* {
|
||||
auto value_rep = SemIR::GetValueRepr(context.sem_ir(), type_id);
|
||||
auto value_rep = SemIR::ValueRepr::ForType(context.sem_ir(), type_id);
|
||||
switch (value_rep.kind) {
|
||||
case SemIR::ValueRepr::Unknown:
|
||||
CARBON_FATAL() << "Incomplete aggregate type in lowering";
|
||||
|
||||
@@ -312,14 +312,15 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
|
||||
|
||||
std::vector<llvm::Value*> args;
|
||||
|
||||
if (SemIR::GetInitRepr(context.sem_ir(), inst.type_id).has_return_slot()) {
|
||||
if (SemIR::ReturnTypeInfo::ForType(context.sem_ir(), inst.type_id)
|
||||
.has_return_slot()) {
|
||||
args.push_back(context.GetValue(arg_ids.back()));
|
||||
arg_ids = arg_ids.drop_back();
|
||||
}
|
||||
|
||||
for (auto arg_id : arg_ids) {
|
||||
auto arg_type_id = context.sem_ir().insts().Get(arg_id).type_id();
|
||||
if (SemIR::GetValueRepr(context.sem_ir(), arg_type_id).kind !=
|
||||
if (SemIR::ValueRepr::ForType(context.sem_ir(), arg_type_id).kind !=
|
||||
SemIR::ValueRepr::None) {
|
||||
args.push_back(context.GetValue(arg_id));
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Carbon::Lower {
|
||||
|
||||
auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
|
||||
SemIR::BindValue inst) -> void {
|
||||
switch (auto rep = SemIR::GetValueRepr(context.sem_ir(), inst.type_id);
|
||||
switch (auto rep = SemIR::ValueRepr::ForType(context.sem_ir(), inst.type_id);
|
||||
rep.kind) {
|
||||
case SemIR::ValueRepr::Unknown:
|
||||
CARBON_FATAL()
|
||||
@@ -51,7 +51,7 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
|
||||
SemIR::ValueAsRef inst) -> void {
|
||||
CARBON_CHECK(SemIR::GetExprCategory(context.sem_ir(), inst.value_id) ==
|
||||
SemIR::ExprCategory::Value);
|
||||
CARBON_CHECK(SemIR::GetValueRepr(context.sem_ir(), inst.type_id).kind ==
|
||||
CARBON_CHECK(SemIR::ValueRepr::ForType(context.sem_ir(), inst.type_id).kind ==
|
||||
SemIR::ValueRepr::Pointer);
|
||||
context.SetLocal(inst_id, context.GetValue(inst.value_id));
|
||||
}
|
||||
@@ -60,9 +60,9 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
|
||||
SemIR::ValueOfInitializer inst) -> void {
|
||||
CARBON_CHECK(SemIR::GetExprCategory(context.sem_ir(), inst.init_id) ==
|
||||
SemIR::ExprCategory::Initializing);
|
||||
CARBON_CHECK(SemIR::GetValueRepr(context.sem_ir(), inst.type_id).kind ==
|
||||
CARBON_CHECK(SemIR::ValueRepr::ForType(context.sem_ir(), inst.type_id).kind ==
|
||||
SemIR::ValueRepr::Copy);
|
||||
CARBON_CHECK(SemIR::GetInitRepr(context.sem_ir(), inst.type_id).kind ==
|
||||
CARBON_CHECK(SemIR::InitRepr::ForType(context.sem_ir(), inst.type_id).kind ==
|
||||
SemIR::InitRepr::ByCopy);
|
||||
context.SetLocal(inst_id, context.GetValue(inst.init_id));
|
||||
}
|
||||
|
||||
+3
-11
@@ -88,6 +88,7 @@ cc_library(
|
||||
"function.cpp",
|
||||
"generic.cpp",
|
||||
"name.cpp",
|
||||
"type_info.cpp",
|
||||
],
|
||||
hdrs = [
|
||||
"builtin_function_kind.h",
|
||||
@@ -105,6 +106,7 @@ cc_library(
|
||||
"name.h",
|
||||
"name_scope.h",
|
||||
"type.h",
|
||||
"type_info.h",
|
||||
],
|
||||
textual_hdrs = [
|
||||
"builtin_function_kind.def",
|
||||
@@ -115,12 +117,12 @@ cc_library(
|
||||
":ids",
|
||||
":inst",
|
||||
":inst_kind",
|
||||
":type_info",
|
||||
"//common:check",
|
||||
"//common:enum_base",
|
||||
"//common:error",
|
||||
"//common:hashing",
|
||||
"//common:map",
|
||||
"//common:ostream",
|
||||
"//common:set",
|
||||
"//toolchain/base:kind_switch",
|
||||
"//toolchain/base:value_store",
|
||||
@@ -176,16 +178,6 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "type_info",
|
||||
hdrs = ["type_info.h"],
|
||||
deps = [
|
||||
":ids",
|
||||
":inst",
|
||||
"//common:ostream",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "typed_insts_test",
|
||||
size = "small",
|
||||
|
||||
@@ -19,32 +19,6 @@
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
auto ValueRepr::Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{kind: ";
|
||||
switch (kind) {
|
||||
case Unknown:
|
||||
out << "unknown";
|
||||
break;
|
||||
case None:
|
||||
out << "none";
|
||||
break;
|
||||
case Copy:
|
||||
out << "copy";
|
||||
break;
|
||||
case Pointer:
|
||||
out << "pointer";
|
||||
break;
|
||||
case Custom:
|
||||
out << "custom";
|
||||
break;
|
||||
}
|
||||
out << ", type: " << type_id << "}";
|
||||
}
|
||||
|
||||
auto CompleteTypeInfo::Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{value_rep: " << value_repr << "}";
|
||||
}
|
||||
|
||||
File::File(CheckIRId check_ir_id, IdentifierId package_id,
|
||||
StringLiteralValueId library_id, SharedValueStores& value_stores,
|
||||
std::string filename)
|
||||
@@ -690,26 +664,4 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
|
||||
}
|
||||
}
|
||||
|
||||
auto GetInitRepr(const File& file, TypeId type_id) -> InitRepr {
|
||||
auto value_rep = GetValueRepr(file, type_id);
|
||||
switch (value_rep.kind) {
|
||||
case ValueRepr::None:
|
||||
return {.kind = InitRepr::None};
|
||||
|
||||
case ValueRepr::Copy:
|
||||
// TODO: Use in-place initialization for types that have non-trivial
|
||||
// destructive move.
|
||||
return {.kind = InitRepr::ByCopy};
|
||||
|
||||
case ValueRepr::Pointer:
|
||||
case ValueRepr::Custom:
|
||||
return {.kind = InitRepr::InPlace};
|
||||
|
||||
case ValueRepr::Unknown:
|
||||
CARBON_FATAL()
|
||||
<< "Attempting to perform initialization of incomplete type "
|
||||
<< file.types().GetAsInst(type_id);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
@@ -282,37 +282,6 @@ enum class ExprCategory : int8_t {
|
||||
// Returns the expression category for an instruction.
|
||||
auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory;
|
||||
|
||||
// Returns information about the value representation to use for a type.
|
||||
inline auto GetValueRepr(const File& file, TypeId type_id) -> ValueRepr {
|
||||
return file.types().GetValueRepr(type_id);
|
||||
}
|
||||
|
||||
// The initializing representation to use when returning by value.
|
||||
struct InitRepr {
|
||||
enum Kind : int8_t {
|
||||
// The type has no initializing representation. This is used for empty
|
||||
// types, where no initialization is necessary.
|
||||
None,
|
||||
// An initializing expression produces an object representation by value,
|
||||
// which is copied into the initialized object.
|
||||
ByCopy,
|
||||
// An initializing expression takes a location as input, which is
|
||||
// initialized as a side effect of evaluating the expression.
|
||||
InPlace,
|
||||
// TODO: Consider adding a kind where the expression takes an advisory
|
||||
// location and returns a value plus an indicator of whether the location
|
||||
// was actually initialized.
|
||||
};
|
||||
// The kind of initializing representation used by this type.
|
||||
Kind kind;
|
||||
|
||||
// Returns whether a return slot is used when returning this type.
|
||||
auto has_return_slot() const -> bool { return kind == InPlace; }
|
||||
};
|
||||
|
||||
// Returns information about the initializing representation to use for a type.
|
||||
auto GetInitRepr(const File& file, TypeId type_id) -> InitRepr;
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_SEM_IR_FILE_H_
|
||||
|
||||
@@ -306,7 +306,7 @@ class FormatterImpl {
|
||||
|
||||
if (fn.return_storage_id.is_valid()) {
|
||||
out_ << " -> ";
|
||||
auto return_info = fn.GetReturnInfo(sem_ir_);
|
||||
auto return_info = ReturnTypeInfo::ForFunction(sem_ir_, fn);
|
||||
if (!fn.body_block_ids.empty() && return_info.is_valid() &&
|
||||
return_info.has_return_slot()) {
|
||||
FormatName(fn.return_storage_id);
|
||||
@@ -712,7 +712,7 @@ class FormatterImpl {
|
||||
|
||||
llvm::ArrayRef<InstId> args = sem_ir_.inst_blocks().Get(inst.args_id);
|
||||
|
||||
auto return_info = ReturnInfo::ForType(sem_ir_, inst.type_id);
|
||||
auto return_info = ReturnTypeInfo::ForType(sem_ir_, inst.type_id);
|
||||
bool has_return_slot = return_info.has_return_slot();
|
||||
InstId return_slot_id = InstId::Invalid;
|
||||
if (has_return_slot) {
|
||||
|
||||
@@ -68,20 +68,4 @@ auto Function::GetDeclaredReturnType(const File& file,
|
||||
file.insts().Get(return_storage_id).type_id());
|
||||
}
|
||||
|
||||
auto ReturnInfo::ForType(const File& file, TypeId type_id) -> ReturnInfo {
|
||||
if (!type_id.is_valid()) {
|
||||
// Implicit `-> ()` has no return slot.
|
||||
return {.type_id = type_id, .return_slot = ReturnSlot::Absent};
|
||||
}
|
||||
|
||||
if (!file.types().IsComplete(type_id)) {
|
||||
return {.type_id = type_id, .return_slot = ReturnSlot::Incomplete};
|
||||
}
|
||||
|
||||
return {.type_id = type_id,
|
||||
.return_slot = GetInitRepr(file, type_id).has_return_slot()
|
||||
? SemIR::ReturnSlot::Present
|
||||
: SemIR::ReturnSlot::Absent};
|
||||
}
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
@@ -12,41 +12,6 @@
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
// A value that describes whether the function uses a return slot.
|
||||
enum class ReturnSlot : int8_t {
|
||||
// The function is known to not use a return slot.
|
||||
Absent,
|
||||
// The function has a return slot, and a call to the function is expected to
|
||||
// have an additional final argument corresponding to the return slot.
|
||||
Present,
|
||||
// Computing whether the function should have a return slot failed because
|
||||
// the return type was incomplete.
|
||||
Incomplete,
|
||||
};
|
||||
|
||||
// Information about how a function returns its return value.
|
||||
struct ReturnInfo {
|
||||
// Builds return information for a given declared return type.
|
||||
static auto ForType(const File& file, TypeId type_id) -> ReturnInfo;
|
||||
|
||||
// Returns whether the return information could be fully computed.
|
||||
auto is_valid() const -> bool {
|
||||
return return_slot != ReturnSlot::Incomplete;
|
||||
}
|
||||
|
||||
// Returns whether the function has a return slot. Can only be called for
|
||||
// valid return info.
|
||||
auto has_return_slot() const -> bool {
|
||||
CARBON_CHECK(is_valid());
|
||||
return return_slot == ReturnSlot::Present;
|
||||
}
|
||||
|
||||
// The return type. Invalid if no return type was specified.
|
||||
TypeId type_id;
|
||||
// The return slot usage for this function.
|
||||
ReturnSlot return_slot;
|
||||
};
|
||||
|
||||
// Function-specific fields.
|
||||
struct FunctionFields {
|
||||
// The following members always have values, and do not change throughout the
|
||||
@@ -107,13 +72,6 @@ struct Function : public EntityWithParamsBase,
|
||||
auto GetDeclaredReturnType(const File& file,
|
||||
SpecificId specific_id = SpecificId::Invalid) const
|
||||
-> TypeId;
|
||||
|
||||
// Returns information about how the function returns its return value.
|
||||
auto GetReturnInfo(const File& file,
|
||||
SpecificId specific_id = SpecificId::Invalid) const
|
||||
-> ReturnInfo {
|
||||
return ReturnInfo::ForType(file, GetDeclaredReturnType(file, specific_id));
|
||||
}
|
||||
};
|
||||
|
||||
class File;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/sem_ir/type_info.h"
|
||||
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
auto ValueRepr::Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{kind: ";
|
||||
switch (kind) {
|
||||
case Unknown:
|
||||
out << "unknown";
|
||||
break;
|
||||
case None:
|
||||
out << "none";
|
||||
break;
|
||||
case Copy:
|
||||
out << "copy";
|
||||
break;
|
||||
case Pointer:
|
||||
out << "pointer";
|
||||
break;
|
||||
case Custom:
|
||||
out << "custom";
|
||||
break;
|
||||
}
|
||||
out << ", type: " << type_id << "}";
|
||||
}
|
||||
|
||||
auto CompleteTypeInfo::Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{value_rep: " << value_repr << "}";
|
||||
}
|
||||
|
||||
auto ValueRepr::ForType(const File& file, TypeId type_id) -> ValueRepr {
|
||||
return file.types().GetValueRepr(type_id);
|
||||
}
|
||||
|
||||
auto InitRepr::ForType(const File& file, TypeId type_id) -> InitRepr {
|
||||
auto value_rep = ValueRepr::ForType(file, type_id);
|
||||
switch (value_rep.kind) {
|
||||
case ValueRepr::None:
|
||||
return {.kind = InitRepr::None};
|
||||
|
||||
case ValueRepr::Copy:
|
||||
// TODO: Use in-place initialization for types that have non-trivial
|
||||
// destructive move.
|
||||
return {.kind = InitRepr::ByCopy};
|
||||
|
||||
case ValueRepr::Pointer:
|
||||
case ValueRepr::Custom:
|
||||
return {.kind = InitRepr::InPlace};
|
||||
|
||||
case ValueRepr::Unknown:
|
||||
return {.kind = InitRepr::Incomplete};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
@@ -6,12 +6,16 @@
|
||||
#define CARBON_TOOLCHAIN_SEM_IR_TYPE_INFO_H_
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
// The value representation to use when passing by value.
|
||||
struct ValueRepr : public Printable<ValueRepr> {
|
||||
// Returns information about the value representation to use for a type.
|
||||
static auto ForType(const File& file, TypeId type_id) -> ValueRepr;
|
||||
|
||||
auto Print(llvm::raw_ostream& out) const -> void;
|
||||
|
||||
enum Kind : int8_t {
|
||||
@@ -71,6 +75,69 @@ struct CompleteTypeInfo : public Printable<CompleteTypeInfo> {
|
||||
ValueRepr value_repr = ValueRepr();
|
||||
};
|
||||
|
||||
// The initializing representation to use when returning by value.
|
||||
struct InitRepr {
|
||||
// Returns information about the initializing representation to use for a
|
||||
// type.
|
||||
static auto ForType(const File& file, TypeId type_id) -> InitRepr;
|
||||
|
||||
enum Kind : int8_t {
|
||||
// The type has no initializing representation. This is used for empty
|
||||
// types, where no initialization is necessary.
|
||||
None,
|
||||
// An initializing expression produces an object representation by value,
|
||||
// which is copied into the initialized object.
|
||||
ByCopy,
|
||||
// An initializing expression takes a location as input, which is
|
||||
// initialized as a side effect of evaluating the expression.
|
||||
InPlace,
|
||||
// No initializing expressions should exist because the type is not
|
||||
// complete.
|
||||
Incomplete,
|
||||
// TODO: Consider adding a kind where the expression takes an advisory
|
||||
// location and returns a value plus an indicator of whether the location
|
||||
// was actually initialized.
|
||||
};
|
||||
// The kind of initializing representation used by this type.
|
||||
Kind kind;
|
||||
|
||||
// Returns whether the initializing representation information could be fully
|
||||
// computed.
|
||||
auto is_valid() const -> bool { return kind != Incomplete; }
|
||||
};
|
||||
|
||||
// Information about a function's return type.
|
||||
struct ReturnTypeInfo {
|
||||
// Builds return type information for a given declared return type.
|
||||
static auto ForType(const File& file, TypeId type_id) -> ReturnTypeInfo {
|
||||
return {.type_id = type_id,
|
||||
.init_repr = type_id.is_valid() ? InitRepr::ForType(file, type_id)
|
||||
: InitRepr{.kind = InitRepr::None}};
|
||||
}
|
||||
|
||||
// Builds return type information for a given function.
|
||||
static auto ForFunction(const File& file, const Function& function,
|
||||
SpecificId specific_id = SpecificId::Invalid)
|
||||
-> ReturnTypeInfo {
|
||||
return ForType(file, function.GetDeclaredReturnType(file, specific_id));
|
||||
}
|
||||
|
||||
// Returns whether the return information could be fully computed.
|
||||
auto is_valid() const -> bool { return init_repr.is_valid(); }
|
||||
|
||||
// Returns whether a function with this return type has a return slot. Can
|
||||
// only be called for valid return info.
|
||||
auto has_return_slot() const -> bool {
|
||||
CARBON_CHECK(is_valid());
|
||||
return init_repr.kind == InitRepr::InPlace;
|
||||
}
|
||||
|
||||
// The declared return type. Invalid if no return type was specified.
|
||||
TypeId type_id;
|
||||
// The initializing representation for the return type.
|
||||
InitRepr init_repr;
|
||||
};
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_SEM_IR_TYPE_INFO_H_
|
||||
|
||||
Reference in New Issue
Block a user