feat: Honor recursion limit configuration

This patch makes RA understand `#![recursion_limit = "N"]` annotations.

- `crate_limits` query is moved to `DefDatabase`
- `DefMap` now has `recursion_limit: Option<u32>` field
This commit is contained in:
Maybe Waffle 2022-01-28 01:23:09 +03:00
parent 81211f538c
commit 6d18c5b69d
6 changed files with 54 additions and 15 deletions

View file

@ -69,21 +69,6 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
/// The crate graph. /// The crate graph.
#[salsa::input] #[salsa::input]
fn crate_graph(&self) -> Arc<CrateGraph>; fn crate_graph(&self) -> Arc<CrateGraph>;
#[salsa::transparent]
fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
}
pub struct CrateLimits {
/// The maximum depth for potentially infinitely-recursive compile-time operations like macro expansion or auto-dereference.
pub recursion_limit: u32,
}
fn crate_limits(_db: &dyn SourceDatabase, _crate_id: CrateId) -> CrateLimits {
CrateLimits {
// 128 is the default in rustc.
recursion_limit: 128,
}
} }
fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {

View file

@ -61,6 +61,24 @@ fn main() { n_nuple!(1,2,3); }
); );
} }
#[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); }
"#,
);
}
#[test] #[test]
fn macro_resolve() { fn macro_resolve() {
// Regression test for a path resolution bug introduced with inner item handling. // Regression test for a path resolution bug introduced with inner item handling.

View file

@ -157,9 +157,26 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
#[salsa::invoke(visibility::function_visibility_query)] #[salsa::invoke(visibility::function_visibility_query)]
fn function_visibility(&self, def: FunctionId) -> Visibility; fn function_visibility(&self, def: FunctionId) -> Visibility;
#[salsa::transparent]
fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
} }
fn crate_def_map_wait(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> { fn crate_def_map_wait(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
let _p = profile::span("crate_def_map:wait"); let _p = profile::span("crate_def_map:wait");
db.crate_def_map_query(krate) db.crate_def_map_query(krate)
} }
pub struct CrateLimits {
/// The maximum depth for potentially infinitely-recursive compile-time operations like macro expansion or auto-dereference.
pub recursion_limit: u32,
}
fn crate_limits(db: &dyn DefDatabase, crate_id: CrateId) -> CrateLimits {
let def_map = db.crate_def_map(crate_id);
CrateLimits {
// 128 is the default in rustc.
recursion_limit: def_map.recursion_limit().unwrap_or(128),
}
}

View file

@ -114,6 +114,7 @@ pub struct DefMap {
registered_tools: Vec<SmolStr>, registered_tools: Vec<SmolStr>,
edition: Edition, edition: Edition,
recursion_limit: Option<u32>,
diagnostics: Vec<DefDiagnostic>, diagnostics: Vec<DefDiagnostic>,
} }
@ -272,6 +273,7 @@ impl DefMap {
block: None, block: None,
krate, krate,
edition, edition,
recursion_limit: None,
extern_prelude: FxHashMap::default(), extern_prelude: FxHashMap::default(),
exported_proc_macros: FxHashMap::default(), exported_proc_macros: FxHashMap::default(),
prelude: None, prelude: None,
@ -461,6 +463,7 @@ impl DefMap {
registered_tools, registered_tools,
block: _, block: _,
edition: _, edition: _,
recursion_limit: _,
krate: _, krate: _,
prelude: _, prelude: _,
root: _, root: _,
@ -482,6 +485,10 @@ impl DefMap {
pub fn diagnostics(&self) -> &[DefDiagnostic] { pub fn diagnostics(&self) -> &[DefDiagnostic] {
self.diagnostics.as_slice() self.diagnostics.as_slice()
} }
pub fn recursion_limit(&self) -> Option<u32> {
self.recursion_limit
}
} }
impl ModuleData { impl ModuleData {

View file

@ -271,6 +271,17 @@ impl DefCollector<'_> {
None => continue, None => continue,
}; };
if *attr_name == hir_expand::name![recursion_limit] {
if let Some(input) = &attr.input {
if let AttrInput::Literal(limit) = &**input {
if let Ok(limit) = limit.parse() {
self.def_map.recursion_limit = Some(limit);
}
}
}
continue;
}
let attr_is_register_like = *attr_name == hir_expand::name![register_attr] let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
|| *attr_name == hir_expand::name![register_tool]; || *attr_name == hir_expand::name![register_tool];
if !attr_is_register_like { if !attr_is_register_like {

View file

@ -270,6 +270,7 @@ pub mod known {
global_allocator, global_allocator,
test, test,
test_case, test_case,
recursion_limit,
// Safe intrinsics // Safe intrinsics
abort, abort,
add_with_overflow, add_with_overflow,