about summary refs log tree commit diff
path: root/compiler/rustc_errors/src/error.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-11 17:01:44 +0000
committerbors <bors@rust-lang.org>2023-01-11 17:01:44 +0000
commitef4046e4f3932991971cdb64915172899532aece (patch)
tree0d19af73ce4d98d239abf182b4dc07a44dff124f /compiler/rustc_errors/src/error.rs
parentb22c152958eade17a71d899b29a2d39bcc77aa48 (diff)
parent9aeef61820b4cd14b3f4cab601a95b15ced5862e (diff)
downloadrust-ef4046e4f3932991971cdb64915172899532aece.tar.gz
rust-ef4046e4f3932991971cdb64915172899532aece.zip
Auto merge of #106730 - Nilstrieb:rollup-f7p8dsa, r=Nilstrieb
Rollup of 9 pull requests

Successful merges:

 - #106321 (Collect and emit proper backtraces for `delay_span_bug`s)
 - #106397 (Check `impl`'s `where` clauses in `consider_impl_candidate` in experimental solver)
 - #106427 (Improve fluent error messages)
 - #106570 (add tests for div_duration_* functions)
 - #106648 (Polymorphization cleanup)
 - #106664 (Remove unnecessary lseek syscall when using std::fs::read)
 - #106709 (Disable "split dwarf inlining" by default.)
 - #106715 (Autolabel and ping wg for changes to new solver)
 - #106717 (fix typo LocalItemId -> ItemLocalId)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
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 00000000000..ec0a2fe8cd8
--- /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<'_> {}