diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index d4b4cbe6c7..ea682f5cbd 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 093dd67970..318f654c16 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 f5346898c2..13aa6130be 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::()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Debug::fmt), ]);
+ ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a::()), ::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 e9e1c6c3b3..0640ba774b 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 d6bad1a48c..10a251ba78 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 5ab1f97020..b4b5fdd891 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 {
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(
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index ac295b5837..9ff58b27bb 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("".to_string())),
+ BeginPanic => Err(MirEvalError::Panic("".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(|| "".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 4bf8070fa4..292a771baf 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 4af143829f..9f5f1ea325 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);
fn f(
num_zeros: usize,
- ) -> dyn Iterator- ; LEN]> {
+ ) -> &dyn Iterator
- ; LEN]> {
loop {}
}
fn dynamic_programming() {
- for board in f::<9, u8, 7>(1) {
- //^^^^^ [Ar; 9]
- }
+ let board = f::<9, u8, 7>(1).next();
+ //^^^^^ Option<[Ar; 9]>
}
"#,
);
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index 451c15a25c..db98bf2f9b 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 960934cb69..22cef04983 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: Src) -> Dst;
+ }
+ // endregion:transmute
}
pub mod ptr {
+ // region:drop
#[lang = "drop_in_place"]
pub unsafe fn drop_in_place(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]