1use crate::Type;
2use std::rc::Rc;
3use terl::{Message, Span, WithSpan};
4
5#[derive(Debug, Clone)]
6pub enum DeclareError {
7 UniqueDeleted {
8 reason: Box<DeclareError>,
9 },
10 NonBranchSelected {
11 expect: String,
12 },
13 ConflictSelected {
14 conflict_with: Type,
15 this: Type,
16 },
17 NeverUsed {
18 in_group: Span,
19 reason: Option<Box<DeclareError>>,
20 },
21 Declared {
23 declare_as: Type,
24 },
25 Unexpect {
26 expect: String,
27 },
28 ShouldAlign {
29 left: Span,
30 right: Span,
31 },
32 WithLocation {
33 location: Span,
34 error: Box<DeclareError>,
35 },
36 WithPrevious {
37 previous: Type,
38 error: Box<DeclareError>,
39 },
40 Shared {
41 err: Rc<DeclareError>,
42 },
43
44 Filtered,
45 Empty,
46}
47
48impl DeclareError {
49 pub fn with_location(self, location: Span) -> Self {
50 Self::WithLocation {
51 location,
52 error: Box::new(self),
53 }
54 }
55
56 pub fn into_shared(self) -> Self {
57 Self::Shared { err: Rc::new(self) }
58 }
59
60 pub fn with_previous(self, previous: Type) -> Self {
61 Self::WithPrevious {
62 previous,
63 error: Box::new(self),
64 }
65 }
66
67 fn generate_inner(&self, msgs: &mut Vec<terl::Message>) {
68 match self {
69 DeclareError::UniqueDeleted { reason } => {
70 msgs.push(Message::Text(
71 "this has been declared, but filtered latter".to_owned(),
72 ));
73 reason.generate_inner(msgs)
74 }
75 DeclareError::NonBranchSelected { expect } => {
76 msgs.push(Message::Text(format!("this should be `{expect}`")))
77 }
78 DeclareError::ConflictSelected {
79 conflict_with,
80 this,
81 } => msgs.push(Message::Text(format!(
82 "this is required to been declared as {} and {} together, but its impossiable",
83 this, conflict_with
84 ))),
85 DeclareError::NeverUsed { reason, in_group } => {
86 msgs.push(in_group.make_message("the branch is never used in group"));
87 if let Some(reason) = reason.as_ref() {
88 reason.generate_inner(msgs)
89 }
90 }
91
92 DeclareError::ShouldAlign { left, right } => {
93 msgs.push("those two has been declared to have same type".into());
94 msgs.push((*left).into());
95 msgs.push((*right).into());
96 }
97 DeclareError::Declared { declare_as } => msgs.push(Message::Text(format!(
98 "this has been declared as {declare_as}"
99 ))),
100 DeclareError::Unexpect { expect } => msgs.push(Message::Text(format!(
101 "expect this to be declared as `{}`",
102 expect.to_owned()
103 ))),
104 DeclareError::Filtered => msgs.push(Message::Text("this has been filtered".to_owned())),
105 DeclareError::Shared { err } => err.generate_inner(msgs),
106
107 DeclareError::WithLocation { location, error } => {
108 let len = msgs.len();
109 error.generate_inner(msgs);
110 if let Message::Text(ref mut msg) = msgs[len] {
111 msgs[len] = Message::Rich(std::mem::take(msg), *location)
112 }
113 }
114 DeclareError::WithPrevious { previous, error } => {
115 error.generate_inner(msgs);
116 msgs.push(Message::Text(format!(
117 "note: this used to be guessed as {previous}"
118 )))
119 }
120 DeclareError::Empty => {}
121 }
122 }
123
124 pub fn generate(&self) -> Vec<terl::Message> {
125 let mut msgs = vec![];
126 self.generate_inner(&mut msgs);
127 msgs
128 }
129}