cranelift_codegen/
print_errors.rs

1//! Utility routines for pretty-printing error messages.
2
3use 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
16/// Pretty-print a verifier error.
17pub 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
79/// Pretty-print a function verifier error for a given block.
80fn 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.
117fn 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
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    // 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///    ;   ^~~~~~
191fn 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]
208fn 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.
214pub 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}