1 //! Utility routines for pretty-printing error messages.
2
3 use crate::entity::SecondaryMap;
4 use crate::ir;
5 use crate::ir::entities::{AnyEntity, Block, Inst, Value};
6 use crate::ir::function::Function;
7 use crate::result::CodegenError;
8 use crate::verifier::{VerifierError, VerifierErrors};
9 use crate::write::{FuncWriter, PlainWriter, decorate_function};
10 use alloc::boxed::Box;
11 use alloc::string::{String, ToString};
12 use alloc::vec::Vec;
13 use core::fmt;
14 use core::fmt::Write;
15
16 /// Pretty-print a verifier error.
pretty_verifier_error<'a>( func: &ir::Function, func_w: Option<Box<dyn FuncWriter + 'a>>, errors: VerifierErrors, ) -> String17 pub 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
44 struct PrettyVerifierError<'a>(Box<dyn FuncWriter + 'a>, &'a mut Vec<VerifierError>);
45
46 impl<'a> FuncWriter for PrettyVerifierError<'a> {
write_block_header( &mut self, w: &mut dyn Write, func: &Function, block: Block, indent: usize, ) -> fmt::Result47 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
write_instruction( &mut self, w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, inst: Inst, indent: usize, ) -> fmt::Result57 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
write_entity_definition( &mut self, w: &mut dyn Write, func: &Function, entity: AnyEntity, value: &dyn fmt::Display, ) -> fmt::Result68 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
79 /// Pretty-print a function verifier error for a given block.
pretty_block_header_error( w: &mut dyn Write, func: &Function, cur_block: Block, indent: usize, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result80 fn 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 // TODO: Use drain_filter here when it gets stabilized
93 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
116 /// Pretty-print a function verifier error for a given instruction.
pretty_instruction_error( w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, cur_inst: Inst, indent: usize, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result117 fn 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 // TODO: Use drain_filter here when it gets stabilized
131 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
pretty_preamble_error( w: &mut dyn Write, func: &Function, entity: AnyEntity, value: &dyn fmt::Display, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result154 fn 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 // TODO: Use drain_filter here when it gets stabilized
167 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
189 /// Prints:
190 /// ; ^~~~~~
print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result191 fn 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
206 /// Prints:
207 /// ; error: [ERROR BODY]
print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result208 fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result {
209 writeln!(w, "; error: {}", err.to_string())?;
210 Ok(())
211 }
212
213 /// Pretty-print a Cranelift error.
pretty_error(func: &ir::Function, err: CodegenError) -> String214 pub 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 }
221