Switch GetNodeBlock and GetTypeBlock to return an ArrayRef (#3220)

This removes the risk of accidentally performing a vector copy when
calling these functions, and is a preparation step towards the new node
block allocation design.

This required changing how we build call expressions. Instead of
finishing the argument block and then later adding a return slot, we now
delay finishing the argument block and checking for conversions to
parameter types until after we've added the return slot to it.
This commit is contained in:
Richard Smith
2023-09-13 20:47:53 +00:00
committed by GitHub
parent a05018a6ba
commit d63fceff8e
8 changed files with 130 additions and 48 deletions
+35 -16
View File
@@ -69,6 +69,11 @@ auto Context::AddNodeToBlock(SemIR::NodeBlockId block, SemIR::Node node)
return semantics_ir_->AddNode(block, node);
}
auto Context::AddNodeIdToBlock(SemIR::NodeBlockId block, SemIR::NodeId node_id)
-> void {
semantics_ir_->AddNodeId(block, node_id);
}
auto Context::AddNodeAndPush(Parse::Node parse_node, SemIR::Node node) -> void {
auto node_id = AddNode(node);
node_stack_.Push(parse_node, node_id);
@@ -436,7 +441,8 @@ auto Context::HandleDiscardedExpression(SemIR::NodeId expr_id) -> void {
auto Context::ImplicitAsForArgs(Parse::Node call_parse_node,
SemIR::NodeBlockId arg_refs_id,
Parse::Node param_parse_node,
SemIR::NodeBlockId param_refs_id) -> bool {
SemIR::NodeBlockId param_refs_id,
bool has_return_slot) -> bool {
// If both arguments and parameters are empty, return quickly. Otherwise,
// we'll fetch both so that errors are consistent.
if (arg_refs_id == SemIR::NodeBlockId::Empty &&
@@ -444,8 +450,16 @@ auto Context::ImplicitAsForArgs(Parse::Node call_parse_node,
return true;
}
auto& arg_refs = semantics_ir_->GetNodeBlock(arg_refs_id);
const auto& param_refs = semantics_ir_->GetNodeBlock(param_refs_id);
auto arg_refs = semantics_ir_->GetNodeBlock(arg_refs_id);
auto param_refs = semantics_ir_->GetNodeBlock(param_refs_id);
if (has_return_slot) {
// There's no entry in the parameter block for the return slot, so ignore
// the corresponding entry in the argument block.
// TODO: Consider adding the return slot to the parameter list.
CARBON_CHECK(!arg_refs.empty()) << "missing return slot";
arg_refs = arg_refs.drop_back();
}
// If sizes mismatch, fail early.
if (arg_refs.size() != param_refs.size()) {
@@ -581,14 +595,23 @@ auto Context::ParamOrArgComma(bool for_args) -> void {
ParamOrArgSave(for_args);
}
auto Context::ParamOrArgEnd(bool for_args, Parse::NodeKind start_kind)
-> SemIR::NodeBlockId {
auto Context::ParamOrArgEndNoPop(bool for_args, Parse::NodeKind start_kind)
-> void {
if (parse_tree_->node_kind(node_stack_.PeekParseNode()) != start_kind) {
ParamOrArgSave(for_args);
}
}
auto Context::ParamOrArgPop() -> SemIR::NodeBlockId {
return params_or_args_stack_.Pop();
}
auto Context::ParamOrArgEnd(bool for_args, Parse::NodeKind start_kind)
-> SemIR::NodeBlockId {
ParamOrArgEndNoPop(for_args, start_kind);
return ParamOrArgPop();
}
auto Context::ParamOrArgSave(bool for_args) -> void {
auto [entry_parse_node, entry_node_id] =
node_stack_.PopExpressionWithParseNode();
@@ -601,9 +624,7 @@ auto Context::ParamOrArgSave(bool for_args) -> void {
}
// Save the param or arg ID.
auto& params_or_args =
semantics_ir_->GetNodeBlock(params_or_args_stack_.PeekForAdd());
params_or_args.push_back(entry_node_id);
AddNodeIdToBlock(params_or_args_stack_.PeekForAdd(), entry_node_id);
}
auto Context::CanonicalizeTypeImpl(
@@ -641,9 +662,9 @@ auto Context::CanonicalizeTypeImpl(
}
// Compute a fingerprint for a tuple type, for use as a key in a folding set.
static auto ProfileTupleType(const llvm::SmallVector<SemIR::TypeId>& type_ids,
static auto ProfileTupleType(llvm::ArrayRef<SemIR::TypeId> type_ids,
llvm::FoldingSetNodeID& canonical_id) -> void {
for (const auto& type_id : type_ids) {
for (auto type_id : type_ids) {
canonical_id.AddInteger(type_id.index);
}
}
@@ -739,18 +760,16 @@ auto Context::CanonicalizeStructType(Parse::Node parse_node,
}
auto Context::CanonicalizeTupleType(Parse::Node parse_node,
llvm::SmallVector<SemIR::TypeId>&& type_ids)
llvm::ArrayRef<SemIR::TypeId> type_ids)
-> SemIR::TypeId {
// Defer allocating a SemIR::TypeBlockId until we know this is a new type.
auto profile_tuple = [&](llvm::FoldingSetNodeID& canonical_id) {
ProfileTupleType(type_ids, canonical_id);
};
auto make_tuple_node = [&] {
auto type_block_id = semantics_ir_->AddTypeBlock();
auto& type_block = semantics_ir_->GetTypeBlock(type_block_id);
type_block = std::move(type_ids);
return AddNode(SemIR::Node::TupleType::Make(
parse_node, SemIR::TypeId::TypeType, type_block_id));
return AddNode(
SemIR::Node::TupleType::Make(parse_node, SemIR::TypeId::TypeType,
semantics_ir_->AddTypeBlock(type_ids)));
};
return CanonicalizeTypeImpl(SemIR::NodeKind::TupleType, profile_tuple,
make_tuple_node);