Skip to main content

hir_ide/mir_pretty/
errors.rs

1//! Pretty-printing MIR and consteval errors.
2
3use std::fmt::Write;
4
5use either::Either;
6use hir_def::{
7    GenericParamId, ItemContainerId, Lookup,
8    expr_store::{Body, ExpressionStore},
9    hir::generics::GenericParams,
10    signatures::{FunctionSignature, TraitSignature},
11};
12use hir_expand::{InFile, name::Name};
13use hir_ty::{
14    InferBodyId,
15    consteval::ConstEvalError,
16    db::HirDatabase,
17    mir::{MirEvalError, MirLowerError, MirSpan},
18};
19use macros::extension;
20use span::{FileId, TextRange};
21use syntax::SyntaxNodePtr;
22
23use crate::display::{ClosureStyle, DisplayTarget, HirDisplay};
24
25#[extension(pub trait MirLowerErrorPretty)]
26impl MirLowerError<'_> {
27    fn pretty_print(
28        &self,
29        f: &mut String,
30        db: &dyn HirDatabase,
31        span_formatter: impl Fn(FileId, TextRange) -> String,
32        display_target: DisplayTarget,
33    ) -> std::result::Result<(), std::fmt::Error> {
34        match self {
35            MirLowerError::ConstEvalError(name, e) => {
36                writeln!(f, "In evaluating constant {name}")?;
37                match &**e {
38                    ConstEvalError::MirLowerError(e) => {
39                        e.pretty_print(f, db, span_formatter, display_target)?
40                    }
41                    ConstEvalError::MirEvalError(e) => {
42                        e.pretty_print(f, db, span_formatter, display_target)?
43                    }
44                }
45            }
46            MirLowerError::MissingFunctionDefinition(owner, it) => {
47                let owner = owner.expression_store_owner(db);
48                let store = ExpressionStore::of(db, owner);
49                writeln!(
50                    f,
51                    "Missing function definition for {}",
52                    hir_def::expr_store::pretty::print_expr_hir(
53                        db,
54                        store,
55                        owner,
56                        *it,
57                        display_target.edition
58                    )
59                )?;
60            }
61            MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,
62            MirLowerError::GenericArgNotProvided(id, subst) => {
63                let param_name = match *id {
64                    GenericParamId::TypeParamId(id) => {
65                        GenericParams::of(db, id.parent())[id.local_id()].name().cloned()
66                    }
67                    GenericParamId::ConstParamId(id) => {
68                        GenericParams::of(db, id.parent())[id.local_id()].name().cloned()
69                    }
70                    GenericParamId::LifetimeParamId(id) => {
71                        Some(GenericParams::of(db, id.parent)[id.local_id].name.clone())
72                    }
73                };
74                writeln!(
75                    f,
76                    "Generic arg not provided for {}",
77                    param_name.unwrap_or(Name::missing()).display(db, display_target.edition)
78                )?;
79                writeln!(f, "Provided args: [")?;
80                for g in subst.as_ref() {
81                    write!(f, "    {},", g.display(db, display_target))?;
82                }
83                writeln!(f, "]")?;
84            }
85            MirLowerError::LayoutError(_)
86            | MirLowerError::UnsizedTemporary(_)
87            | MirLowerError::IncompleteExpr
88            | MirLowerError::IncompletePattern
89            | MirLowerError::InaccessibleLocal
90            | MirLowerError::TraitFunctionDefinition(_, _)
91            | MirLowerError::UnresolvedName { .. }
92            | MirLowerError::RecordLiteralWithoutPath
93            | MirLowerError::UnresolvedMethod(_)
94            | MirLowerError::UnresolvedField
95            | MirLowerError::TypeError(_)
96            | MirLowerError::NotSupported(_)
97            | MirLowerError::ContinueWithoutLoop
98            | MirLowerError::BreakWithoutLoop
99            | MirLowerError::Loop
100            | MirLowerError::ImplementationError(_)
101            | MirLowerError::LangItemNotFound
102            | MirLowerError::MutatingRvalue
103            | MirLowerError::UnresolvedLabel
104            | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?,
105        }
106        Ok(())
107    }
108}
109
110#[extension(pub trait MirEvalErrorPretty)]
111impl MirEvalError<'_> {
112    fn pretty_print(
113        &self,
114        f: &mut String,
115        db: &dyn HirDatabase,
116        span_formatter: impl Fn(FileId, TextRange) -> String,
117        display_target: DisplayTarget,
118    ) -> std::result::Result<(), std::fmt::Error> {
119        writeln!(f, "Mir eval error:")?;
120        let mut err = self;
121        while let MirEvalError::InFunction(e, stack) = err {
122            err = e;
123            for (func, span, def) in stack.iter().take(30).rev() {
124                match func {
125                    Either::Left(func) => {
126                        let function_name = FunctionSignature::of(db, *func);
127                        writeln!(
128                            f,
129                            "In function {} ({:?})",
130                            function_name.name.display(db, display_target.edition),
131                            func
132                        )?;
133                    }
134                    Either::Right(closure) => {
135                        writeln!(f, "In {closure:?}")?;
136                    }
137                }
138                let (source_map, self_param_syntax) = match *def {
139                    InferBodyId::DefWithBodyId(def) => {
140                        let body = &Body::with_source_map(db, def).1;
141                        (&**body, body.self_param_syntax())
142                    }
143                    InferBodyId::AnonConstId(def) => {
144                        let store = ExpressionStore::with_source_map(db, def.loc(db).owner).1;
145                        (store, None)
146                    }
147                };
148                let span: InFile<SyntaxNodePtr> = match *span {
149                    MirSpan::ExprId(e) => match source_map.expr_syntax(e) {
150                        Ok(s) => s.map(|it| it.into()),
151                        Err(_) => continue,
152                    },
153                    MirSpan::PatId(p) => match source_map.pat_syntax(p) {
154                        Ok(s) => s.map(|it| it.syntax_node_ptr()),
155                        Err(_) => continue,
156                    },
157                    MirSpan::BindingId(b) => {
158                        match source_map
159                            .patterns_for_binding(b)
160                            .iter()
161                            .find_map(|p| source_map.pat_syntax(*p).ok())
162                        {
163                            Some(s) => s.map(|it| it.syntax_node_ptr()),
164                            None => continue,
165                        }
166                    }
167                    MirSpan::SelfParam => match self_param_syntax {
168                        Some(s) => s.map(|it| it.syntax_node_ptr()),
169                        None => continue,
170                    },
171                    MirSpan::Unknown => continue,
172                };
173                let file_id = span.file_id.original_file(db);
174                let text_range = span.value.text_range();
175                writeln!(f, "{}", span_formatter(file_id.file_id(db), text_range))?;
176            }
177        }
178        match err {
179            MirEvalError::InFunction(..) => unreachable!(),
180            MirEvalError::LayoutError(err, ty) => {
181                write!(
182                    f,
183                    "Layout for type `{}` is not available due {err:?}",
184                    ty.as_ref()
185                        .display(db, display_target)
186                        .with_closure_style(ClosureStyle::ClosureWithId)
187                )?;
188            }
189            MirEvalError::MirLowerError(func, err) => {
190                let function_name = FunctionSignature::of(db, *func);
191                let self_ = match func.lookup(db).container {
192                    ItemContainerId::ImplId(impl_id) => Some({
193                        db.impl_self_ty(impl_id)
194                            .instantiate_identity()
195                            .skip_norm_wip()
196                            .display(db, display_target)
197                            .to_string()
198                    }),
199                    ItemContainerId::TraitId(it) => Some(
200                        TraitSignature::of(db, it)
201                            .name
202                            .display(db, display_target.edition)
203                            .to_string(),
204                    ),
205                    _ => None,
206                };
207                writeln!(
208                    f,
209                    "MIR lowering for function `{}{}{}` ({:?}) failed due:",
210                    self_.as_deref().unwrap_or_default(),
211                    if self_.is_some() { "::" } else { "" },
212                    function_name.name.display(db, display_target.edition),
213                    func
214                )?;
215                err.pretty_print(f, db, span_formatter, display_target)?;
216            }
217            MirEvalError::ConstEvalError(name, err) => {
218                MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
219                    f,
220                    db,
221                    span_formatter,
222                    display_target,
223                )?;
224            }
225            MirEvalError::UndefinedBehavior(_)
226            | MirEvalError::TargetDataLayoutNotAvailable(_)
227            | MirEvalError::Panic(_)
228            | MirEvalError::MirLowerErrorForClosure(_, _)
229            | MirEvalError::TypeIsUnsized(_, _)
230            | MirEvalError::NotSupported(_)
231            | MirEvalError::InvalidConst
232            | MirEvalError::ExecutionLimitExceeded
233            | MirEvalError::StackOverflow
234            | MirEvalError::CoerceUnsizedError(_)
235            | MirEvalError::InternalError(_)
236            | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?,
237        }
238        Ok(())
239    }
240
241    fn is_panic(&self) -> Option<&str> {
242        let mut err = self;
243        while let MirEvalError::InFunction(e, _) = err {
244            err = e;
245        }
246        match err {
247            MirEvalError::Panic(msg) => Some(msg),
248            _ => None,
249        }
250    }
251}
252
253#[extension(pub trait ConstEvalErrorPretty)]
254impl ConstEvalError<'_> {
255    fn pretty_print(
256        &self,
257        f: &mut String,
258        db: &dyn HirDatabase,
259        span_formatter: impl Fn(span::FileId, span::TextRange) -> String,
260        display_target: DisplayTarget,
261    ) -> std::result::Result<(), std::fmt::Error> {
262        match self {
263            ConstEvalError::MirLowerError(e) => {
264                e.pretty_print(f, db, span_formatter, display_target)
265            }
266            ConstEvalError::MirEvalError(e) => {
267                e.pretty_print(f, db, span_formatter, display_target)
268            }
269        }
270    }
271}