]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_errors/src/error.rs
Rollup merge of #106625 - Swatinem:ref/cov6, r=nagisa
[rust.git] / compiler / rustc_errors / src / error.rs
1 use rustc_error_messages::{
2     fluent_bundle::resolver::errors::{ReferenceKind, ResolverError},
3     FluentArgs, FluentError,
4 };
5 use std::borrow::Cow;
6 use std::error::Error;
7 use std::fmt;
8
9 #[derive(Debug)]
10 pub enum TranslateError<'args> {
11     One {
12         id: &'args Cow<'args, str>,
13         args: &'args FluentArgs<'args>,
14         kind: TranslateErrorKind<'args>,
15     },
16     Two {
17         primary: Box<TranslateError<'args>>,
18         fallback: Box<TranslateError<'args>>,
19     },
20 }
21
22 impl<'args> TranslateError<'args> {
23     pub fn message(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
24         Self::One { id, args, kind: TranslateErrorKind::MessageMissing }
25     }
26     pub fn primary(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
27         Self::One { id, args, kind: TranslateErrorKind::PrimaryBundleMissing }
28     }
29     pub fn attribute(
30         id: &'args Cow<'args, str>,
31         args: &'args FluentArgs<'args>,
32         attr: &'args str,
33     ) -> Self {
34         Self::One { id, args, kind: TranslateErrorKind::AttributeMissing { attr } }
35     }
36     pub fn value(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self {
37         Self::One { id, args, kind: TranslateErrorKind::ValueMissing }
38     }
39
40     pub fn fluent(
41         id: &'args Cow<'args, str>,
42         args: &'args FluentArgs<'args>,
43         errs: Vec<FluentError>,
44     ) -> Self {
45         Self::One { id, args, kind: TranslateErrorKind::Fluent { errs } }
46     }
47
48     pub fn and(self, fallback: TranslateError<'args>) -> TranslateError<'args> {
49         Self::Two { primary: Box::new(self), fallback: Box::new(fallback) }
50     }
51 }
52
53 #[derive(Debug)]
54 pub enum TranslateErrorKind<'args> {
55     MessageMissing,
56     PrimaryBundleMissing,
57     AttributeMissing { attr: &'args str },
58     ValueMissing,
59     Fluent { errs: Vec<FluentError> },
60 }
61
62 impl fmt::Display for TranslateError<'_> {
63     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64         use TranslateErrorKind::*;
65
66         match self {
67             Self::One { id, args, kind } => {
68                 writeln!(f, "failed while formatting fluent string `{id}`: ")?;
69                 match kind {
70                     MessageMissing => writeln!(f, "message was missing")?,
71                     PrimaryBundleMissing => writeln!(f, "the primary bundle was missing")?,
72                     AttributeMissing { attr } => {
73                         writeln!(f, "the attribute `{attr}` was missing")?;
74                         writeln!(f, "help: add `.{attr} = <message>`")?;
75                     }
76                     ValueMissing => writeln!(f, "the value was missing")?,
77                     Fluent { errs } => {
78                         for err in errs {
79                             match err {
80                                 FluentError::ResolverError(ResolverError::Reference(
81                                     ReferenceKind::Message { id, .. }
82                                     | ReferenceKind::Variable { id, .. },
83                                 )) => {
84                                     if args.iter().any(|(arg_id, _)| arg_id == id) {
85                                         writeln!(
86                                             f,
87                                             "argument `{id}` exists but was not referenced correctly"
88                                         )?;
89                                         writeln!(f, "help: try using `{{${id}}}` instead")?;
90                                     } else {
91                                         writeln!(
92                                             f,
93                                             "the fluent string has an argument `{id}` that was not found."
94                                         )?;
95                                         let vars: Vec<&str> =
96                                             args.iter().map(|(a, _v)| a).collect();
97                                         match &*vars {
98                                             [] => writeln!(f, "help: no arguments are available")?,
99                                             [one] => writeln!(
100                                                 f,
101                                                 "help: the argument `{one}` is available"
102                                             )?,
103                                             [first, middle @ .., last] => {
104                                                 write!(f, "help: the arguments `{first}`")?;
105                                                 for a in middle {
106                                                     write!(f, ", `{a}`")?;
107                                                 }
108                                                 writeln!(f, " and `{last}` are available")?;
109                                             }
110                                         }
111                                     }
112                                 }
113                                 _ => writeln!(f, "{err}")?,
114                             }
115                         }
116                     }
117                 }
118             }
119             // If someone cares about primary bundles, they'll probably notice it's missing
120             // regardless or will be using `debug_assertions`
121             // so we skip the arm below this one to avoid confusing the regular user.
122             Self::Two { primary: box Self::One { kind: PrimaryBundleMissing, .. }, fallback } => {
123                 fmt::Display::fmt(fallback, f)?;
124             }
125             Self::Two { primary, fallback } => {
126                 writeln!(
127                     f,
128                     "first, fluent formatting using the primary bundle failed:\n {primary}\n \
129                     while attempting to recover by using the fallback bundle instead, another error occurred:\n{fallback}"
130                 )?;
131             }
132         }
133         Ok(())
134     }
135 }
136
137 impl Error for TranslateError<'_> {}