1use 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}