1 #![allow(
2     clippy::iter_cloned_collect,
3     clippy::option_if_let_else,
4     clippy::uninlined_format_args
5 )]
6 
7 use std::fmt::Display;
8 use thiserror::Error;
9 
10 // Some of the elaborate cases from the rcc codebase, which is a C compiler in
11 // Rust. https://github.com/jyn514/rcc/blob/0.8.0/src/data/error.rs
12 #[derive(Error, Debug)]
13 pub enum CompilerError {
14     #[error("cannot shift {} by {maximum} or more bits (got {current})", if *.is_left { "left" } else { "right" })]
15     TooManyShiftBits {
16         is_left: bool,
17         maximum: u64,
18         current: u64,
19     },
20 
21     #[error("#error {}", (.0).iter().copied().collect::<Vec<_>>().join(" "))]
22     User(Vec<&'static str>),
23 
24     #[error("overflow while parsing {}integer literal",
25         if let Some(signed) = .is_signed {
26             if *signed { "signed "} else { "unsigned "}
27         } else {
28             ""
29         }
30     )]
31     IntegerOverflow { is_signed: Option<bool> },
32 
33     #[error("overflow while parsing {}integer literal", match .is_signed {
34         Some(true) => "signed ",
35         Some(false) => "unsigned ",
36         None => "",
37     })]
38     IntegerOverflow2 { is_signed: Option<bool> },
39 }
40 
41 // Examples drawn from Rustup.
42 #[derive(Error, Debug)]
43 pub enum RustupError {
44     #[error(
45         "toolchain '{name}' does not contain component {component}{}",
46         .suggestion
47             .as_ref()
48             .map_or_else(String::new, |s| format!("; did you mean '{}'?", s)),
49     )]
50     UnknownComponent {
51         name: String,
52         component: String,
53         suggestion: Option<String>,
54     },
55 }
56 
57 fn assert<T: Display>(expected: &str, value: T) {
58     assert_eq!(expected, value.to_string());
59 }
60 
61 #[test]
62 fn test_rcc() {
63     assert(
64         "cannot shift left by 32 or more bits (got 50)",
65         CompilerError::TooManyShiftBits {
66             is_left: true,
67             maximum: 32,
68             current: 50,
69         },
70     );
71 
72     assert("#error A B C", CompilerError::User(vec!["A", "B", "C"]));
73 
74     assert(
75         "overflow while parsing signed integer literal",
76         CompilerError::IntegerOverflow {
77             is_signed: Some(true),
78         },
79     );
80 }
81 
82 #[test]
83 fn test_rustup() {
84     assert(
85         "toolchain 'nightly' does not contain component clipy; did you mean 'clippy'?",
86         RustupError::UnknownComponent {
87             name: "nightly".to_owned(),
88             component: "clipy".to_owned(),
89             suggestion: Some("clippy".to_owned()),
90         },
91     );
92 }
93