Skip to content

internal: Partially support panic message in MirEvalError #14843

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions crates/hir-def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@ impl Body {
pretty::print_body_hir(db, self, owner)
}

pub fn pretty_print_expr(
&self,
db: &dyn DefDatabase,
owner: DefWithBodyId,
expr: ExprId,
) -> String {
pretty::print_expr_hir(db, self, owner, expr)
}

fn new(
db: &dyn DefDatabase,
owner: DefWithBodyId,
Expand Down
11 changes: 11 additions & 0 deletions crates/hir-def/src/body/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
p.buf
}

pub(super) fn print_expr_hir(
_db: &dyn DefDatabase,
body: &Body,
_owner: DefWithBodyId,
expr: ExprId,
) -> String {
let mut p = Printer { body, buf: String::new(), indent_level: 0, needs_indent: false };
p.print_expr(expr);
p.buf
}

macro_rules! w {
($dst:expr, $($arg:tt)*) => {
{ let _ = write!($dst, $($arg)*); }
Expand Down
10 changes: 5 additions & 5 deletions crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ macro_rules! format_args {
}

fn main() {
$crate::fmt::Arguments::new_v1(&["", " ", ], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Debug::fmt), ]);
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(arg2), ::core::fmt::Debug::fmt), ]);
}
"##]],
);
Expand Down Expand Up @@ -229,7 +229,7 @@ macro_rules! format_args {
}

fn main() {
$crate::fmt::Arguments::new_v1(&["", " ", ], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Debug::fmt), ]);
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a::<A, B>()), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
}
"##]],
);
Expand Down Expand Up @@ -262,7 +262,7 @@ macro_rules! format_args {
}

fn main() {
$crate::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[$crate::fmt::ArgumentV1::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(mismatch.expected.display(db)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(mismatch.actual.display(db)), $crate::fmt::Display::fmt), ]);
::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::ArgumentV1::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]);
}
"##]],
);
Expand Down Expand Up @@ -296,7 +296,7 @@ macro_rules! format_args {
}

fn main() {
$crate::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[$crate::fmt::ArgumentV1::new(&(2), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Debug::fmt), ]);
::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::ArgumentV1::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
}
"##]],
);
Expand Down Expand Up @@ -327,7 +327,7 @@ macro_rules! format_args {
fn main() {
let _ =
/* error: no rule matches input tokens *//* parse error: expected field name or number */
$crate::fmt::Arguments::new_v1(&["", " ", ], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(), $crate::fmt::Debug::fmt), ]);
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(), ::core::fmt::Debug::fmt), ]);
}
"##]],
);
Expand Down
12 changes: 5 additions & 7 deletions crates/hir-expand/src/builtin_fn_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,16 +363,14 @@ fn format_args_expand_general(
quote!(#ident)
};
let formatter = match &*format_spec {
"?" => quote!(#DOLLAR_CRATE::fmt::Debug::fmt),
"" => quote!(#DOLLAR_CRATE::fmt::Display::fmt),
"?" => quote!(::core::fmt::Debug::fmt),
"" => quote!(::core::fmt::Display::fmt),
_ => {
// FIXME: implement the rest and return expand error here
quote!(#DOLLAR_CRATE::fmt::Display::fmt)
quote!(::core::fmt::Display::fmt)
}
};
arg_tts.push(
quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg_tree), #formatter), },
);
arg_tts.push(quote! { ::core::fmt::ArgumentV1::new(&(#arg_tree), #formatter), });
}
'}' => {
if format_iter.peek() == Some(&'}') {
Expand Down Expand Up @@ -400,7 +398,7 @@ fn format_args_expand_general(
});
let arg_tts = arg_tts.into_iter().flat_map(|arg| arg.token_trees);
let expanded = quote! {
#DOLLAR_CRATE::fmt::Arguments::new_v1(&[##part_tts], &[##arg_tts])
::core::fmt::Arguments::new_v1(&[##part_tts], &[##arg_tts])
};
ExpandResult { value: expanded, err }
}
Expand Down
2 changes: 2 additions & 0 deletions crates/hir-expand/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ pub mod known {
gt,
le,
lt,
// known fields of lang items
pieces,
// lang items
add_assign,
add,
Expand Down
39 changes: 30 additions & 9 deletions crates/hir-ty/src/consteval/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ fn simplify(e: ConstEvalError) -> ConstEvalError {
#[track_caller]
fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) {
let (db, file_id) = TestDB::with_single_file(ra_fixture);
match eval_goal(&db, file_id).map_err(simplify) {
match eval_goal(&db, file_id) {
Ok(_) => panic!("Expected fail, but it succeeded"),
Err(e) => assert!(error(e)),
Err(e) => {
assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, db))
}
}
}

Expand All @@ -38,13 +40,7 @@ fn check_number(ra_fixture: &str, answer: i128) {
let r = match eval_goal(&db, file_id) {
Ok(t) => t,
Err(e) => {
let mut err = String::new();
let span_formatter = |file, range| format!("{:?} {:?}", file, range);
match e {
ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter),
ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter),
}
.unwrap();
let err = pretty_print_err(e, db);
panic!("Error in evaluating goal: {}", err);
}
};
Expand All @@ -64,6 +60,17 @@ fn check_number(ra_fixture: &str, answer: i128) {
}
}

fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
let mut err = String::new();
let span_formatter = |file, range| format!("{:?} {:?}", file, range);
match e {
ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter),
ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter),
}
.unwrap();
err
}

fn eval_goal(db: &TestDB, file_id: FileId) -> Result<Const, ConstEvalError> {
let module_id = db.module_for_file(file_id);
let def_map = module_id.def_map(db);
Expand Down Expand Up @@ -2187,6 +2194,20 @@ fn const_trait_assoc() {
);
}

#[test]
fn panic_messages() {
check_fail(
r#"
//- minicore: panic
const GOAL: u8 = {
let x: u16 = 2;
panic!("hello");
};
"#,
|e| e == ConstEvalError::MirEvalError(MirEvalError::Panic("hello".to_string())),
);
}

#[test]
fn exec_limits() {
check_fail(
Expand Down
47 changes: 43 additions & 4 deletions crates/hir-ty/src/mir/eval/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,49 @@ impl Evaluator<'_> {
use LangItem::*;
let mut args = args.iter();
match x {
// FIXME: we want to find the panic message from arguments, but it wouldn't work
// currently even if we do that, since macro expansion of panic related macros
// is dummy.
PanicFmt | BeginPanic => Err(MirEvalError::Panic("<format-args>".to_string())),
BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_string())),
PanicFmt => {
let message = (|| {
let arguments_struct =
self.db.lang_item(self.crate_id, LangItem::FormatArguments)?.as_struct()?;
let arguments_layout = self
.layout_adt(arguments_struct.into(), Substitution::empty(Interner))
.ok()?;
let arguments_field_pieces =
self.db.struct_data(arguments_struct).variant_data.field(&name![pieces])?;
let pieces_offset = arguments_layout
.fields
.offset(u32::from(arguments_field_pieces.into_raw()) as usize)
.bytes_usize();
let ptr_size = self.ptr_size();
let arg = args.next()?;
let pieces_array_addr =
Address::from_bytes(&arg[pieces_offset..pieces_offset + ptr_size]).ok()?;
let pieces_array_len = usize::from_le_bytes(
(&arg[pieces_offset + ptr_size..pieces_offset + 2 * ptr_size])
.try_into()
.ok()?,
);
let mut message = "".to_string();
for i in 0..pieces_array_len {
let piece_ptr_addr = pieces_array_addr.offset(2 * i * ptr_size);
let piece_addr =
Address::from_bytes(self.read_memory(piece_ptr_addr, ptr_size).ok()?)
.ok()?;
let piece_len = usize::from_le_bytes(
self.read_memory(piece_ptr_addr.offset(ptr_size), ptr_size)
.ok()?
.try_into()
.ok()?,
);
let piece_data = self.read_memory(piece_addr, piece_len).ok()?;
message += &std::string::String::from_utf8_lossy(piece_data);
}
Some(message)
})()
.unwrap_or_else(|| "<format-args-evaluation-failed>".to_string());
Err(MirEvalError::Panic(message))
}
SliceLen => {
let arg = args
.next()
Expand Down
22 changes: 18 additions & 4 deletions crates/hir-ty/src/mir/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub enum MirLowerError {
UnresolvedMethod(String),
UnresolvedField,
UnsizedTemporary(Ty),
MissingFunctionDefinition,
MissingFunctionDefinition(DefWithBodyId, ExprId),
TypeMismatch(TypeMismatch),
/// This should be never happen. Type mismatch should catch everything.
TypeError(&'static str),
Expand Down Expand Up @@ -113,6 +113,22 @@ impl MirLowerError {
ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter)?,
}
}
MirLowerError::MissingFunctionDefinition(owner, x) => {
let body = db.body(*owner);
writeln!(
f,
"Missing function definition for {}",
body.pretty_print_expr(db.upcast(), *owner, *x)
)?;
}
MirLowerError::TypeMismatch(e) => {
writeln!(
f,
"Type mismatch: Expected {}, found {}",
e.expected.display(db),
e.actual.display(db),
)?;
}
MirLowerError::LayoutError(_)
| MirLowerError::UnsizedTemporary(_)
| MirLowerError::IncompleteExpr
Expand All @@ -122,8 +138,6 @@ impl MirLowerError {
| MirLowerError::RecordLiteralWithoutPath
| MirLowerError::UnresolvedMethod(_)
| MirLowerError::UnresolvedField
| MirLowerError::MissingFunctionDefinition
| MirLowerError::TypeMismatch(_)
| MirLowerError::TypeError(_)
| MirLowerError::NotSupported(_)
| MirLowerError::ContinueWithoutLoop
Expand Down Expand Up @@ -599,7 +613,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id), expr_id.into())
}
TyKind::Error => return Err(MirLowerError::MissingFunctionDefinition),
TyKind::Error => return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)),
_ => return Err(MirLowerError::TypeError("function call on bad type")),
}
}
Expand Down
7 changes: 3 additions & 4 deletions crates/hir-ty/src/tests/regression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1475,13 +1475,12 @@ fn regression_11688_3() {
struct Ar<T, const N: u8>(T);
fn f<const LEN: usize, T, const BASE: u8>(
num_zeros: usize,
) -> dyn Iterator<Item = [Ar<T, BASE>; LEN]> {
) -> &dyn Iterator<Item = [Ar<T, BASE>; LEN]> {
loop {}
}
fn dynamic_programming() {
for board in f::<9, u8, 7>(1) {
//^^^^^ [Ar<u8, 7>; 9]
}
let board = f::<9, u8, 7>(1).next();
//^^^^^ Option<[Ar<u8, 7>; 9]>
}
"#,
);
Expand Down
12 changes: 6 additions & 6 deletions crates/ide/src/inlay_hints/chaining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5769..5777,
range: 9164..9172,
},
),
tooltip: "",
Expand All @@ -487,7 +487,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5801..5805,
range: 9196..9200,
},
),
tooltip: "",
Expand All @@ -511,7 +511,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5769..5777,
range: 9164..9172,
},
),
tooltip: "",
Expand All @@ -524,7 +524,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5801..5805,
range: 9196..9200,
},
),
tooltip: "",
Expand All @@ -548,7 +548,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5769..5777,
range: 9164..9172,
},
),
tooltip: "",
Expand All @@ -561,7 +561,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5801..5805,
range: 9196..9200,
},
),
tooltip: "",
Expand Down
Loading