2021-02-01 12:20:35 +00:00
|
|
|
mod block;
|
|
|
|
|
2023-12-18 11:09:54 +00:00
|
|
|
use base_db::SourceDatabase;
|
2023-09-06 13:21:41 +00:00
|
|
|
use expect_test::{expect, Expect};
|
2023-12-18 11:09:54 +00:00
|
|
|
use hir_expand::fixture::WithFixture;
|
2020-10-23 17:27:04 +00:00
|
|
|
|
2023-06-27 06:22:18 +00:00
|
|
|
use crate::{test_db::TestDB, ModuleDefId};
|
2020-10-23 17:27:04 +00:00
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
2023-09-06 13:21:41 +00:00
|
|
|
fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
|
2023-06-27 06:22:18 +00:00
|
|
|
let db = TestDB::with_files(ra_fixture);
|
2020-10-23 17:27:04 +00:00
|
|
|
|
|
|
|
let krate = db.crate_graph().iter().next().unwrap();
|
|
|
|
let def_map = db.crate_def_map(krate);
|
2021-01-21 19:35:36 +00:00
|
|
|
let mut fn_def = None;
|
|
|
|
'outer: for (_, module) in def_map.modules() {
|
|
|
|
for decl in module.scope.declarations() {
|
2021-06-07 11:59:01 +00:00
|
|
|
if let ModuleDefId::FunctionId(it) = decl {
|
|
|
|
fn_def = Some(it);
|
|
|
|
break 'outer;
|
2021-01-21 19:35:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-06 13:21:41 +00:00
|
|
|
let fn_def = fn_def.unwrap().into();
|
2021-01-21 19:35:36 +00:00
|
|
|
|
2023-09-06 13:21:41 +00:00
|
|
|
let body = db.body(fn_def);
|
|
|
|
(db, body, fn_def)
|
2020-10-23 17:27:04 +00:00
|
|
|
}
|
|
|
|
|
2023-06-27 06:22:18 +00:00
|
|
|
fn def_map_at(ra_fixture: &str) -> String {
|
|
|
|
let (db, position) = TestDB::with_position(ra_fixture);
|
2021-02-01 12:20:35 +00:00
|
|
|
|
2021-02-09 16:22:57 +00:00
|
|
|
let module = db.module_at_position(position);
|
|
|
|
module.def_map(&db).dump(&db)
|
2021-02-01 12:20:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-21 15:57:45 +00:00
|
|
|
fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
|
2023-06-27 06:22:18 +00:00
|
|
|
let (db, position) = TestDB::with_position(ra_fixture);
|
2021-04-21 15:57:45 +00:00
|
|
|
|
|
|
|
let module = db.module_at_position(position);
|
|
|
|
let actual = module.def_map(&db).dump_block_scopes(&db);
|
|
|
|
expect.assert_eq(&actual);
|
|
|
|
}
|
|
|
|
|
2021-02-01 12:20:35 +00:00
|
|
|
fn check_at(ra_fixture: &str, expect: Expect) {
|
2023-06-27 06:22:18 +00:00
|
|
|
let actual = def_map_at(ra_fixture);
|
2021-02-01 12:20:35 +00:00
|
|
|
expect.assert_eq(&actual);
|
|
|
|
}
|
|
|
|
|
2020-10-23 17:27:04 +00:00
|
|
|
#[test]
|
|
|
|
fn your_stack_belongs_to_me() {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::check!(your_stack_belongs_to_me);
|
2020-10-23 17:27:04 +00:00
|
|
|
lower(
|
2021-06-13 15:45:38 +00:00
|
|
|
r#"
|
2020-10-23 17:27:04 +00:00
|
|
|
macro_rules! n_nuple {
|
|
|
|
($e:tt) => ();
|
|
|
|
($($rest:tt)*) => {{
|
|
|
|
(n_nuple!($($rest)*)None,)
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
fn main() { n_nuple!(1,2,3); }
|
2021-06-13 15:45:38 +00:00
|
|
|
"#,
|
2020-10-23 17:27:04 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-02-08 11:11:54 +00:00
|
|
|
#[test]
|
|
|
|
fn your_stack_belongs_to_me2() {
|
|
|
|
cov_mark::check!(overflow_but_not_me);
|
|
|
|
lower(
|
|
|
|
r#"
|
|
|
|
macro_rules! foo {
|
|
|
|
() => {{ foo!(); foo!(); }}
|
|
|
|
}
|
|
|
|
fn main() { foo!(); }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-27 22:23:09 +00:00
|
|
|
#[test]
|
|
|
|
fn recursion_limit() {
|
|
|
|
cov_mark::check!(your_stack_belongs_to_me);
|
|
|
|
|
|
|
|
lower(
|
|
|
|
r#"
|
|
|
|
#![recursion_limit = "2"]
|
|
|
|
macro_rules! n_nuple {
|
|
|
|
($e:tt) => ();
|
|
|
|
($first:tt $($rest:tt)*) => {{
|
|
|
|
n_nuple!($($rest)*)
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
fn main() { n_nuple!(1,2,3); }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-04-05 15:42:07 +00:00
|
|
|
#[test]
|
|
|
|
fn issue_3642_bad_macro_stackover() {
|
|
|
|
lower(
|
|
|
|
r#"
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! match_ast {
|
|
|
|
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
|
|
|
|
|
|
|
|
(match ($node:expr) {
|
|
|
|
$( ast::$ast:ident($it:ident) => $res:expr, )*
|
|
|
|
_ => $catch_all:expr $(,)?
|
|
|
|
}) => {{
|
|
|
|
$( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
|
|
|
|
{ $catch_all }
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let anchor = match_ast! {
|
|
|
|
match parent {
|
|
|
|
as => {},
|
|
|
|
_ => return None
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-01-21 19:35:36 +00:00
|
|
|
#[test]
|
|
|
|
fn macro_resolve() {
|
|
|
|
// Regression test for a path resolution bug introduced with inner item handling.
|
|
|
|
lower(
|
2021-06-13 15:45:38 +00:00
|
|
|
r#"
|
2021-01-21 19:35:36 +00:00
|
|
|
macro_rules! vec {
|
|
|
|
() => { () };
|
|
|
|
($elem:expr; $n:expr) => { () };
|
|
|
|
($($x:expr),+ $(,)?) => { () };
|
|
|
|
}
|
|
|
|
mod m {
|
|
|
|
fn outer() {
|
|
|
|
let _ = vec![FileSet::default(); self.len()];
|
|
|
|
}
|
|
|
|
}
|
2021-06-13 15:45:38 +00:00
|
|
|
"#,
|
2021-01-21 19:35:36 +00:00
|
|
|
);
|
|
|
|
}
|
2023-09-06 13:21:41 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn desugar_builtin_format_args() {
|
|
|
|
let (db, body, def) = lower(
|
|
|
|
r#"
|
|
|
|
//- minicore: fmt
|
|
|
|
fn main() {
|
|
|
|
let are = "are";
|
|
|
|
let count = 10;
|
|
|
|
builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
expect![[r#"
|
|
|
|
fn main() {
|
|
|
|
let are = "are";
|
|
|
|
let count = 10;
|
|
|
|
builtin#lang(Arguments::new_v1_formatted)(
|
|
|
|
&[
|
2023-12-05 14:42:39 +00:00
|
|
|
"hello ", " ", " friends, we ", " ", "",
|
2023-09-06 13:21:41 +00:00
|
|
|
],
|
|
|
|
&[
|
|
|
|
builtin#lang(Argument::new_display)(
|
|
|
|
&count,
|
|
|
|
), builtin#lang(Argument::new_display)(
|
|
|
|
&"fancy",
|
|
|
|
), builtin#lang(Argument::new_debug)(
|
|
|
|
&are,
|
|
|
|
), builtin#lang(Argument::new_display)(
|
|
|
|
&"!",
|
2023-09-06 16:52:12 +00:00
|
|
|
),
|
2023-09-06 13:21:41 +00:00
|
|
|
],
|
|
|
|
&[
|
|
|
|
builtin#lang(Placeholder::new)(
|
|
|
|
0usize,
|
|
|
|
' ',
|
|
|
|
builtin#lang(Alignment::Unknown),
|
|
|
|
8u32,
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
builtin#lang(Count::Is)(
|
|
|
|
2usize,
|
|
|
|
),
|
|
|
|
), builtin#lang(Placeholder::new)(
|
|
|
|
1usize,
|
|
|
|
' ',
|
|
|
|
builtin#lang(Alignment::Unknown),
|
|
|
|
0u32,
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
), builtin#lang(Placeholder::new)(
|
|
|
|
2usize,
|
|
|
|
' ',
|
|
|
|
builtin#lang(Alignment::Unknown),
|
|
|
|
0u32,
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
), builtin#lang(Placeholder::new)(
|
|
|
|
1usize,
|
|
|
|
' ',
|
|
|
|
builtin#lang(Alignment::Unknown),
|
|
|
|
0u32,
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
), builtin#lang(Placeholder::new)(
|
|
|
|
3usize,
|
|
|
|
' ',
|
|
|
|
builtin#lang(Alignment::Unknown),
|
|
|
|
0u32,
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
builtin#lang(Count::Implied),
|
2023-09-06 16:52:12 +00:00
|
|
|
),
|
2023-09-06 13:21:41 +00:00
|
|
|
],
|
|
|
|
unsafe {
|
|
|
|
builtin#lang(UnsafeArg::new)()
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}"#]]
|
|
|
|
.assert_eq(&body.pretty_print(&db, def))
|
|
|
|
}
|
2023-12-02 12:03:46 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_macro_hygiene() {
|
|
|
|
let (db, body, def) = lower(
|
|
|
|
r##"
|
|
|
|
//- minicore: fmt, from
|
|
|
|
//- /main.rs
|
|
|
|
mod error;
|
|
|
|
|
|
|
|
use crate::error::error;
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
// _ = forces body expansion instead of block def map expansion
|
|
|
|
_ = error!("Failed to resolve path `{}`", node.text());
|
|
|
|
}
|
|
|
|
//- /error.rs
|
|
|
|
macro_rules! _error {
|
|
|
|
($fmt:expr, $($arg:tt)+) => {$crate::error::intermediate!(format_args!($fmt, $($arg)+))}
|
|
|
|
}
|
|
|
|
pub(crate) use _error as error;
|
|
|
|
macro_rules! _intermediate {
|
|
|
|
($arg:expr) => {$crate::error::SsrError::new($arg)}
|
|
|
|
}
|
|
|
|
pub(crate) use _intermediate as intermediate;
|
|
|
|
|
|
|
|
pub struct SsrError(pub(crate) core::fmt::Arguments);
|
|
|
|
|
|
|
|
impl SsrError {
|
|
|
|
pub(crate) fn new(message: impl Into<core::fmt::Arguments>) -> SsrError {
|
|
|
|
SsrError(message.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"##,
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(db.body_with_source_map(def.into()).1.diagnostics(), &[]);
|
|
|
|
expect![[r#"
|
|
|
|
fn main() {
|
|
|
|
_ = $crate::error::SsrError::new(
|
|
|
|
builtin#lang(Arguments::new_v1_formatted)(
|
|
|
|
&[
|
2023-12-05 14:42:39 +00:00
|
|
|
"Failed to resolve path `", "`",
|
2023-12-02 12:03:46 +00:00
|
|
|
],
|
|
|
|
&[
|
|
|
|
builtin#lang(Argument::new_display)(
|
|
|
|
&node.text(),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
&[
|
|
|
|
builtin#lang(Placeholder::new)(
|
|
|
|
0usize,
|
|
|
|
' ',
|
|
|
|
builtin#lang(Alignment::Unknown),
|
|
|
|
0u32,
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
builtin#lang(Count::Implied),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
unsafe {
|
|
|
|
builtin#lang(UnsafeArg::new)()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}"#]]
|
|
|
|
.assert_eq(&body.pretty_print(&db, def))
|
|
|
|
}
|
2023-12-02 15:50:21 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn regression_10300() {
|
|
|
|
let (db, body, def) = lower(
|
|
|
|
r#"
|
|
|
|
//- minicore: concat, panic
|
|
|
|
mod private {
|
|
|
|
pub use core::concat;
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! m {
|
|
|
|
() => {
|
|
|
|
panic!(concat!($crate::private::concat!("cc")));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn f() {
|
|
|
|
m!();
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
let (_, source_map) = db.body_with_source_map(def.into());
|
|
|
|
assert_eq!(source_map.diagnostics(), &[]);
|
|
|
|
|
|
|
|
for (_, def_map) in body.blocks(&db) {
|
|
|
|
assert_eq!(def_map.diagnostics(), &[]);
|
|
|
|
}
|
|
|
|
|
|
|
|
expect![[r#"
|
|
|
|
fn f() {
|
|
|
|
$crate::panicking::panic_fmt(
|
|
|
|
builtin#lang(Arguments::new_v1_formatted)(
|
|
|
|
&[
|
2023-12-05 14:42:39 +00:00
|
|
|
"cc",
|
2023-12-02 15:50:21 +00:00
|
|
|
],
|
|
|
|
&[],
|
|
|
|
&[],
|
|
|
|
unsafe {
|
|
|
|
builtin#lang(UnsafeArg::new)()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}"#]]
|
|
|
|
.assert_eq(&body.pretty_print(&db, def))
|
|
|
|
}
|