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