Combine DiagnosticConverter into DiagnosticEmitter (#4878)

At present, we typically define a DiagnosticConverter, then store an
instance of it and a DiagnosticEmitter that wraps it. This is relatively
minor in general, but I've been trying to create more self-contained
DiagnosticEmitter classes (which hold their own DiagnosticConverter,
similar to NullDiagnosticEmitter), and there it just gets in the way.

Since we don't reuse DiagnosticConverter instances, this combines the
definition into DiagnosticEmitter. Mainly this means we don't have a
separate object in play, and less to carry around.

The most impact is probably to SemIRDiagnosticConverter, which was also
the most complex. Now `SemIRLocDiagnosticEmitter`, this gets some
different construction flow. Note in the PR I've split the file rename
to its own commit, to try to help delta views. However, the most
substantial parts of the refactoring are split into #4876, which this
depends upon.
This commit is contained in:
Jon Ross-Perkins
2025-02-06 20:27:57 +00:00
committed by GitHub
parent a16a17daf0
commit e79d3be5bd
31 changed files with 264 additions and 316 deletions
+31 -49
View File
@@ -333,22 +333,15 @@ class CompilationUnit {
// Parses tokens. Returns true on success.
auto RunParse() -> void;
// Prepares per-IR lazy fetch functions which may come up in cross-IR
// diagnostics.
auto PreCheck() -> Parse::GetTreeAndSubtreesFn;
// Returns information needed to check this unit.
auto GetCheckUnit(
SemIR::CheckIRId check_ir_id,
llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> all_trees_and_subtrees)
-> Check::Unit;
auto GetCheckUnit(SemIR::CheckIRId check_ir_id) -> Check::Unit;
// Runs post-check logic. Returns true if checking succeeded for the IR.
auto PostCheck() -> void;
// Lower SemIR to LLVM IR.
auto RunLower(std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
all_trees_and_subtrees_for_debug_info) -> void;
tree_and_subtrees_getters_for_debug_info) -> void;
auto RunCodeGen() -> void;
@@ -363,6 +356,9 @@ class CompilationUnit {
auto input_filename() -> llvm::StringRef { return input_filename_; }
auto success() -> bool { return success_; }
auto has_source() -> bool { return source_.has_value(); }
auto get_trees_and_subtrees() -> Parse::GetTreeAndSubtreesFn {
return *tree_and_subtrees_getter_;
}
private:
// Do codegen. Returns true on success.
@@ -414,8 +410,7 @@ class CompilationUnit {
std::optional<Parse::Tree> parse_tree_;
std::optional<Parse::TreeAndSubtrees> parse_tree_and_subtrees_;
std::optional<std::function<const Parse::TreeAndSubtrees&()>>
get_parse_tree_and_subtrees_;
std::optional<Check::SemIRDiagnosticConverter> sem_ir_converter_;
tree_and_subtrees_getter_;
std::optional<SemIR::File> sem_ir_;
std::unique_ptr<llvm::LLVMContext> llvm_context_;
std::unique_ptr<llvm::Module> module_;
@@ -500,36 +495,25 @@ auto CompilationUnit::RunParse() -> void {
}
}
auto CompilationUnit::PreCheck() -> Parse::GetTreeAndSubtreesFn {
auto CompilationUnit::GetCheckUnit(SemIR::CheckIRId check_ir_id)
-> Check::Unit {
CARBON_CHECK(parse_tree_, "Must call RunParse first");
CARBON_CHECK(!get_parse_tree_and_subtrees_, "Called PreCheck twice");
CARBON_CHECK(!sem_ir_, "Called GetCheckUnit twice");
get_parse_tree_and_subtrees_ = [this]() -> const Parse::TreeAndSubtrees& {
tree_and_subtrees_getter_ = [this]() -> const Parse::TreeAndSubtrees& {
return this->GetParseTreeAndSubtrees();
};
return *get_parse_tree_and_subtrees_;
}
auto CompilationUnit::GetCheckUnit(
SemIR::CheckIRId check_ir_id,
llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> all_trees_and_subtrees)
-> Check::Unit {
CARBON_CHECK(get_parse_tree_and_subtrees_, "Must call PreCheck first");
CARBON_CHECK(!sem_ir_converter_, "Called GetCheckUnit twice");
sem_ir_.emplace(&*parse_tree_, check_ir_id, parse_tree_->packaging_decl(),
value_stores_, input_filename_);
sem_ir_converter_.emplace(all_trees_and_subtrees, &*sem_ir_);
return {.consumer = consumer_,
.value_stores = &value_stores_,
.timings = timings_ ? &*timings_ : nullptr,
.get_parse_tree_and_subtrees = *get_parse_tree_and_subtrees_,
.sem_ir = &*sem_ir_,
.sem_ir_converter = &*sem_ir_converter_};
.tree_and_subtrees_getter = *tree_and_subtrees_getter_,
.sem_ir = &*sem_ir_};
}
auto CompilationUnit::PostCheck() -> void {
CARBON_CHECK(sem_ir_converter_, "Must call GetCheckUnit first");
CARBON_CHECK(sem_ir_, "Must call GetCheckUnit first");
// We've finished all steps that can produce diagnostics. Emit the
// diagnostics now, so that the developer sees them sooner and doesn't need
@@ -589,15 +573,15 @@ auto CompilationUnit::PostCheck() -> void {
auto CompilationUnit::RunLower(
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
all_trees_and_subtrees_for_debug_info) -> void {
tree_and_subtrees_getters_for_debug_info) -> void {
LogCall("Lower::LowerToLLVM", "lower", [&] {
llvm_context_ = std::make_unique<llvm::LLVMContext>();
// TODO: Consider disabling instruction naming by default if we're not
// producing textual LLVM IR.
SemIR::InstNamer inst_namer(&*sem_ir_);
module_ = Lower::LowerToLLVM(
*llvm_context_, all_trees_and_subtrees_for_debug_info, input_filename_,
*sem_ir_, &inst_namer, vlog_stream_);
*llvm_context_, tree_and_subtrees_getters_for_debug_info,
input_filename_, *sem_ir_, &inst_namer, vlog_stream_);
});
if (vlog_stream_) {
CARBON_VLOG("*** llvm::Module ***\n");
@@ -843,25 +827,13 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
return make_result();
}
// Pre-check assigns IR IDs and constructs node converters.
llvm::SmallVector<Parse::GetTreeAndSubtreesFn> all_trees_and_subtrees;
// This size may not match due to units that are missing source, but that's an
// error case and not worth extra work.
all_trees_and_subtrees.reserve(units.size());
for (auto& unit : units) {
if (unit->has_source()) {
all_trees_and_subtrees.push_back(unit->PreCheck());
}
}
// Gather Check::Units.
llvm::SmallVector<Check::Unit> check_units;
check_units.reserve(all_trees_and_subtrees.size());
check_units.reserve(units.size());
for (auto& unit : units) {
if (unit->has_source()) {
SemIR::CheckIRId check_ir_id(check_units.size());
check_units.push_back(
unit->GetCheckUnit(check_ir_id, all_trees_and_subtrees));
check_units.push_back(unit->GetCheckUnit(check_ir_id));
}
}
@@ -888,13 +860,23 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
}
// Lower.
llvm::SmallVector<Parse::GetTreeAndSubtreesFn> tree_and_subtrees_getters;
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
all_trees_and_subtrees_for_debug_info;
tree_and_subtrees_getters_for_debug_info;
if (options_.include_debug_info) {
all_trees_and_subtrees_for_debug_info = all_trees_and_subtrees;
// This size may not match due to units that are missing source, but that's
// an error case and not worth extra work.
tree_and_subtrees_getters.reserve(units.size());
for (auto& unit : units) {
if (unit->has_source()) {
tree_and_subtrees_getters.push_back(unit->get_trees_and_subtrees());
}
}
tree_and_subtrees_getters_for_debug_info = {};
tree_and_subtrees_getters_for_debug_info = tree_and_subtrees_getters;
}
for (const auto& unit : units) {
unit->RunLower(all_trees_and_subtrees_for_debug_info);
unit->RunLower(tree_and_subtrees_getters_for_debug_info);
}
if (options_.phase == CompileOptions::Phase::Lower) {
return make_result();