about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-05-18 18:30:49 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-05-18 18:30:49 +0330
commit4adfbbfbadf0fb74dee05d4bc5110e00596c5919 (patch)
treec27745fec4ba5940e1db0421deac3d73a31d2ee8
parent9ce95674e8d1d0dfb32f9a31f265ad081be4e46f (diff)
downloadrust-4adfbbfbadf0fb74dee05d4bc5110e00596c5919.tar.gz
rust-4adfbbfbadf0fb74dee05d4bc5110e00596c5919.zip
partially support panic message in `MirEvalError`
-rw-r--r--crates/hir-def/src/body.rs9
-rw-r--r--crates/hir-def/src/body/pretty.rs11
-rw-r--r--crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs10
-rw-r--r--crates/hir-expand/src/builtin_fn_macro.rs12
-rw-r--r--crates/hir-expand/src/name.rs2
-rw-r--r--crates/hir-ty/src/consteval/tests.rs39
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs47
-rw-r--r--crates/hir-ty/src/mir/lower.rs22
-rw-r--r--crates/hir-ty/src/tests/regression.rs7
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs12
-rw-r--r--crates/test-utils/src/minicore.rs73
11 files changed, 199 insertions, 45 deletions
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index d4b4cbe6c7c..ea682f5cbde 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -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,
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index 093dd679702..318f654c16f 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -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)*); }
diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index f5346898c20..13aa6130be8 100644
--- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -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), ]);
 }
 "##]],
     );
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index e9e1c6c3b33..0640ba774bb 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -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 }
 }
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index d6bad1a48c1..10a251ba784 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -362,6 +362,8 @@ pub mod known {
         gt,
         le,
         lt,
+        // known fields of lang items
+        pieces,
         // lang items
         add_assign,
         add,
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 5ab1f970201..b4b5fdd8916 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -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);
@@ -2188,6 +2195,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(
         r#"
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index ac295b58375..9ff58b27bb4 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -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()
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 4bf8070fa46..292a771baf9 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -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")),
                 }
             }
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 4af143829f3..9f5f1ea3255 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -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]>
         }
         "#,
     );
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index 451c15a25c3..db98bf2f9bc 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -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: "",
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 960934cb69d..22cef049838 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -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]