Store SemanticsNode in a single list instead of per-block (#2475)

This switches to single list storage of SemanticsNode. The driving motivation behind this is to simplify cross-references within a given IR. Types of nodes will frequently refer to other blocks. This causes a significant increase in the number of cross-references, which can become difficult to manage (and reason about). By reducing to a single list of nodes, cross-references are only needed when crossing IR boundaries.

Because cross-references now only have 2 things to track (IR and index), they can be a regular SemanticsNode and don't need further indirection. This wasn't motivating, but feels like it reinforces the simplification.

Note this isn't being used to deduplicate nodes, at least right now. That could lead to difficult-to-update situations, but also most nodes are associated with the underlying ParseTree::Node in order to track sources for diagnostics; as a consequence, nodes representing equal text in different source locations wouldn't be the same node. There may be future opportunities here, discussed with @zygoloid, but no action is taken at present.

We may eventually want to switch the storage of NodeBlocks to have `[start, end)` ranges instead of individual numbers, but I'm leaving that alone for now.

As an aside, I noticed I was accidentally overloading the copy constructor on SemanticsIR. I've added some disambiguation on that, but am not deleting the copy constructor per style advice (even though the type should never be copied due to storage size).

codespell tries to change `CrossReference -> cross-reference` so disabling it there.
This commit is contained in:
Jon Ross-Perkins
2022-12-21 13:13:13 -08:00
committed by GitHub
parent 34ec3ce74b
commit e5d49f5989
31 changed files with 495 additions and 482 deletions
@@ -86,15 +86,6 @@ auto SemanticsParseTreeHandler::Build() -> void {
CARBON_CHECK(scope_stack_.empty()) << scope_stack_.size();
}
auto SemanticsParseTreeHandler::AddCrossReference(SemanticsNodeId node_id)
-> SemanticsNodeId {
CARBON_CHECK(!node_id.is_cross_reference())
<< "Should use the existing cross-reference. Might want to return this, "
"but lacking a use-case, it's treated as bad input.";
return semantics_->AddCrossReference(SemanticsCrossReference(
SemanticsIR::ThisIR, current_block_id(), node_id));
}
auto SemanticsParseTreeHandler::AddNode(SemanticsNode node) -> SemanticsNodeId {
CARBON_VLOG() << "AddNode " << current_block_id() << ": " << node << "\n";
return semantics_->AddNode(current_block_id(), node);
@@ -113,7 +104,7 @@ auto SemanticsParseTreeHandler::BindName(ParseTree::Node name_node,
SemanticsNode::MakeBindName(name_node, type_id, name_id, target_id));
auto [it, inserted] = current_scope().names.insert(name_id);
if (inserted) {
name_lookup_[name_id].push_back(AddCrossReference(bind_id));
name_lookup_[name_id].push_back(bind_id);
} else {
CARBON_DIAGNOSTIC(NameRedefined, Error, "Redefining {0} in the same scope.",
llvm::StringRef);
@@ -122,7 +113,7 @@ auto SemanticsParseTreeHandler::BindName(ParseTree::Node name_node,
// TODO: This should be a note and sorted with the above diagnostic.
// But that depends on more diagnostic support we currently don't have.
auto prev_def_id = name_lookup_[name_id].back();
auto prev_def = semantics_->GetNode(current_block_id(), prev_def_id);
auto prev_def = semantics_->GetNode(prev_def_id);
CARBON_DIAGNOSTIC(PreviousDefinition, Error,
"Previous definition is here.");
emitter_->Emit(parse_tree_->node_token(prev_def.parse_node()),
@@ -234,9 +225,8 @@ auto SemanticsParseTreeHandler::TryTypeConversion(ParseTree::Node parse_node,
SemanticsNodeId rhs_id,
bool /*can_convert_lhs*/)
-> SemanticsNodeId {
auto block = current_block_id();
auto lhs_type = semantics_->GetType(block, lhs_id);
auto rhs_type = semantics_->GetType(block, rhs_id);
auto lhs_type = semantics_->GetType(lhs_id);
auto rhs_type = semantics_->GetType(rhs_id);
// TODO: This should attempt a type conversion, but there's not enough
// implemented to do that right now.
if (lhs_type != rhs_type) {
@@ -615,7 +605,7 @@ auto SemanticsParseTreeHandler::HandleReturnStatement(
Push(parse_node, SemanticsNode::MakeReturn(parse_node));
} else {
auto arg = PopWithResult();
auto arg_type = semantics_->GetType(current_block_id(), arg);
auto arg_type = semantics_->GetType(arg);
Pop(ParseNodeKind::ReturnStatementStart());
Push(parse_node,
SemanticsNode::MakeReturnExpression(parse_node, arg_type, arg));