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