mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-13 00:17:15 +00:00
partially support panic message in MirEvalError
This commit is contained in:
parent
9ce95674e8
commit
4adfbbfbad
11 changed files with 199 additions and 45 deletions
|
@ -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,
|
||||
|
|
|
@ -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)*); }
|
||||
|
|
|
@ -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), ]);
|
||||
}
|
||||
"##]],
|
||||
);
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -362,6 +362,8 @@ pub mod known {
|
|||
gt,
|
||||
le,
|
||||
lt,
|
||||
// known fields of lang items
|
||||
pieces,
|
||||
// lang items
|
||||
add_assign,
|
||||
add,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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")),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
|
|
@ -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: "",
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue