Files
carbon-lang/toolchain/check/deferred_definition_worklist.cpp
T
Dana Jansens 517c4d3c20 Remove VariantMatch; use CARBON_KIND_SWITCH for std::variants (#5437)
Teach CARBON_KIND_SWITCH to handle mutable lvalues and rvalues, and
CARBON_KIND to forward along rvalues so that it's possible to write
`case CARBON_KIND(const T& t)`, `case CARBON_KIND(T& t)`, and `case
CARBON_KIND(T&& t)`, depending on the type that was passed to
CARBON_KIND_SWITCH.

Replace all uses of VariantMatch with their equivalent of a switch using
CARBON_KIND_SWITCH, and remove the VariantMatch helper from the
codebase.
2025-05-12 18:56:52 +00:00

133 lines
5.3 KiB
C++

// 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/check/deferred_definition_worklist.h"
#include <algorithm>
#include <optional>
#include "common/vlog.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/handle.h"
namespace Carbon::Check {
static constexpr llvm::StringLiteral VlogPrefix = "DeferredDefinitionWorklist ";
DeferredDefinitionWorklist::DeferredDefinitionWorklist(
llvm::raw_ostream* vlog_stream)
: vlog_stream_(vlog_stream) {
// See declaration of `worklist_`.
worklist_.reserve(64);
}
auto DeferredDefinitionWorklist::SuspendFunctionAndPush(
Context& context, Parse::DeferredDefinitionIndex index,
Parse::FunctionDefinitionStartId node_id) -> void {
// TODO: Investigate factoring out `HandleFunctionDefinitionSuspend` to make
// `DeferredDefinitionWorklist` reusable.
worklist_.push_back(CheckSkippedDefinition{
index, HandleFunctionDefinitionSuspend(context, node_id)});
CARBON_VLOG("{0}Push CheckSkippedDefinition {1}\n", VlogPrefix, index.index);
}
auto DeferredDefinitionWorklist::PushEnterDeferredDefinitionScope(
Context& context) -> bool {
bool nested = !entered_scopes_.empty() &&
entered_scopes_.back().scope_index ==
context.decl_name_stack().PeekInitialScopeIndex();
entered_scopes_.push_back({.worklist_start_index = worklist_.size(),
.scope_index = context.scope_stack().PeekIndex()});
worklist_.push_back(EnterDeferredDefinitionScope{
.suspended_name = std::nullopt, .in_deferred_definition_scope = nested});
CARBON_VLOG("{0}Push EnterDeferredDefinitionScope {1}\n", VlogPrefix,
nested ? "(nested)" : "(non-nested)");
return !nested;
}
auto DeferredDefinitionWorklist::SuspendFinishedScopeAndPush(Context& context)
-> FinishedScopeKind {
auto start_index = entered_scopes_.pop_back_val().worklist_start_index;
// If we've not found any deferred definitions in this scope, clean up the
// stack.
if (start_index == worklist_.size() - 1) {
context.decl_name_stack().PopScope();
auto enter_scope =
get<EnterDeferredDefinitionScope>(worklist_.pop_back_val());
CARBON_VLOG("{0}Pop EnterDeferredDefinitionScope (empty)\n", VlogPrefix);
return enter_scope.in_deferred_definition_scope
? FinishedScopeKind::Nested
: FinishedScopeKind::NonNestedEmpty;
}
// If we're finishing a nested deferred definition scope, keep track of that
// but don't type-check deferred definitions now.
if (auto& enter_scope =
get<EnterDeferredDefinitionScope>(worklist_[start_index]);
enter_scope.in_deferred_definition_scope) {
// This is a nested deferred definition scope. Suspend the inner scope so we
// can restore it when we come to type-check the deferred definitions.
enter_scope.suspended_name = context.decl_name_stack().Suspend();
// Enqueue a task to leave the nested scope.
worklist_.push_back(
LeaveDeferredDefinitionScope{.in_deferred_definition_scope = true});
CARBON_VLOG("{0}Push LeaveDeferredDefinitionScope (nested)\n", VlogPrefix);
return FinishedScopeKind::Nested;
}
// We're at the end of a non-nested deferred definition scope. Prepare to
// start checking deferred definitions. Enqueue a task to leave this outer
// scope and end checking deferred definitions.
worklist_.push_back(
LeaveDeferredDefinitionScope{.in_deferred_definition_scope = false});
CARBON_VLOG("{0}Push LeaveDeferredDefinitionScope (non-nested)\n",
VlogPrefix);
// We'll process the worklist in reverse index order, so reverse the part of
// it we're about to execute so we run our tasks in the order in which they
// were pushed.
std::reverse(worklist_.begin() + start_index, worklist_.end());
// Pop the `EnterDeferredDefinitionScope` that's now on the end of the
// worklist. We stay in that scope rather than suspending then immediately
// resuming it.
CARBON_CHECK(
holds_alternative<EnterDeferredDefinitionScope>(worklist_.back()),
"Unexpected task in worklist.");
worklist_.pop_back();
CARBON_VLOG("{0}Handle EnterDeferredDefinitionScope (non-nested)\n",
VlogPrefix);
return FinishedScopeKind::NonNestedWithWork;
}
auto DeferredDefinitionWorklist::Pop(
llvm::function_ref<auto(Task&&)->void> handle_fn) -> void {
if (vlog_stream_) {
CARBON_KIND_SWITCH(worklist_.back()) {
case CARBON_KIND(const CheckSkippedDefinition& definition):
CARBON_VLOG("{0}Handle CheckSkippedDefinition {1}\n", VlogPrefix,
definition.definition_index.index);
break;
case CARBON_KIND(const EnterDeferredDefinitionScope& enter):
CARBON_CHECK(enter.in_deferred_definition_scope);
CARBON_VLOG("{0}Handle EnterDeferredDefinitionScope (nested)\n",
VlogPrefix);
break;
case CARBON_KIND(const LeaveDeferredDefinitionScope& leave): {
bool nested = leave.in_deferred_definition_scope;
CARBON_VLOG("{0}Handle LeaveDeferredDefinitionScope {1}\n", VlogPrefix,
nested ? "(nested)" : "(non-nested)");
break;
}
}
}
handle_fn(std::move(worklist_.back()));
worklist_.pop_back();
}
} // namespace Carbon::Check