Make fatal DiagnosticBuilder yield never

This commit is contained in:
Michael Goulet 2022-03-09 16:11:28 -08:00
parent 93313d108f
commit 928388bad2
11 changed files with 82 additions and 46 deletions

View file

@ -198,6 +198,45 @@ impl EmissionGuarantee for () {
}
}
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
crate fn new_fatal(handler: &'a Handler, message: &str) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
Self::new_diagnostic_fatal(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
crate fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
}
impl EmissionGuarantee for ! {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&Handler` is still available.
DiagnosticBuilderState::Emittable(handler) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
handler.emit_diagnostic(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
// Then fatally error, returning `!`
crate::FatalError.raise()
}
}
/// In general, the `DiagnosticBuilder` uses deref to allow access to
/// the fields and methods of the embedded `diagnostic` in a
/// transparent way. *However,* many of the methods are intended to