Create a Generic object to represent a generic. (#4081)

Build a `Generic` object for generic functions. This object tracks the
generic parameters that are in scope for the generic entity. Eventually
it will track other information about the generic too.

Add basic SemIR formatting support for generic functions.
This commit is contained in:
Richard Smith
2024-06-26 20:13:26 +00:00
committed by GitHub
parent e5efea89d7
commit e7b0529957
79 changed files with 491 additions and 209 deletions
+49 -8
View File
@@ -56,6 +56,16 @@ auto ScopeStack::Pop() -> void {
CARBON_CHECK(return_scope_stack_.back().returned_var.is_valid());
return_scope_stack_.back().returned_var = SemIR::InstId::Invalid;
}
CARBON_CHECK(scope.next_compile_time_bind_index.index ==
static_cast<int32_t>(compile_time_binding_stack_.size()))
<< "Wrong number of entries in compile-time binding stack, have "
<< compile_time_binding_stack_.size() << ", expected "
<< scope.next_compile_time_bind_index.index;
compile_time_binding_stack_.truncate(
scope_stack_.empty()
? 0
: scope_stack_.back().next_compile_time_bind_index.index);
}
auto ScopeStack::PopTo(ScopeIndex index) -> void {
@@ -147,13 +157,35 @@ auto ScopeStack::SetReturnedVarOrGetExisting(SemIR::InstId inst_id)
auto ScopeStack::Suspend() -> SuspendedScope {
CARBON_CHECK(!scope_stack_.empty()) << "No scope to suspend";
SuspendedScope result = {.entry = scope_stack_.pop_back_val(),
.suspended_lookups = {}};
.suspended_items = {}};
if (result.entry.scope_id.is_valid()) {
non_lexical_scope_stack_.pop_back();
}
auto remaining_compile_time_bindings =
scope_stack_.empty()
? 0
: scope_stack_.back().next_compile_time_bind_index.index;
result.suspended_items.reserve(result.entry.names.size() +
compile_time_binding_stack_.size() -
remaining_compile_time_bindings);
for (auto name_id : result.entry.names) {
result.suspended_lookups.push_back(lexical_lookup_.Suspend(name_id));
auto [index, inst_id] = lexical_lookup_.Suspend(name_id);
CARBON_CHECK(index !=
SuspendedScope::ScopeItem::IndexForCompileTimeBinding);
result.suspended_items.push_back({.index = index, .inst_id = inst_id});
}
// Move any compile-time bindings into the suspended scope.
for (auto inst_id : llvm::ArrayRef(compile_time_binding_stack_)
.drop_back(remaining_compile_time_bindings)) {
result.suspended_items.push_back(
{.index = SuspendedScope::ScopeItem::IndexForCompileTimeBinding,
.inst_id = inst_id});
}
compile_time_binding_stack_.truncate(remaining_compile_time_bindings);
// This would be easy to support if we had a need, but currently we do not.
CARBON_CHECK(!result.entry.has_returned_var)
<< "Should not suspend a scope with a returned var.";
@@ -161,13 +193,22 @@ auto ScopeStack::Suspend() -> SuspendedScope {
}
auto ScopeStack::Restore(SuspendedScope scope) -> void {
for (auto entry : scope.suspended_lookups) {
// clang-tidy warns that the `std::move` below has no effect. While that's
// true, this `move` defends against the suspended lookup growing more state
// later.
// NOLINTNEXTLINE(performance-move-const-arg)
lexical_lookup_.Restore(std::move(entry), scope.entry.index);
for (auto [index, inst_id] : scope.suspended_items) {
if (index == SuspendedScope::ScopeItem::IndexForCompileTimeBinding) {
compile_time_binding_stack_.push_back(inst_id);
} else {
lexical_lookup_.Restore({.index = index, .inst_id = inst_id},
scope.entry.index);
}
}
CARBON_CHECK(scope.entry.next_compile_time_bind_index.index ==
static_cast<int32_t>(compile_time_binding_stack_.size()))
<< "Wrong number of entries in compile-time binding stack "
"when restoring, have "
<< compile_time_binding_stack_.size() << ", expected "
<< scope.entry.next_compile_time_bind_index.index;
if (scope.entry.scope_id.is_valid()) {
non_lexical_scope_stack_.push_back({.scope_index = scope.entry.index,
.name_scope_id = scope.entry.scope_id});