pub use self::fatal::{FatalDiagnostic, FatalDiagnosticKind};
mod fatal;
pub use self::warning::WarningDiagnostic;
pub(crate) use self::warning::WarningDiagnosticKind;
mod warning;
pub use self::runtime_warning::RuntimeWarningDiagnostic;
pub(crate) use self::runtime_warning::RuntimeWarningDiagnosticKind;
mod runtime_warning;
use ::rust_alloc::boxed::Box;
use rune_alloc::String;
use crate::alloc::{self, Vec};
use crate::ast::Spanned;
use crate::{Hash, SourceId};
#[cfg(feature = "emit")]
#[cfg_attr(rune_docsrs, doc(cfg(feature = "emit")))]
mod emit;
#[cfg(feature = "emit")]
#[cfg_attr(rune_docsrs, doc(cfg(feature = "emit")))]
#[doc(inline)]
pub use self::emit::EmitError;
#[derive(Debug)]
#[non_exhaustive]
pub enum Diagnostic {
Fatal(FatalDiagnostic),
Warning(WarningDiagnostic),
RuntimeWarning(RuntimeWarningDiagnostic),
}
#[derive(Debug, Clone, Copy)]
enum Mode {
All,
WithoutWarnings,
}
impl Mode {
fn warnings(self) -> bool {
matches!(self, Self::All)
}
}
#[derive(Debug)]
pub struct Diagnostics {
diagnostics: Vec<Diagnostic>,
mode: Mode,
has_error: bool,
has_warning: bool,
}
impl Diagnostics {
fn with_mode(mode: Mode) -> Self {
Self {
diagnostics: Vec::new(),
mode,
has_error: false,
has_warning: false,
}
}
pub fn without_warnings() -> Self {
Self::with_mode(Mode::WithoutWarnings)
}
pub fn new() -> Self {
Self::default()
}
pub fn is_empty(&self) -> bool {
self.diagnostics.is_empty()
}
pub fn has_error(&self) -> bool {
self.has_error
}
pub fn has_warning(&self) -> bool {
self.has_warning
}
pub fn diagnostics(&self) -> &[Diagnostic] {
&self.diagnostics
}
pub fn into_diagnostics(self) -> Vec<Diagnostic> {
self.diagnostics
}
pub(crate) fn internal(
&mut self,
source_id: SourceId,
message: &'static str,
) -> alloc::Result<()> {
self.error(source_id, FatalDiagnosticKind::Internal(message))
}
pub(crate) fn not_used(
&mut self,
source_id: SourceId,
span: &dyn Spanned,
context: Option<&dyn Spanned>,
) -> alloc::Result<()> {
self.warning(
source_id,
WarningDiagnosticKind::NotUsed {
span: span.span(),
context: context.map(Spanned::span),
},
)
}
pub(crate) fn unreachable(
&mut self,
source_id: SourceId,
span: &dyn Spanned,
cause: &dyn Spanned,
) -> alloc::Result<()> {
self.warning(
source_id,
WarningDiagnosticKind::Unreachable {
span: span.span(),
cause: cause.span(),
},
)
}
pub(crate) fn let_pattern_might_panic(
&mut self,
source_id: SourceId,
span: &dyn Spanned,
context: Option<&dyn Spanned>,
) -> alloc::Result<()> {
self.warning(
source_id,
WarningDiagnosticKind::LetPatternMightPanic {
span: span.span(),
context: context.map(Spanned::span),
},
)
}
pub(crate) fn template_without_expansions(
&mut self,
source_id: SourceId,
span: &dyn Spanned,
context: Option<&dyn Spanned>,
) -> alloc::Result<()> {
self.warning(
source_id,
WarningDiagnosticKind::TemplateWithoutExpansions {
span: span.span(),
context: context.map(Spanned::span),
},
)
}
pub(crate) fn remove_tuple_call_parens(
&mut self,
source_id: SourceId,
span: &dyn Spanned,
variant: &dyn Spanned,
context: Option<&dyn Spanned>,
) -> alloc::Result<()> {
self.warning(
source_id,
WarningDiagnosticKind::RemoveTupleCallParams {
span: span.span(),
variant: variant.span(),
context: context.map(Spanned::span),
},
)
}
pub(crate) fn unnecessary_semi_colon(
&mut self,
source_id: SourceId,
span: &dyn Spanned,
) -> alloc::Result<()> {
self.warning(
source_id,
WarningDiagnosticKind::UnnecessarySemiColon { span: span.span() },
)
}
pub(crate) fn used_deprecated(
&mut self,
source_id: SourceId,
span: &dyn Spanned,
context: Option<&dyn Spanned>,
message: String,
) -> alloc::Result<()> {
self.warning(
source_id,
WarningDiagnosticKind::UsedDeprecated {
span: span.span(),
context: context.map(Spanned::span),
message,
},
)
}
pub(crate) fn runtime_used_deprecated(&mut self, ip: usize, hash: Hash) -> alloc::Result<()> {
self.runtime_warning(ip, RuntimeWarningDiagnosticKind::UsedDeprecated { hash })
}
pub(crate) fn warning<T>(&mut self, source_id: SourceId, kind: T) -> alloc::Result<()>
where
WarningDiagnosticKind: From<T>,
{
if !self.mode.warnings() {
return Ok(());
}
self.diagnostics
.try_push(Diagnostic::Warning(WarningDiagnostic {
source_id,
kind: kind.into(),
}))?;
self.has_warning = true;
Ok(())
}
pub(crate) fn runtime_warning<T>(&mut self, ip: usize, kind: T) -> alloc::Result<()>
where
RuntimeWarningDiagnosticKind: From<T>,
{
if !self.mode.warnings() {
return Ok(());
}
self.diagnostics
.try_push(Diagnostic::RuntimeWarning(RuntimeWarningDiagnostic {
ip,
kind: kind.into(),
}))?;
self.has_warning = true;
Ok(())
}
pub(crate) fn error<T>(&mut self, source_id: SourceId, kind: T) -> alloc::Result<()>
where
FatalDiagnosticKind: From<T>,
{
self.diagnostics
.try_push(Diagnostic::Fatal(FatalDiagnostic {
source_id,
kind: Box::new(kind.into()),
}))?;
self.has_error = true;
Ok(())
}
}
impl Default for Diagnostics {
fn default() -> Self {
Self::with_mode(Mode::All)
}
}