use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
mod traits {
use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
use super::structures::*;
#[rustc_diagnostic_item = "Diagnostic"]
pub trait Diagnostic<'diagnostic, GUARANTEE: EmissionGuarantee = ErrorGuaranteed> {
#[must_use]
fn into_diag(
self,
dcx: DiagCtxtHandle<'diagnostic>,
level: DiagnosticLevel,
) -> Diag<'diagnostic, GUARANTEE>;
}
#[rustc_diagnostic_item = "LintDiagnostic"]
pub trait LintDiagnostic<'diagnostic, GUARANTEE: EmissionGuarantee> {
fn decorate_lint<'decorate_lint>(self, diag: &'decorate_lint mut Diag<'diagnostic, GUARANTEE>);
}
pub trait EmissionGuarantee: Sized {
type EmitResult = Self;
const CONTINUEABLE: bool = true;
type RecoveryHandler: RecoveryHandler<Self> = NoRecovery;
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult;
fn emit_continuable(diag: Diag<'_, Self>) -> crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome<Self::EmitResult> {
let result = Self::emit_producing_guarantee(diag);
if Self::CONTINUEABLE {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome::Continue(result)
} else if let Some(recovered) = Self::RecoveryHandler::attempt_recovery(&result) {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome::Recovered(recovered)
} else {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome::MustStop(result)
}
}
}
pub type DiagArgMap = FxIndexMap<DiagArgName, DiagArgValue>; pub type DiagArgName = Cow<'static, str>;
pub trait IntoDiagArg {
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue;
}
}
mod structures {
use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
use crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmissionGuarantee;
#[derive(
Clone,
Copy,
Debug,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord
)] pub struct ErrorGuaranteed(());
pub struct FatalErrorMarker;
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct FatalError;
pub struct FatalRecovery;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum DiagArgValue {
Str(Cow<'static, str>),
Number(i32),
StrListSepByAnd(Vec<Cow<'static, str>>),
}
#[must_use]
pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
pub dcx: DiagnosticContextHandle<'a>,
pub(crate) diag: Option<Box<DiagInner>>,
pub(crate) _marker: PhantomData<G>,
}
#[must_use]
#[derive(Clone, Debug)]
pub struct DiagInner {
pub level: crate::DaemonicCompiler::rustc::rustc_error::DiagnosticLevel,
pub messages: Vec<(DiagMessage, Style)>,
pub code: Option<ErrCode>,
pub lint_id: Option<LintExpectationId>,
pub span: MultiSpan,
pub children: Vec<Subdiag>,
pub suggestions: Suggestions,
pub args: DiagArgMap,
pub sort_span: Span,
pub is_lint: Option<IsLint>,
pub long_ty_path: Option<PathBuf>,
pub emitted_at: DiagLocation,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Subdiag {
pub level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::DiagnosticLevel,
pub messages: Vec<(DiagMessage, Style)>,
pub span: MultiSpan,
}
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
pub enum DiagnosticLevel {
Bug,
Fatal,
Error,
DelayedBug,
ForceWarning,
Warning,
Note,
OnceNote,
Help,
OnceHelp,
FailureNote,
Allow,
Expect,
}
#[derive(Copy, Clone)]
pub struct DiagnosticContextHandle<'a> {
pub dcx: &'a DiagCtxt,
pub tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
}
pub struct DiagCtxt {
pub(crate) inner: Lock<DiagCtxtInner>,
}
pub enum EmitOutcome<R> { Continue(R),
Recovered(RecoveredState),
MustStop(R),
}
pub struct RecoveredState {} }
mod implementations {
use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, DiagnosticContextHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
use crate::daemonic::daemonic_contract::daemonic_result::diagnostic;
use super::structures::*;
use super::traits::*;
impl<'a> DiagnosticContextHandle<'a> {
#[track_caller]
pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> crate::Diag<'a, BugAbort> {
crate::Diag::new(self, crate::DiagnosticLevel::Bug, msg.into())
}
#[track_caller]
pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_bug(msg).emit()
}
#[track_caller]
pub fn struct_span_bug(
self,
span: impl Into<MultiSpan>,
msg: impl Into<Cow<'static, str>>,
) -> crate::Diag<'a, BugAbort> {
self.struct_bug(msg).with_span(span)
}
#[track_caller]
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(self, bug: impl crate::Diagnostic<'a, BugAbort>) -> crate::Diag<'a, BugAbort> {
bug.into_diag(self, crate::DiagnosticLevel::Bug)
}
#[track_caller]
pub fn emit_bug(self, bug: impl crate::Diagnostic<'a, BugAbort>) -> ! {
self.create_bug(bug).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, FatalAbort> {
crate::Diag::new(self, crate::DiagnosticLevel::Fatal, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
self.struct_fatal(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_fatal(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::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>) -> ! {
self.struct_span_fatal(span, msg).emit()
}
#[track_caller]
pub fn create_fatal(self, fatal: impl crate::Diagnostic<'a, FatalAbort>) -> crate::Diag<'a, FatalAbort> {
fatal.into_diag(self, crate::DiagnosticLevel::Fatal)
}
#[track_caller]
pub fn emit_fatal(self, fatal: impl crate::Diagnostic<'a, FatalAbort>) -> ! {
self.create_fatal(fatal).emit()
}
#[track_caller]
pub fn create_almost_fatal(
self,
fatal: impl crate::Diagnostic<'a, crate::FatalError>,
) -> crate::Diag<'a, crate::FatalError> {
fatal.into_diag(self, crate::DiagnosticLevel::Fatal)
}
#[track_caller]
pub fn emit_almost_fatal(self, fatal: impl crate::Diagnostic<'a, crate::FatalError>) -> crate::FatalError {
self.create_almost_fatal(fatal).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_err(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a> {
crate::Diag::new(self, crate::DiagnosticLevel::Error, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn err(self, msg: impl Into<DiagMessage>) -> crate::ErrorGuaranteed {
self.struct_err(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_err(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::Diag<'a> {
self.struct_err(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_err(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::ErrorGuaranteed {
self.struct_span_err(span, msg).emit()
}
#[track_caller]
pub fn create_err(self, err: impl crate::Diagnostic<'a>) -> crate::Diag<'a> {
err.into_diag(self, crate::DiagnosticLevel::Error)
}
#[track_caller]
pub fn emit_err(self, err: impl crate::Diagnostic<'a>) -> crate::ErrorGuaranteed {
self.create_err(err).emit()
}
#[track_caller]
pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> crate::ErrorGuaranteed {
crate::Diag::<crate::ErrorGuaranteed>::new(self, crate::DiagnosticLevel::DelayedBug, msg.into()).emit()
}
#[track_caller]
pub fn span_delayed_bug(
self,
sp: impl Into<MultiSpan>,
msg: impl Into<Cow<'static, str>>,
) -> crate::ErrorGuaranteed {
crate::Diag::<crate::ErrorGuaranteed>::new(self, crate::DiagnosticLevel::DelayedBug, msg.into()).with_span(sp).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Warning, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn warn(self, msg: impl Into<DiagMessage>) {
self.struct_warn(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_warn(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::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>) {
self.struct_span_warn(span, msg).emit()
}
#[track_caller]
pub fn create_warn(self, warning: impl crate::Diagnostic<'a, ()>) -> crate::Diag<'a, ()> {
warning.into_diag(self, crate::DiagnosticLevel::Warning)
}
#[track_caller]
pub fn emit_warn(self, warning: impl crate::Diagnostic<'a, ()>) {
self.create_warn(warning).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_note(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Note, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn note(&self, msg: impl Into<DiagMessage>) {
self.struct_note(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_note(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::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>) {
self.struct_span_note(span, msg).emit()
}
#[track_caller]
pub fn create_note(self, note: impl crate::Diagnostic<'a, ()>) -> crate::Diag<'a, ()> {
note.into_diag(self, crate::DiagnosticLevel::Note)
}
#[track_caller]
pub fn emit_note(self, note: impl crate::Diagnostic<'a, ()>) {
self.create_note(note).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_help(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Help, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::FailureNote, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Allow, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Expect, msg).with_lint_id(id)
}
}
impl<'a> DiagnosticContextHandle<'a> {
pub fn stash_diagnostic(
&self,
span: Span,
key: StashKey,
diag: DiagInner,
) -> Option<ErrorGuaranteed> {
let guar = match diag.level {
DiagnosticLevel::Bug | DiagnosticLevel::Fatal => {
self.span_bug(
span,
format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
);
}
DiagnosticLevel::Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
DiagnosticLevel::DelayedBug => {
return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
}
DiagnosticLevel::ForceWarning
| DiagnosticLevel::Warning
| DiagnosticLevel::Note
| DiagnosticLevel::OnceNote
| DiagnosticLevel::Help
| DiagnosticLevel::OnceHelp
| DiagnosticLevel::FailureNote
| DiagnosticLevel::Allow
| DiagnosticLevel::Expect => None,
};
self.inner
.borrow_mut()
.stashed_diagnostics
.entry(key)
.or_default()
.insert(span.with_parent(None), (diag, guar));
guar
}
pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
|stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
)?;
assert!(!diag.is_error());
assert!(guar.is_none());
Some(Diag::new_diagnostic(self, diag))
}
pub fn try_steal_modify_and_emit_err<F>(
self,
span: Span,
key: StashKey,
mut modify_err: F,
) -> Option<ErrorGuaranteed>
where
F: FnMut(&mut Diag<'_>),
{
let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
|stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
);
err.map(|(err, guar)| {
assert_eq!(err.level, DiagnosticLevel::Error);
assert!(guar.is_some());
let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
modify_err(&mut err);
assert_eq!(err.level, DiagnosticLevel::Error);
err.emit()
})
}
pub fn try_steal_replace_and_emit_err(
self,
span: Span,
key: StashKey,
new_err: Diag<'_>,
) -> ErrorGuaranteed {
let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
|stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
);
match old_err {
Some((old_err, guar)) => {
assert_eq!(old_err.level, DiagnosticLevel::Error);
assert!(guar.is_some());
Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
}
None => {}
};
new_err.emit()
}
pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
let inner = self.inner.borrow();
if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
&& !stashed_diagnostics.is_empty()
{
stashed_diagnostics.contains_key(&span.with_parent(None))
} else {
false
}
}
pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_stashed_diagnostics()
}
#[inline]
pub fn err_count(&self) -> usize {
let inner = self.inner.borrow();
inner.err_guars.len()
+ inner.lint_err_guars.len()
+ inner
.stashed_diagnostics
.values()
.map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
.sum::<usize>()
}
pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_excluding_lint_errors()
}
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors()
}
pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_or_delayed_bugs()
}
pub fn print_error_count(&self) {
let mut inner = self.inner.borrow_mut();
assert!(inner.stashed_diagnostics.is_empty());
if inner.treat_err_as_bug() {
return;
}
let warnings = match inner.deduplicated_warn_count {
0 => Cow::from(""),
1 => Cow::from("1 warning emitted"),
count => Cow::from(format!("{count} warnings emitted")),
};
let errors = match inner.deduplicated_err_count {
0 => Cow::from(""),
1 => Cow::from("1 error emitted"),
count => Cow::from(format!("{count} errors emitted")),
};
if inner.treat_warn_as_err() && !warnings.is_empty() {
inner.emit_diagnostic(
DiagInner::new(DiagnosticLevel::ForceWarning, DiagMessage::Str(warnings.clone().to_owned())),
None,
);
}
if !errors.is_empty() {
if !warnings.is_empty() {
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::Error, format!("{errors}; {warnings}")),
None,
);
} else {
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::Error, errors.clone().to_owned()), None);
}
} else if !warnings.is_empty() {
inner.emit_diagnostic(
DiagInner::new(DiagnosticLevel::ForceWarning, DiagMessage::Str(warnings.clone().to_owned())),
None,
);
}
match (errors.is_empty(), warnings.is_empty()) {
(true, true) => return,
(false, true) => {
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, "aborting due to previous error"), None);
}
(false, false) => {
let msg1 = "aborting due to previous error";
let msg2 = format!("For more information about this error, try `rustc --explain E{}`.", "");
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, msg1), None);
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, msg2), None);
}
(true, false) => {
let msg = "warnings emitted";
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, msg), None);
}
}
}
pub fn abort_if_errors(&self) {
let mut inner = self.inner.borrow_mut();
if !inner.has_errors().is_some() {
return;
}
inner.emit_stashed_diagnostics();
FatalError.raise();
}
pub fn must_teach(&self, code: ErrCode) -> bool {
self.inner.borrow().must_teach(&code)
}
pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
}
pub fn emit_future_breakage_report(&self) {
let mut inner = self.inner.borrow_mut();
if inner.emitted_diagnostics.is_empty() {
return;
}
}
pub fn emit_unused_externs(
&self,
lint_level: rustc_lint_defs::LintLevel,
loud: bool,
unused_externs: &[&str],
) {
let mut inner = self.inner.borrow_mut();
if loud && lint_level.is_error() {
inner.bump_err_count();
}
drop(inner);
for unused in unused_externs {
let unused = unused.to_string();
self.emit_diagnostic(DiagInner::new(
DiagnosticLevel::Allow,
format!("unused extern crate `{unused}`"),
));
}
}
pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
assert!(
self.inner.borrow().unstable_expect_diagnostics.is_empty(),
"`DiagnosticContextHandle::steal_fulfilled_expectation_ids` must be called before `DiagnosticContextHandle::drop`"
);
std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
}
pub fn flush_delayed(&self) {
self.inner.borrow_mut().flush_delayed()
}
#[track_caller]
pub fn set_must_produce_diag(&self) {
assert!(
self.inner.borrow().must_produce_diag.is_none(),
"should only need to collect a backtrace once"
);
self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
}
}
impl ! Send for FatalError {}
impl FatalError {
pub fn raise(self) -> ! {
std::panic::resume_unwind(Box::new(FatalErrorMarker))
}
}
impl std::fmt::Display for FatalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "fatal error")
}
}
impl std::error::Error for FatalError {}
impl ErrorGuaranteed {
#[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"]
pub fn unchecked_error_guaranteed() -> Self {
ErrorGuaranteed(())
}
pub fn raise_fatal(self) -> ! {
FatalError.raise()
}
}
impl diagnostic::EmissionGuarantee for ErrorGuaranteed {
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
todo!()
}
}
impl<G> ! Clone for crate::Diag<'_, G> {}
impl<G: diagnostic::EmissionGuarantee> Deref for crate::Diag<'_, G> {
type Target = DiagInner;
fn deref(&self) -> &DiagInner {
self.diag.as_ref().unwrap()
}
}
impl<G: diagnostic::EmissionGuarantee> DerefMut for crate::Diag<'_, G> {
fn deref_mut(&mut self) -> &mut DiagInner {
self.diag.as_mut().unwrap()
}
}
impl<G: diagnostic::EmissionGuarantee> Debug for crate::Diag<'_, G> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.diag.fmt(f)
}
}
impl<'a, G: diagnostic::EmissionGuarantee> crate::Diag<'a, G> {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn new(dcx: DiagnosticContextHandle<'a>, level: diagnostic::DiagnosticLevel, message: impl Into<DiagMessage>) -> Self {
Self::new_diagnostic(dcx, DiagInner::new(level, message))
}
pub fn with_dcx(mut self, dcx: DiagnosticContextHandle<'_>) -> crate::Diag<'_, G> {
crate::Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
}
#[track_caller]
pub(crate) fn new_diagnostic(dcx: DiagnosticContextHandle<'a>, diag: DiagInner) -> Self {
debug!("Created new diagnostic");
Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn downgrade_to_delayed_bug(&mut self) {
assert!(
matches!(self.level, Level::Error | Level::DelayedBug),
"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
self.level
);
self.level = diagnostic::DiagnosticLevel::DelayedBug;
}
#[doc = r" Appends a labeled span to the diagnostic."]
#[doc = r""]
#[doc = r" Labels are used to convey additional context for the diagnostic's primary span. They will"]
#[doc = r" be shown together with the original diagnostic's span, *not* with spans added by"]
#[doc = r" `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because"]
#[doc = r" the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed"]
#[doc = r" either."]
#[doc = r""]
#[doc = r" Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when"]
#[doc = r" the diagnostic was constructed. However, the label span is *not* considered a"]
#[doc = r#" ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is"#]
#[doc = r" primary."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_label()`]."]
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
let msg = self.subdiagnostic_message_to_diagnostic_message(label);
self.span.push_span_label(span, msg);
self
}
#[doc = r" Appends a labeled span to the diagnostic."]
#[doc = r""]
#[doc = r" Labels are used to convey additional context for the diagnostic's primary span. They will"]
#[doc = r" be shown together with the original diagnostic's span, *not* with spans added by"]
#[doc = r" `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because"]
#[doc = r" the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed"]
#[doc = r" either."]
#[doc = r""]
#[doc = r" Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when"]
#[doc = r" the diagnostic was constructed. However, the label span is *not* considered a"]
#[doc = r#" ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is"#]
#[doc = r" primary."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_label()`]."]
pub fn with_span_label(mut self, span: Span, label: impl Into<SubdiagMessage>) -> Self {
self.span_label(span, label);
self
}
#[doc = r" Labels all the given spans with the provided label."]
#[doc = r" See [`Self::span_label()`] for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_labels()`]."]
pub fn span_labels(&mut self, spans: impl IntoIterator<Item=Span>, label: &str) -> &mut Self {
for span in spans {
self.span_label(span, label.to_string());
}
self
}
#[doc = r" Labels all the given spans with the provided label."]
#[doc = r" See [`Self::span_label()`] for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_labels()`]."]
pub fn with_span_labels(mut self, spans: impl IntoIterator<Item=Span>, label: &str) -> Self {
self.span_labels(spans, label);
self
}
#[rustc_lint_diagnostics]
pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
if span_label.is_primary && keep_label {
self.span.push_span_label(after, label);
} else {
self.span.push_span_label(span_label.span, label);
}
}
}
self
}
#[rustc_lint_diagnostics]
pub fn note_expected_found(
&mut self,
expected_label: &str,
expected: DiagStyledString,
found_label: &str,
found: DiagStyledString,
) -> &mut Self {
self.note_expected_found_extra(
expected_label,
expected,
found_label,
found,
DiagStyledString::normal(""),
DiagStyledString::normal(""),
)
}
#[rustc_lint_diagnostics]
pub fn note_expected_found_extra(
&mut self,
expected_label: &str,
expected: DiagStyledString,
found_label: &str,
found: DiagStyledString,
expected_extra: DiagStyledString,
found_extra: DiagStyledString,
) -> &mut Self {
let expected_label = expected_label.to_string();
let expected_label = if expected_label.is_empty() {
"expected".to_string()
} else {
format!("expected {expected_label}")
};
let found_label = found_label.to_string();
let found_label = if found_label.is_empty() {
"found".to_string()
} else {
format!("found {found_label}")
};
let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
(expected_label.len() - found_label.len(), 0)
} else {
(0, found_label.len() - expected_label.len())
};
let mut msg = vec![StringPart::normal(format!(
"{}{} `",
" ".repeat(expected_padding),
expected_label
))];
msg.extend(expected.0);
msg.push(StringPart::normal(format!("`")));
msg.extend(expected_extra.0);
msg.push(StringPart::normal(format!("\n")));
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
msg.extend(found.0);
msg.push(StringPart::normal(format!("`")));
msg.extend(found_extra.0);
self.highlighted_note(msg);
self
}
#[rustc_lint_diagnostics]
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
self.highlighted_note(vec![
StringPart::normal(format!("`{name}` from trait: `")),
StringPart::highlighted(signature),
StringPart::normal("`"),
]);
self
}
#[doc = r" Add a note attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::note()`]."]
pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Note, msg, MultiSpan::new());
self
}
#[doc = r" Add a note attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::note()`]."]
pub fn with_note(mut self, msg: impl Into<SubdiagMessage>) -> Self {
self.note(msg);
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Note, msg, MultiSpan::new());
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_span_note(
&mut self,
span: impl Into<MultiSpan>,
msg: Vec<StringPart>,
) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Note, msg, span.into());
self
}
#[rustc_lint_diagnostics]
pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::OnceNote, msg, MultiSpan::new());
self
}
#[doc = r" Prints the span with a note above it."]
#[doc = r" This is like [`Diag::note()`], but it gets its own span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_note()`]."]
pub fn span_note(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Note, msg, sp.into());
self
}
#[doc = r" Prints the span with a note above it."]
#[doc = r" This is like [`Diag::note()`], but it gets its own span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_note()`]."]
pub fn with_span_note(mut self, sp: impl Into<MultiSpan>, msg: impl Into<SubdiagMessage>) -> Self {
self.span_note(sp, msg);
self
}
#[rustc_lint_diagnostics]
pub fn span_note_once<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::OnceNote, msg, sp.into());
self
}
#[doc = r" Add a warning attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::warn()`]."]
pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Warning, msg, MultiSpan::new());
self
}
#[doc = r" Add a warning attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::warn()`]."]
pub fn with_warn(mut self, msg: impl Into<SubdiagMessage>) -> Self {
self.warn(msg);
self
}
#[rustc_lint_diagnostics]
pub fn span_warn<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Warning, msg, sp.into());
self
}
#[doc = r" Add a help message attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::help()`]."]
pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Help, msg, MultiSpan::new());
self
}
#[doc = r" Add a help message attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::help()`]."]
pub fn with_help(mut self, msg: impl Into<SubdiagMessage>) -> Self {
self.help(msg);
self
}
#[rustc_lint_diagnostics]
pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::OnceHelp, msg, MultiSpan::new());
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Help, msg, MultiSpan::new());
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_span_help(
&mut self,
span: impl Into<MultiSpan>,
msg: Vec<StringPart>,
) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Help, msg, span.into());
self
}
#[rustc_lint_diagnostics]
pub fn span_help<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Help, msg, sp.into());
self
}
#[rustc_lint_diagnostics]
pub fn disable_suggestions(&mut self) -> &mut Self {
self.suggestions = Suggestions::Disabled;
self
}
#[rustc_lint_diagnostics]
pub fn seal_suggestions(&mut self) -> &mut Self {
if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
self.suggestions = Suggestions::Sealed(suggestions_slice);
}
self
}
#[rustc_lint_diagnostics]
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
for subst in &suggestion.substitutions {
for part in &subst.parts {
let span = part.span;
let call_site = span.ctxt().outer_expn_data().call_site;
if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
return;
}
}
}
if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
suggestions.push(suggestion);
}
}
#[doc = r" Show a suggestion that has multiple parts to it."]
#[doc = r" In other words, multiple changes need to be applied as part of this suggestion."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::multipart_suggestion()`]."]
pub fn multipart_suggestion(&mut self, msg: impl Into<SubdiagMessage>, suggestion: Vec<(Span, String)>, applicability: Applicability) -> &mut Self {
self.multipart_suggestion_with_style(
msg,
suggestion,
applicability,
SuggestionStyle::ShowCode,
)
}
#[doc = r" Show a suggestion that has multiple parts to it."]
#[doc = r" In other words, multiple changes need to be applied as part of this suggestion."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::multipart_suggestion()`]."]
pub fn with_multipart_suggestion(mut self, msg: impl Into<SubdiagMessage>, suggestion: Vec<(Span, String)>, applicability: Applicability) -> Self {
self.multipart_suggestion(msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_verbose(
&mut self,
msg: impl Into<SubdiagMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
self.multipart_suggestion_with_style(
msg,
suggestion,
applicability,
SuggestionStyle::ShowAlways,
)
}
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_with_style(
&mut self,
msg: impl Into<SubdiagMessage>,
mut suggestion: Vec<(Span, String)>,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
let mut seen = FxHashSet::default();
suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
let parts = suggestion
.into_iter()
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect::<Vec<_>>();
assert!(!parts.is_empty());
debug_assert_eq!(
parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
None,
"Span must not be empty and have no suggestion",
);
debug_assert_eq!(
parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
None,
"suggestion must not have overlapping parts",
);
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution { parts }],
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style,
applicability,
});
self
}
#[rustc_lint_diagnostics]
pub fn tool_only_multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
self.multipart_suggestion_with_style(
msg,
suggestion,
applicability,
SuggestionStyle::CompletelyHidden,
)
}
#[doc = r" Prints out a message with a suggested edit of the code."]
#[doc = r""]
#[doc = r" In case of short messages and a simple suggestion, rustc displays it as a label:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc = r" try adding parentheses: `(tup.0).1`"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" The message"]
#[doc = r""]
#[doc = r" * should not end in any punctuation (a `:` is added automatically)"]
#[doc = r#" * should not be a question (avoid language like "did you mean")"#]
#[doc = r#" * should not contain any phrases like "the following", "as shown", etc."#]
#[doc = r#" * may look like "to do xyz, use" or "to do xyz, use abc""#]
#[doc = r" * may contain a name of a function, variable, or type, but not whole expressions"]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion()`]."]
pub fn span_suggestion(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::ShowCode,
);
self
}
#[doc = r" Prints out a message with a suggested edit of the code."]
#[doc = r""]
#[doc = r" In case of short messages and a simple suggestion, rustc displays it as a label:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc = r" try adding parentheses: `(tup.0).1`"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" The message"]
#[doc = r""]
#[doc = r" * should not end in any punctuation (a `:` is added automatically)"]
#[doc = r#" * should not be a question (avoid language like "did you mean")"#]
#[doc = r#" * should not contain any phrases like "the following", "as shown", etc."#]
#[doc = r#" * may look like "to do xyz, use" or "to do xyz, use abc""#]
#[doc = r" * may contain a name of a function, variable, or type, but not whole expressions"]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion()`]."]
pub fn with_span_suggestion(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.span_suggestion(sp, msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn span_suggestion_with_style(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
debug_assert!(
!(sp.is_empty() && suggestion.to_string().is_empty()),
"Span must not be empty and have no suggestion"
);
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
}],
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style,
applicability,
});
self
}
#[doc = r" Always show the suggested change."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_verbose()`]."]
pub fn span_suggestion_verbose(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::ShowAlways,
);
self
}
#[doc = r" Always show the suggested change."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_verbose()`]."]
pub fn with_span_suggestion_verbose(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.span_suggestion_verbose(sp, msg, suggestion, applicability);
self
}
#[doc = r" Prints out a message with multiple suggested edits of the code."]
#[doc = r" See also [`Diag::span_suggestion()`]."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestions()`]."]
pub fn span_suggestions(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestions: impl IntoIterator<Item=String>, applicability: Applicability) -> &mut Self {
self.span_suggestions_with_style(
sp,
msg,
suggestions,
applicability,
SuggestionStyle::ShowCode,
)
}
#[doc = r" Prints out a message with multiple suggested edits of the code."]
#[doc = r" See also [`Diag::span_suggestion()`]."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestions()`]."]
pub fn with_span_suggestions(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestions: impl IntoIterator<Item=String>, applicability: Applicability) -> Self {
self.span_suggestions(sp, msg, suggestions, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn span_suggestions_with_style(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
suggestions: impl IntoIterator<Item=String>,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
let substitutions = suggestions
.into_iter()
.map(|snippet| {
debug_assert!(
!(sp.is_empty() && snippet.is_empty()),
"Span must not be empty and have no suggestion"
);
Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }
})
.collect();
self.push_suggestion(CodeSuggestion {
substitutions,
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style,
applicability,
});
self
}
#[rustc_lint_diagnostics]
pub fn multipart_suggestions(
&mut self,
msg: impl Into<SubdiagMessage>,
suggestions: impl IntoIterator<Item=Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
let substitutions = suggestions
.into_iter()
.map(|sugg| {
let mut parts = sugg
.into_iter()
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect::<Vec<_>>();
parts.sort_unstable_by_key(|part| part.span);
assert!(!parts.is_empty());
debug_assert_eq!(
parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
None,
"Span must not be empty and have no suggestion",
);
debug_assert_eq!(
parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
None,
"suggestion must not have overlapping parts",
);
Substitution { parts }
})
.collect();
self.push_suggestion(CodeSuggestion {
substitutions,
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style: SuggestionStyle::ShowCode,
applicability,
});
self
}
#[doc = r" Prints out a message with a suggested edit of the code. If the suggestion is presented"]
#[doc = r" inline, it will only show the message and not the suggestion."]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_short()`]."]
pub fn span_suggestion_short(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::HideCodeInline,
);
self
}
#[doc = r" Prints out a message with a suggested edit of the code. If the suggestion is presented"]
#[doc = r" inline, it will only show the message and not the suggestion."]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_short()`]."]
pub fn with_span_suggestion_short(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.span_suggestion_short(sp, msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::HideCodeAlways,
);
self
}
#[doc = r" Adds a suggestion to the JSON output that will not be shown in the CLI."]
#[doc = r""]
#[doc = r" This is intended to be used for suggestions that are *very* obvious in what the changes"]
#[doc = r" need to be from the message, but we still want other tools to be able to apply them."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::tool_only_span_suggestion()`]."]
pub fn tool_only_span_suggestion(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::CompletelyHidden,
);
self
}
#[doc = r" Adds a suggestion to the JSON output that will not be shown in the CLI."]
#[doc = r""]
#[doc = r" This is intended to be used for suggestions that are *very* obvious in what the changes"]
#[doc = r" need to be from the message, but we still want other tools to be able to apply them."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::tool_only_span_suggestion()`]."]
pub fn with_tool_only_span_suggestion(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.tool_only_span_suggestion(sp, msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
subdiagnostic.add_to_diag(self);
self
}
pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
let args = self.args.iter();
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
self.dcx.eagerly_translate(msg, args)
}
#[doc = r" Add a span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span()`]."]
pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
self.sort_span = span;
}
self
}
#[doc = r" Add a span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span()`]."]
pub fn with_span(mut self, sp: impl Into<MultiSpan>) -> Self {
self.span(sp);
self
}
#[rustc_lint_diagnostics]
pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
self.is_lint = Some(IsLint { name, has_future_breakage });
self
}
#[doc = r" Add an error code."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::code()`]."]
pub fn code(&mut self, code: ErrCode) -> &mut Self {
self.code = Some(code);
self
}
#[doc = r" Add an error code."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::code()`]."]
pub fn with_code(mut self, code: ErrCode) -> Self {
self.code(code);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::lint_id()`]."]
pub fn lint_id(&mut self, id: LintExpectationId) -> &mut Self {
self.lint_id = Some(id);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::lint_id()`]."]
pub fn with_lint_id(mut self, id: LintExpectationId) -> Self {
self.lint_id(id);
self
}
#[doc = r" Add a primary message."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::primary_message()`]."]
pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle);
self
}
#[doc = r" Add a primary message."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::primary_message()`]."]
pub fn with_primary_message(mut self, msg: impl Into<DiagMessage>) -> Self {
self.primary_message(msg);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::arg()`]."]
pub fn arg(&mut self, name: impl Into<diagnostic::DiagArgName>, arg: impl crate::IntoDiagArg) -> &mut Self {
self.deref_mut().arg(name, arg);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::arg()`]."]
pub fn with_arg(mut self, name: impl Into<diagnostic::DiagArgName>, arg: impl crate::IntoDiagArg) -> Self {
self.arg(name, arg);
self
}
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagMessage>,
) -> DiagMessage {
self.deref().subdiagnostic_message_to_diagnostic_message(attr)
}
pub fn sub(&mut self, level: diagnostic::DiagnosticLevel, message: impl Into<SubdiagMessage>, span: MultiSpan) {
self.deref_mut().sub(level, message, span);
}
fn sub_with_highlights(&mut self, level: diagnostic::DiagnosticLevel, messages: Vec<StringPart>, span: MultiSpan) {
let messages = messages
.into_iter()
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
.collect();
let sub = crate::Subdiag { level, messages, span };
self.children.push(sub);
}
fn take_diag(&mut self) -> DiagInner {
if let Some(path) = &self.long_ty_path {
self.note(format!(
"the full name for the type has been written to '{}'",
path.display()
));
self.note("consider using `--verbose` to print the full type name to the console");
}
Box::into_inner(self.diag.take().unwrap())
}
pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
&mut self.long_ty_path
}
pub fn emit_producing_nothing(mut self) {
let diag = self.take_diag();
self.dcx.emit_diagnostic(diag);
}
pub fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
let diag = self.take_diag();
assert!(
matches!(diag.level, Level::Error | Level::DelayedBug),
"invalid diagnostic level ({:?})",
diag.level,
);
let guar = self.dcx.emit_diagnostic(diag);
guar.unwrap()
}
#[track_caller]
pub fn emit(self) -> G::EmitResult {
G::emit_producing_guarantee(self)
}
#[track_caller]
pub fn emit_unless(mut self, delay: bool) -> G::EmitResult {
if delay {
self.downgrade_to_delayed_bug();
}
self.emit()
}
pub fn cancel(mut self) {
self.diag = None;
drop(self);
}
pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
let diag = self.take_diag();
self.dcx.stash_diagnostic(span, key, diag)
}
#[track_caller]
pub fn delay_as_bug(mut self) -> G::EmitResult {
self.downgrade_to_delayed_bug();
self.emit()
}
}
impl<G: diagnostic::EmissionGuarantee> Drop for crate::Diag<'_, G> {
fn drop(&mut self) {
match self.diag.take() {
Some(diag) if !panicking() => {
self.dcx.emit_diagnostic(DiagInner::new(
diagnostic::DiagnosticLevel::Bug,
DiagMessage::from("the following error was constructed but not emitted"),
));
self.dcx.emit_diagnostic(*diag);
panic!("error was constructed but not emitted");
}
_ => {}
}
}
}
impl fmt::Display for crate::DiagnosticLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.to_str().fmt(f)
}
}
impl crate::DiagnosticLevel {
pub fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new();
match self {
crate::DiagnosticLevel::Bug | crate::DiagnosticLevel::Fatal | crate::DiagnosticLevel::Error | crate::DiagnosticLevel::DelayedBug => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
crate::DiagnosticLevel::ForceWarning | crate::DiagnosticLevel::Warning => {
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
}
crate::DiagnosticLevel::Note | crate::DiagnosticLevel::OnceNote => {
spec.set_fg(Some(Color::Green)).set_intense(true);
}
crate::DiagnosticLevel::Help | crate::DiagnosticLevel::OnceHelp => {
spec.set_fg(Some(Color::Cyan)).set_intense(true);
}
crate::DiagnosticLevel::FailureNote => {}
crate::DiagnosticLevel::Allow | crate::DiagnosticLevel::Expect => unreachable!(),
}
spec
}
pub fn to_str(self) -> &'static str {
match self {
crate::DiagnosticLevel::Bug | crate::DiagnosticLevel::DelayedBug => "error: internal compiler error",
crate::DiagnosticLevel::Fatal | crate::DiagnosticLevel::Error => "error",
crate::DiagnosticLevel::ForceWarning | crate::DiagnosticLevel::Warning => "warning",
crate::DiagnosticLevel::Note | crate::DiagnosticLevel::OnceNote => "note",
crate::DiagnosticLevel::Help | crate::DiagnosticLevel::OnceHelp => "help",
crate::DiagnosticLevel::FailureNote => "failure-note",
crate::DiagnosticLevel::Allow | crate::DiagnosticLevel::Expect => unreachable!(),
}
}
pub fn is_failure_note(&self) -> bool {
matches!(*self, DiagnosticLevel::FailureNote)
}
fn can_be_subdiag(&self) -> bool {
match self {
crate::DiagnosticLevel::Bug |
crate::DiagnosticLevel::DelayedBug |
crate::DiagnosticLevel::Fatal |
crate::DiagnosticLevel::Error |
crate::DiagnosticLevel::ForceWarning |
crate::DiagnosticLevel::FailureNote |
crate::DiagnosticLevel::Allow |
crate::DiagnosticLevel::Expect => false,
crate::DiagnosticLevel::Warning |
crate::DiagnosticLevel::Note |
crate::DiagnosticLevel::Help |
crate::DiagnosticLevel::OnceNote |
crate::DiagnosticLevel::OnceHelp => true,
}
}
}
impl diagnostic::EmissionGuarantee for () {
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
todo!()
}
}
impl diagnostic::EmissionGuarantee for FatalGuarantee {
const CONTINUEABLE: bool = false; type RecoveryHandler = diagnostic::FatalRecovery;
fn emit_producing_guarantee(diag: crate::Diag<'_, Self>) -> Self::EmitResult {
}
}
impl RecoveryHandler<FatalGuarantee> for FatalRecovery {
fn attempt_recovery(result: &FatalGuarantee) -> Option<RecoveredState> {
if result.kind.is_structurally_broken() {
None } else {
Some(RecoveredState::from_fatal(result))
}
}
}
impl EmissionGuarantee for FatalGuarantee {
const CONTINUEABLE: bool = false;
type RecoveryHandler = FatalRecovery;
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
}
}
impl DiagInner {
#[track_caller]
pub fn new<M: Into<DiagMessage>>(level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel, message: M) -> Self {
DiagInner::new_with_messages(level, vec![(message.into(), Style::NoStyle)])
}
#[track_caller]
pub fn new_with_messages(level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel, messages: Vec<(DiagMessage, Style)>) -> Self {
DiagInner {
level,
lint_id: None,
messages,
code: None,
span: MultiSpan::new(),
children: vec![],
suggestions: Suggestions::Enabled(vec![]),
args: Default::default(),
sort_span: DUMMY_SP,
is_lint: None,
long_ty_path: None,
emitted_at: DiagLocation::caller(),
}
}
#[inline(always)]
pub fn level(&self) -> crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel {
self.level
}
pub fn is_error(&self) -> bool {
match self.level {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Bug | crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Fatal | crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Error | crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::DelayedBug => true,
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::ForceWarning
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Warning
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Note
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::OnceNote
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Help
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::OnceHelp
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::FailureNote
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Allow
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Expect => false,
}
}
pub(crate) fn has_future_breakage(&self) -> bool {
matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))
}
pub(crate) fn is_force_warn(&self) -> bool {
match self.level {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::ForceWarning => {
assert!(self.is_lint.is_some());
true
}
_ => false,
}
}
pub fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagMessage>,
) -> DiagMessage {
let msg =
self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
msg.with_subdiagnostic_message(attr.into())
}
pub(crate) fn sub(
&mut self,
level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel,
message: impl Into<SubdiagMessage>,
span: MultiSpan,
) {
let sub = Subdiag {
level,
messages: vec![(
self.subdiagnostic_message_to_diagnostic_message(message),
Style::NoStyle,
)],
span,
};
self.children.push(sub);
}
pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path));
}
fn keys(
&self,
) -> (
&crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel,
&[(DiagMessage, Style)],
&Option<ErrCode>,
&MultiSpan,
&[Subdiag],
&Suggestions,
Vec<(&DiagArgName, &DiagArgValue)>,
&Option<IsLint>,
) {
(
&self.level,
&self.messages,
&self.code,
&self.span,
&self.children,
&self.suggestions,
self.args.iter().collect(),
&self.is_lint,
)
}
}
impl Hash for DiagInner {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.keys().hash(state);
}
}
impl PartialEq for DiagInner {
fn eq(&self, other: &Self) -> bool {
self.keys() == other.keys()
}
}
impl IntoDiagArg for DiagArgValue {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
self
}
}
impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
type Target = &'a DiagCtxt;
fn deref(&self) -> &Self::Target {
&self.dcx
}
}
}
pub use traits::*;
pub use structures::*;
pub use implementations::*;
#[macro_export]
macro_rules! debug {
(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
);
(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+)
);
(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
);
(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
);
(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, {}, $($arg)+)
);
(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(target: $target:expr, $($arg:tt)+ ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+)
);
(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ $($field)+ },
$($arg)+
)
);
(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ $($k).+ = $($field)*}
)
);
(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ ?$($k).+ = $($field)*}
)
);
(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ %$($k).+ = $($field)*}
)
);
(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ $($k).+, $($field)*}
)
);
(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ ?$($k).+, $($field)*}
)
);
(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ %$($k).+, $($field)*}
)
);
(parent: $parent:expr, $($arg:tt)+) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{},
$($arg)+
)
);
({ $($field:tt)+ }, $($arg:tt)+ ) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($field)+ },
$($arg)+
)
);
($($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($k).+ = $($field)*}
)
);
(?$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ ?$($k).+ = $($field)*}
)
);
(%$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ %$($k).+ = $($field)*}
)
);
($($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($k).+, $($field)*}
)
);
(?$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ ?$($k).+, $($field)*}
)
);
(%$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ %$($k).+, $($field)*}
)
);
(?$($k:ident).+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ ?$($k).+ }
)
);
(%$($k:ident).+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ %$($k).+ }
)
);
($($k:ident).+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($k).+ }
)
);
($($arg:tt)+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
$($arg)+
)
);
}