partially support panic message in MirEvalError

This commit is contained in:
hkalbasi 2023-05-18 18:30:49 +03:30
parent 9ce95674e8
commit 4adfbbfbad
11 changed files with 199 additions and 45 deletions

View file

@ -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,

View file

@ -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)*); }

View file

@ -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), ]);
}
"##]],
);
@ -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), ]);
}
"##]],
);
@ -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), ]);
}
"##]],
);
@ -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), ]);
}
"##]],
);
@ -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), ]);
}
"##]],
);

View file

@ -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(&'}') {
@ -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 }
}

View file

@ -362,6 +362,8 @@ pub mod known {
gt,
le,
lt,
// known fields of lang items
pieces,
// lang items
add_assign,
add,

View file

@ -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))
}
}
}
@ -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);
}
};
@ -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);
@ -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(

View file

@ -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()

View file

@ -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),
@ -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
@ -122,8 +138,6 @@ impl MirLowerError {
| MirLowerError::RecordLiteralWithoutPath
| MirLowerError::UnresolvedMethod(_)
| MirLowerError::UnresolvedField
| MirLowerError::MissingFunctionDefinition
| MirLowerError::TypeMismatch(_)
| MirLowerError::TypeError(_)
| MirLowerError::NotSupported(_)
| MirLowerError::ContinueWithoutLoop
@ -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")),
}
}

View file

@ -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]>
}
"#,
);

View file

@ -474,7 +474,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5769..5777,
range: 9164..9172,
},
),
tooltip: "",
@ -487,7 +487,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5801..5805,
range: 9196..9200,
},
),
tooltip: "",
@ -511,7 +511,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5769..5777,
range: 9164..9172,
},
),
tooltip: "",
@ -524,7 +524,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5801..5805,
range: 9196..9200,
},
),
tooltip: "",
@ -548,7 +548,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5769..5777,
range: 9164..9172,
},
),
tooltip: "",
@ -561,7 +561,7 @@ fn main() {
file_id: FileId(
1,
),
range: 5801..5805,
range: 9196..9200,
},
),
tooltip: "",

View file

@ -23,7 +23,7 @@
//! drop:
//! eq: sized
//! error: fmt
//! fmt: result
//! fmt: result, transmute, coerce_unsized
//! fn:
//! from: sized
//! future: pin
@ -37,7 +37,7 @@
//! non_zero:
//! option: panic
//! ord: eq, option
//! panic:
//! panic: fmt
//! pin:
//! range:
//! result:
@ -45,6 +45,7 @@
//! sized:
//! slice:
//! sync: sized
//! transmute:
//! try: infallible
//! unsize: sized
@ -289,8 +290,8 @@ pub mod convert {
// endregion:infallible
}
// region:drop
pub mod mem {
// region:drop
// region:manually_drop
#[lang = "manually_drop"]
#[repr(transparent)]
@ -323,15 +324,23 @@ pub mod mem {
result
}
}
// endregion:drop
// region:transmute
extern "rust-intrinsic" {
pub fn transmute<Src, Dst>(src: Src) -> Dst;
}
// endregion:transmute
}
pub mod ptr {
// region:drop
#[lang = "drop_in_place"]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
unsafe { drop_in_place(to_drop) }
}
// endregion:drop
}
// endregion:drop
pub mod ops {
// region:coerce_unsized
@ -812,6 +821,38 @@ pub mod fmt {
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
}
extern "C" {
type Opaque;
}
#[lang = "format_argument"]
pub struct ArgumentV1<'a> {
value: &'a Opaque,
formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
}
impl<'a> ArgumentV1<'a> {
pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
use crate::mem::transmute;
unsafe { ArgumentV1 { formatter: transmute(f), value: transmute(x) } }
}
}
#[lang = "format_arguments"]
pub struct Arguments<'a> {
pieces: &'a [&'static str],
args: &'a [ArgumentV1<'a>],
}
impl<'a> Arguments<'a> {
pub const fn new_v1(
pieces: &'a [&'static str],
args: &'a [ArgumentV1<'a>],
) -> Arguments<'a> {
Arguments { pieces, args }
}
}
// region:derive
#[rustc_builtin_macro]
pub macro Debug($item:item) {}
@ -1147,8 +1188,17 @@ pub mod iter {
// region:panic
mod panic {
pub macro panic_2021($($t:tt)+) {
/* Nothing yet */
pub macro panic_2021 {
($($t:tt)+) => (
$crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
),
}
}
mod panicking {
#[lang = "panic_fmt"]
pub const fn panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! {
loop {}
}
}
// endregion:panic
@ -1166,6 +1216,17 @@ mod macros {
pub(crate) use panic;
// endregion:panic
// region:fmt
#[macro_export]
#[rustc_builtin_macro]
macro_rules! const_format_args {
($fmt:expr) => {{ /* compiler built-in */ }};
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
}
pub(crate) use const_format_args;
// endregion:fmt
// region:derive
pub(crate) mod builtin {
#[rustc_builtin_macro]