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