summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_errors/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors/src/error.rs')
-rw-r--r--compiler/rustc_errors/src/error.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/compiler/rustc_errors/src/error.rs b/compiler/rustc_errors/src/error.rs
new file mode 100644
index 000000000..ec0a2fe8c
--- /dev/null
+++ b/compiler/rustc_errors/src/error.rs
@@ -0,0 +1,137 @@
+use rustc_error_messages::{
+ fluent_bundle::resolver::errors::{ReferenceKind, ResolverError},
+ FluentArgs, FluentError,
+};
+use std::borrow::Cow;
+use std::error::Error;
+use std::fmt;
+
+#[derive(Debug)]
+pub enum TranslateError<'args> {
+ One {
+ id: &'args Cow<'args, str>,
+ args: &'args FluentArgs<'args>,
+ kind: TranslateErrorKind<'args>,
+ },
+ Two {
+ primary: Box<TranslateError<'args>>,
+ fallback: Box<TranslateError<'args>>,
+ },
+}
+
+impl<'args> TranslateError<'args> {
+ pub fn message(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
+ Self::One { id, args, kind: TranslateErrorKind::MessageMissing }
+ }
+ pub fn primary(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
+ Self::One { id, args, kind: TranslateErrorKind::PrimaryBundleMissing }
+ }
+ pub fn attribute(
+ id: &'args Cow<'args, str>,
+ args: &'args FluentArgs<'args>,
+ attr: &'args str,
+ ) -> Self {
+ Self::One { id, args, kind: TranslateErrorKind::AttributeMissing { attr } }
+ }
+ pub fn value(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
+ Self::One { id, args, kind: TranslateErrorKind::ValueMissing }
+ }
+
+ pub fn fluent(
+ id: &'args Cow<'args, str>,
+ args: &'args FluentArgs<'args>,
+ errs: Vec<FluentError>,
+ ) -> Self {
+ Self::One { id, args, kind: TranslateErrorKind::Fluent { errs } }
+ }
+
+ pub fn and(self, fallback: TranslateError<'args>) -> TranslateError<'args> {
+ Self::Two { primary: Box::new(self), fallback: Box::new(fallback) }
+ }
+}
+
+#[derive(Debug)]
+pub enum TranslateErrorKind<'args> {
+ MessageMissing,
+ PrimaryBundleMissing,
+ AttributeMissing { attr: &'args str },
+ ValueMissing,
+ Fluent { errs: Vec<FluentError> },
+}
+
+impl fmt::Display for TranslateError<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use TranslateErrorKind::*;
+
+ match self {
+ Self::One { id, args, kind } => {
+ writeln!(f, "failed while formatting fluent string `{id}`: ")?;
+ match kind {
+ MessageMissing => writeln!(f, "message was missing")?,
+ PrimaryBundleMissing => writeln!(f, "the primary bundle was missing")?,
+ AttributeMissing { attr } => {
+ writeln!(f, "the attribute `{attr}` was missing")?;
+ writeln!(f, "help: add `.{attr} = <message>`")?;
+ }
+ ValueMissing => writeln!(f, "the value was missing")?,
+ Fluent { errs } => {
+ for err in errs {
+ match err {
+ FluentError::ResolverError(ResolverError::Reference(
+ ReferenceKind::Message { id, .. }
+ | ReferenceKind::Variable { id, .. },
+ )) => {
+ if args.iter().any(|(arg_id, _)| arg_id == id) {
+ writeln!(
+ f,
+ "argument `{id}` exists but was not referenced correctly"
+ )?;
+ writeln!(f, "help: try using `{{${id}}}` instead")?;
+ } else {
+ writeln!(
+ f,
+ "the fluent string has an argument `{id}` that was not found."
+ )?;
+ let vars: Vec<&str> =
+ args.iter().map(|(a, _v)| a).collect();
+ match &*vars {
+ [] => writeln!(f, "help: no arguments are available")?,
+ [one] => writeln!(
+ f,
+ "help: the argument `{one}` is available"
+ )?,
+ [first, middle @ .., last] => {
+ write!(f, "help: the arguments `{first}`")?;
+ for a in middle {
+ write!(f, ", `{a}`")?;
+ }
+ writeln!(f, " and `{last}` are available")?;
+ }
+ }
+ }
+ }
+ _ => writeln!(f, "{err}")?,
+ }
+ }
+ }
+ }
+ }
+ // If someone cares about primary bundles, they'll probably notice it's missing
+ // regardless or will be using `debug_assertions`
+ // so we skip the arm below this one to avoid confusing the regular user.
+ Self::Two { primary: box Self::One { kind: PrimaryBundleMissing, .. }, fallback } => {
+ fmt::Display::fmt(fallback, f)?;
+ }
+ Self::Two { primary, fallback } => {
+ writeln!(
+ f,
+ "first, fluent formatting using the primary bundle failed:\n {primary}\n \
+ while attempting to recover by using the fallback bundle instead, another error occurred:\n{fallback}"
+ )?;
+ }
+ }
+ Ok(())
+ }
+}
+
+impl Error for TranslateError<'_> {}