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.
17 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> {
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 
79 /// Pretty-print a function verifier error for a given block.
80 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.
117 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 
154 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 ///    ;   ^~~~~~
191 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]
208 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.
214 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