1
Fork 0

Use a dedicated type instead of a reference for the diagnostic context

This paves the way for tracking more state (e.g. error tainting) in the diagnostic context handle
This commit is contained in:
Oli Scherer 2024-06-18 10:35:56 +00:00
parent c91edc3888
commit 7ba82d61eb
77 changed files with 363 additions and 328 deletions

View file

@ -414,6 +414,19 @@ pub struct DiagCtxt {
inner: Lock<DiagCtxtInner>,
}
#[derive(Copy, Clone)]
pub struct DiagCtxtHandle<'a> {
dcx: &'a DiagCtxt,
}
impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
type Target = &'a DiagCtxt;
fn deref(&self) -> &Self::Target {
&self.dcx
}
}
/// This inner struct exists to keep it all behind a single lock;
/// this is done to prevent possible deadlocks in a multi-threaded compiler,
/// as well as inconsistent state observation.
@ -608,7 +621,7 @@ impl DiagCtxt {
}
pub fn make_silent(
&mut self,
&self,
fallback_bundle: LazyFallbackBundle,
fatal_note: Option<String>,
emit_fatal_diagnostic: bool,
@ -623,7 +636,7 @@ impl DiagCtxt {
});
}
fn wrap_emitter<F>(&mut self, f: F)
fn wrap_emitter<F>(&self, f: F)
where
F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>,
{
@ -738,6 +751,12 @@ impl DiagCtxt {
*fulfilled_expectations = Default::default();
}
pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
DiagCtxtHandle { dcx: self }
}
}
impl<'a> DiagCtxtHandle<'a> {
/// Stashes a diagnostic for possible later improvement in a different,
/// later stage of the compiler. Possible actions depend on the diagnostic
/// level:
@ -745,8 +764,8 @@ impl DiagCtxt {
/// - Level::Error: immediately counted as an error that has occurred, because it
/// is guaranteed to be emitted eventually. Can be later accessed with the
/// provided `span` and `key` through
/// [`DiagCtxt::try_steal_modify_and_emit_err`] or
/// [`DiagCtxt::try_steal_replace_and_emit_err`]. These do not allow
/// [`DiagCtxtHandle::try_steal_modify_and_emit_err`] or
/// [`DiagCtxtHandle::try_steal_replace_and_emit_err`]. These do not allow
/// cancellation or downgrading of the error. Returns
/// `Some(ErrorGuaranteed)`.
/// - Level::DelayedBug: this does happen occasionally with errors that are
@ -757,7 +776,7 @@ impl DiagCtxt {
/// user-facing error. Returns `Some(ErrorGuaranteed)` as is normal for
/// delayed bugs.
/// - Level::Warning and lower (i.e. !is_error()): can be accessed with the
/// provided `span` and `key` through [`DiagCtxt::steal_non_err()`]. This
/// provided `span` and `key` through [`DiagCtxtHandle::steal_non_err()`]. This
/// allows cancelling and downgrading of the diagnostic. Returns `None`.
pub fn stash_diagnostic(
&self,
@ -793,7 +812,7 @@ impl DiagCtxt {
/// Steal a previously stashed non-error diagnostic with the given `Span`
/// and [`StashKey`] as the key. Panics if the found diagnostic is an
/// error.
pub fn steal_non_err(&self, span: Span, key: StashKey) -> Option<Diag<'_, ()>> {
pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
let key = (span.with_parent(None), key);
// FIXME(#120456) - is `swap_remove` correct?
let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key)?;
@ -807,7 +826,7 @@ impl DiagCtxt {
/// no matching diagnostic is found. Panics if the found diagnostic's level
/// isn't `Level::Error`.
pub fn try_steal_modify_and_emit_err<F>(
&self,
self,
span: Span,
key: StashKey,
mut modify_err: F,
@ -833,7 +852,7 @@ impl DiagCtxt {
/// [`StashKey`] as the key, cancels it if found, and emits `new_err`.
/// Panics if the found diagnostic's level isn't `Level::Error`.
pub fn try_steal_replace_and_emit_err(
&self,
self,
span: Span,
key: StashKey,
new_err: Diag<'_>,
@ -1106,18 +1125,18 @@ impl DiagCtxt {
//
// Functions beginning with `struct_`/`create_` create a diagnostic. Other
// functions create and emit a diagnostic all in one go.
impl DiagCtxt {
impl<'a> DiagCtxtHandle<'a> {
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn struct_bug(&self, msg: impl Into<Cow<'static, str>>) -> Diag<'_, BugAbort> {
pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
Diag::new(self, Bug, msg.into())
}
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn bug(&self, msg: impl Into<Cow<'static, str>>) -> ! {
pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_bug(msg).emit()
}
@ -1125,111 +1144,108 @@ impl DiagCtxt {
// user-facing.
#[track_caller]
pub fn struct_span_bug(
&self,
self,
span: impl Into<MultiSpan>,
msg: impl Into<Cow<'static, str>>,
) -> Diag<'_, BugAbort> {
) -> Diag<'a, BugAbort> {
self.struct_bug(msg).with_span(span)
}
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_span_bug(span, msg.into()).emit()
}
#[track_caller]
pub fn create_bug<'a>(&'a self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
bug.into_diag(self, Bug)
}
#[track_caller]
pub fn emit_bug<'a>(&'a self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
self.create_bug(bug).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_fatal(&self, msg: impl Into<DiagMessage>) -> Diag<'_, FatalAbort> {
pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
Diag::new(self, Fatal, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn fatal(&self, msg: impl Into<DiagMessage>) -> ! {
pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
self.struct_fatal(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_fatal(
&self,
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> Diag<'_, FatalAbort> {
) -> Diag<'a, FatalAbort> {
self.struct_fatal(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
self.struct_span_fatal(span, msg).emit()
}
#[track_caller]
pub fn create_fatal<'a>(
&'a self,
fatal: impl Diagnostic<'a, FatalAbort>,
) -> Diag<'a, FatalAbort> {
pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
fatal.into_diag(self, Fatal)
}
#[track_caller]
pub fn emit_fatal<'a>(&'a self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
self.create_fatal(fatal).emit()
}
#[track_caller]
pub fn create_almost_fatal<'a>(
&'a self,
pub fn create_almost_fatal(
self,
fatal: impl Diagnostic<'a, FatalError>,
) -> Diag<'a, FatalError> {
fatal.into_diag(self, Fatal)
}
#[track_caller]
pub fn emit_almost_fatal<'a>(&'a self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
self.create_almost_fatal(fatal).emit()
}
// FIXME: This method should be removed (every error should have an associated error code).
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_err(&self, msg: impl Into<DiagMessage>) -> Diag<'_> {
pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
Diag::new(self, Error, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn err(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
self.struct_err(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_err(
&self,
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> Diag<'_> {
) -> Diag<'a> {
self.struct_err(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_err(
&self,
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> ErrorGuaranteed {
@ -1237,12 +1253,12 @@ impl DiagCtxt {
}
#[track_caller]
pub fn create_err<'a>(&'a self, err: impl Diagnostic<'a>) -> Diag<'a> {
pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
err.into_diag(self, Error)
}
#[track_caller]
pub fn emit_err<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
self.create_err(err).emit()
}
@ -1251,7 +1267,7 @@ impl DiagCtxt {
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn delayed_bug(&self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
}
@ -1264,7 +1280,7 @@ impl DiagCtxt {
// user-facing.
#[track_caller]
pub fn span_delayed_bug(
&self,
self,
sp: impl Into<MultiSpan>,
msg: impl Into<Cow<'static, str>>,
) -> ErrorGuaranteed {
@ -1273,45 +1289,45 @@ impl DiagCtxt {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_warn(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Warning, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn warn(&self, msg: impl Into<DiagMessage>) {
pub fn warn(self, msg: impl Into<DiagMessage>) {
self.struct_warn(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_warn(
&self,
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> Diag<'_, ()> {
) -> Diag<'a, ()> {
self.struct_warn(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
self.struct_span_warn(span, msg).emit()
}
#[track_caller]
pub fn create_warn<'a>(&'a self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
warning.into_diag(self, Warning)
}
#[track_caller]
pub fn emit_warn<'a>(&'a self, warning: impl Diagnostic<'a, ()>) {
pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
self.create_warn(warning).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_note(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Note, msg)
}
@ -1324,54 +1340,50 @@ impl DiagCtxt {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_note(
&self,
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> Diag<'_, ()> {
) -> Diag<'a, ()> {
self.struct_note(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
self.struct_span_note(span, msg).emit()
}
#[track_caller]
pub fn create_note<'a>(&'a self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
note.into_diag(self, Note)
}
#[track_caller]
pub fn emit_note<'a>(&'a self, note: impl Diagnostic<'a, ()>) {
pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
self.create_note(note).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_help(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Help, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_failure_note(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, FailureNote, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_allow(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Allow, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_expect(
&self,
msg: impl Into<DiagMessage>,
id: LintExpectationId,
) -> Diag<'_, ()> {
pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
Diag::new(self, Expect(id), msg)
}
}