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