1use crate::entity::SecondaryMap;
4use crate::ir;
5use crate::ir::entities::{AnyEntity, Block, Inst, Value};
6use crate::ir::function::Function;
7use crate::result::CodegenError;
8use crate::verifier::{VerifierError, VerifierErrors};
9use crate::write::{decorate_function, FuncWriter, PlainWriter};
10use alloc::boxed::Box;
11use alloc::string::{String, ToString};
12use alloc::vec::Vec;
13use core::fmt;
14use core::fmt::Write;
15
16pub fn pretty_verifier_error<'a>(
18 func: &ir::Function,
19 func_w: Option<Box<dyn FuncWriter + 'a>>,
20 errors: VerifierErrors,
21) -> String {
22 let mut errors = errors.0;
23 let mut w = String::new();
24 let num_errors = errors.len();
25
26 decorate_function(
27 &mut PrettyVerifierError(func_w.unwrap_or_else(|| Box::new(PlainWriter)), &mut errors),
28 &mut w,
29 func,
30 )
31 .unwrap();
32
33 writeln!(
34 w,
35 "\n; {} verifier error{} detected (see above). Compilation aborted.",
36 num_errors,
37 if num_errors == 1 { "" } else { "s" }
38 )
39 .unwrap();
40
41 w
42}
43
44struct PrettyVerifierError<'a>(Box<dyn FuncWriter + 'a>, &'a mut Vec<VerifierError>);
45
46impl<'a> FuncWriter for PrettyVerifierError<'a> {
47 fn write_block_header(
48 &mut self,
49 w: &mut dyn Write,
50 func: &Function,
51 block: Block,
52 indent: usize,
53 ) -> fmt::Result {
54 pretty_block_header_error(w, func, block, indent, &mut *self.0, self.1)
55 }
56
57 fn write_instruction(
58 &mut self,
59 w: &mut dyn Write,
60 func: &Function,
61 aliases: &SecondaryMap<Value, Vec<Value>>,
62 inst: Inst,
63 indent: usize,
64 ) -> fmt::Result {
65 pretty_instruction_error(w, func, aliases, inst, indent, &mut *self.0, self.1)
66 }
67
68 fn write_entity_definition(
69 &mut self,
70 w: &mut dyn Write,
71 func: &Function,
72 entity: AnyEntity,
73 value: &dyn fmt::Display,
74 ) -> fmt::Result {
75 pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1)
76 }
77}
78
79fn pretty_block_header_error(
81 w: &mut dyn Write,
82 func: &Function,
83 cur_block: Block,
84 indent: usize,
85 func_w: &mut dyn FuncWriter,
86 errors: &mut Vec<VerifierError>,
87) -> fmt::Result {
88 let mut s = String::new();
89 func_w.write_block_header(&mut s, func, cur_block, indent)?;
90 write!(w, "{}", s)?;
91
92 let mut i = 0;
94 let mut printed_error = false;
95 while i != errors.len() {
96 match errors[i].location {
97 ir::entities::AnyEntity::Block(block) if block == cur_block => {
98 if !printed_error {
99 print_arrow(w, &s)?;
100 printed_error = true;
101 }
102 let err = errors.remove(i);
103 print_error(w, err)?;
104 }
105 _ => i += 1,
106 }
107 }
108
109 if printed_error {
110 w.write_char('\n')?;
111 }
112
113 Ok(())
114}
115
116fn pretty_instruction_error(
118 w: &mut dyn Write,
119 func: &Function,
120 aliases: &SecondaryMap<Value, Vec<Value>>,
121 cur_inst: Inst,
122 indent: usize,
123 func_w: &mut dyn FuncWriter,
124 errors: &mut Vec<VerifierError>,
125) -> fmt::Result {
126 let mut s = String::new();
127 func_w.write_instruction(&mut s, func, aliases, cur_inst, indent)?;
128 write!(w, "{}", s)?;
129
130 let mut i = 0;
132 let mut printed_error = false;
133 while i != errors.len() {
134 match errors[i].location {
135 ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
136 if !printed_error {
137 print_arrow(w, &s)?;
138 printed_error = true;
139 }
140 let err = errors.remove(i);
141 print_error(w, err)?;
142 }
143 _ => i += 1,
144 }
145 }
146
147 if printed_error {
148 w.write_char('\n')?;
149 }
150
151 Ok(())
152}
153
154fn pretty_preamble_error(
155 w: &mut dyn Write,
156 func: &Function,
157 entity: AnyEntity,
158 value: &dyn fmt::Display,
159 func_w: &mut dyn FuncWriter,
160 errors: &mut Vec<VerifierError>,
161) -> fmt::Result {
162 let mut s = String::new();
163 func_w.write_entity_definition(&mut s, func, entity, value)?;
164 write!(w, "{}", s)?;
165
166 let mut i = 0;
168 let mut printed_error = false;
169 while i != errors.len() {
170 if entity == errors[i].location {
171 if !printed_error {
172 print_arrow(w, &s)?;
173 printed_error = true;
174 }
175 let err = errors.remove(i);
176 print_error(w, err)?;
177 } else {
178 i += 1
179 }
180 }
181
182 if printed_error {
183 w.write_char('\n')?;
184 }
185
186 Ok(())
187}
188
189fn print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result {
192 write!(w, ";")?;
193
194 let indent = entity.len() - entity.trim_start().len();
195 if indent != 0 {
196 write!(w, "{1:0$}^", indent - 1, "")?;
197 }
198
199 for _ in 0..entity.trim().len() - 1 {
200 write!(w, "~")?;
201 }
202
203 writeln!(w)
204}
205
206fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result {
209 writeln!(w, "; error: {}", err.to_string())?;
210 Ok(())
211}
212
213pub fn pretty_error(func: &ir::Function, err: CodegenError) -> String {
215 if let CodegenError::Verifier(e) = err {
216 pretty_verifier_error(func, None, e)
217 } else {
218 err.to_string()
219 }
220}