mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Collapse term search exprs before Cartesian product to avoid OOM
This commit is contained in:
parent
c4618fe14d
commit
c3ab435b54
4 changed files with 43 additions and 20 deletions
|
@ -127,6 +127,13 @@ impl LookupTable {
|
||||||
self.types_wishlist.insert(ty.clone());
|
self.types_wishlist.insert(ty.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collapse suggestions if there are many
|
||||||
|
if let Some(res) = &res {
|
||||||
|
if res.len() > self.many_threshold {
|
||||||
|
return Some(vec![Expr::Many(ty.clone())]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +165,13 @@ impl LookupTable {
|
||||||
self.types_wishlist.insert(ty.clone());
|
self.types_wishlist.insert(ty.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collapse suggestions if there are many
|
||||||
|
if let Some(res) = &res {
|
||||||
|
if res.len() > self.many_threshold {
|
||||||
|
return Some(vec![Expr::Many(ty.clone())]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,11 +190,11 @@ impl LookupTable {
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.data.insert(ty.clone(), AlternativeExprs::new(self.many_threshold, exprs));
|
self.data.insert(ty.clone(), AlternativeExprs::new(self.many_threshold, exprs));
|
||||||
for it in self.new_types.values_mut() {
|
|
||||||
it.push(ty.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for it in self.new_types.values_mut() {
|
||||||
|
it.push(ty.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate all the reachable types
|
/// Iterate all the reachable types
|
||||||
|
|
|
@ -211,13 +211,13 @@ impl Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Method { func, target, params, .. } => {
|
Expr::Method { func, target, params, .. } => {
|
||||||
if target.contains_many_in_illegal_pos() {
|
if self.contains_many_in_illegal_pos(db) {
|
||||||
return Ok(many_formatter(&target.ty(db)));
|
return Ok(many_formatter(&target.ty(db)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let func_name = func.name(db).display(db.upcast()).to_string();
|
let func_name = func.name(db).display(db.upcast()).to_string();
|
||||||
let self_param = func.self_param(db).unwrap();
|
let self_param = func.self_param(db).unwrap();
|
||||||
let target = target.gen_source_code(
|
let target_str = target.gen_source_code(
|
||||||
sema_scope,
|
sema_scope,
|
||||||
many_formatter,
|
many_formatter,
|
||||||
prefer_no_std,
|
prefer_no_std,
|
||||||
|
@ -236,9 +236,12 @@ impl Expr {
|
||||||
Some(trait_) => {
|
Some(trait_) => {
|
||||||
let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?;
|
let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?;
|
||||||
let target = match self_param.access(db) {
|
let target = match self_param.access(db) {
|
||||||
crate::Access::Shared => format!("&{target}"),
|
crate::Access::Shared if !target.is_many() => format!("&{target_str}"),
|
||||||
crate::Access::Exclusive => format!("&mut {target}"),
|
crate::Access::Exclusive if !target.is_many() => {
|
||||||
crate::Access::Owned => target,
|
format!("&mut {target_str}")
|
||||||
|
}
|
||||||
|
crate::Access::Owned => target_str,
|
||||||
|
_ => many_formatter(&target.ty(db)),
|
||||||
};
|
};
|
||||||
let res = match args.is_empty() {
|
let res = match args.is_empty() {
|
||||||
true => format!("{trait_name}::{func_name}({target})",),
|
true => format!("{trait_name}::{func_name}({target})",),
|
||||||
|
@ -246,7 +249,7 @@ impl Expr {
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
None => Ok(format!("{target}.{func_name}({args})")),
|
None => Ok(format!("{target_str}.{func_name}({args})")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Variant { variant, generics, params } => {
|
Expr::Variant { variant, generics, params } => {
|
||||||
|
@ -381,7 +384,7 @@ impl Expr {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
Expr::Field { expr, field } => {
|
Expr::Field { expr, field } => {
|
||||||
if expr.contains_many_in_illegal_pos() {
|
if expr.contains_many_in_illegal_pos(db) {
|
||||||
return Ok(many_formatter(&expr.ty(db)));
|
return Ok(many_formatter(&expr.ty(db)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +398,7 @@ impl Expr {
|
||||||
Ok(format!("{strukt}.{field}"))
|
Ok(format!("{strukt}.{field}"))
|
||||||
}
|
}
|
||||||
Expr::Reference(expr) => {
|
Expr::Reference(expr) => {
|
||||||
if expr.contains_many_in_illegal_pos() {
|
if expr.contains_many_in_illegal_pos(db) {
|
||||||
return Ok(many_formatter(&expr.ty(db)));
|
return Ok(many_formatter(&expr.ty(db)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,10 +469,17 @@ impl Expr {
|
||||||
/// macro!().bar()
|
/// macro!().bar()
|
||||||
/// ¯o!()
|
/// ¯o!()
|
||||||
/// ```
|
/// ```
|
||||||
fn contains_many_in_illegal_pos(&self) -> bool {
|
fn contains_many_in_illegal_pos(&self, db: &dyn HirDatabase) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Expr::Method { target, .. } => target.contains_many_in_illegal_pos(),
|
Expr::Method { target, func, .. } => {
|
||||||
Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(),
|
match func.as_assoc_item(db).and_then(|it| it.container_or_implemented_trait(db)) {
|
||||||
|
Some(_) => false,
|
||||||
|
None => {
|
||||||
|
target.is_many()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(db),
|
||||||
Expr::Reference(target) => target.is_many(),
|
Expr::Reference(target) => target.is_many(),
|
||||||
Expr::Many(_) => true,
|
Expr::Many(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -1808,8 +1808,7 @@ fn f() { A { bar: b$0 }; }
|
||||||
fn baz() [type]
|
fn baz() [type]
|
||||||
ex baz() [type]
|
ex baz() [type]
|
||||||
ex bar() [type]
|
ex bar() [type]
|
||||||
ex A { bar: baz() }.bar [type]
|
ex A { bar: ... }.bar [type]
|
||||||
ex A { bar: bar() }.bar [type]
|
|
||||||
st A []
|
st A []
|
||||||
fn f() []
|
fn f() []
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -1947,8 +1946,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
|
|
||||||
ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
|
ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
|
||||||
|
ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
|
||||||
lc m [local]
|
lc m [local]
|
||||||
lc t [local]
|
lc t [local]
|
||||||
lc &t [type+local]
|
lc &t [type+local]
|
||||||
|
@ -1997,8 +1996,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
|
|
||||||
ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
|
ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
|
||||||
|
ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
|
||||||
lc m [local]
|
lc m [local]
|
||||||
lc t [local]
|
lc t [local]
|
||||||
lc &mut t [type+local]
|
lc &mut t [type+local]
|
||||||
|
|
|
@ -274,7 +274,7 @@ impl Foo for Baz {
|
||||||
}
|
}
|
||||||
fn asd() -> Bar {
|
fn asd() -> Bar {
|
||||||
let a = Baz;
|
let a = Baz;
|
||||||
Foo::foo(a)
|
Foo::foo(_)
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
|
@ -363,7 +363,7 @@ impl Foo for A {
|
||||||
}
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = A;
|
let a = A;
|
||||||
let c: Bar = Foo::foo(&a);
|
let c: Bar = Foo::foo(_);
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue