diff options
author | Florian Diebold <[email protected]> | 2019-05-11 19:31:41 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-05-12 19:23:57 +0100 |
commit | 7fda874dd4c84d4b53ed625e9eccc92c3fa9a48e (patch) | |
tree | 104eccdcdc745f6d15dcf9173996815c807a7287 /crates | |
parent | c8b85891b0c6c03a1b373491f75b8872ec47e06f (diff) |
Blacklist some traits from being considered in where clauses
For Send/Sync/Sized, we don't handle auto traits correctly yet and because they
have a lot of impls, they can easily lead to slowdowns. In the case of
Fn/FnMut/FnOnce, we don't parse the special Fn notation correctly yet and don't
handle closures yet, so we are very unlikely to find an impl.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 29 |
2 files changed, 34 insertions, 7 deletions
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 59c85daed..510fa5333 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2620,22 +2620,22 @@ fn method_resolution_slow() { | |||
2620 | let t = type_at( | 2620 | let t = type_at( |
2621 | r#" | 2621 | r#" |
2622 | //- /main.rs | 2622 | //- /main.rs |
2623 | trait Send {} | 2623 | trait SendX {} |
2624 | 2624 | ||
2625 | struct S1; impl Send for S1; | 2625 | struct S1; impl SendX for S1; |
2626 | struct S2; impl Send for S2; | 2626 | struct S2; impl SendX for S2; |
2627 | struct U1; | 2627 | struct U1; |
2628 | 2628 | ||
2629 | trait Trait { fn method(self); } | 2629 | trait Trait { fn method(self); } |
2630 | 2630 | ||
2631 | struct X1<A, B> {} | 2631 | struct X1<A, B> {} |
2632 | impl<A, B> Send for X1<A, B> where A: Send, B: Send {} | 2632 | impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {} |
2633 | 2633 | ||
2634 | struct S<B, C> {} | 2634 | struct S<B, C> {} |
2635 | 2635 | ||
2636 | trait Fn {} | 2636 | trait FnX {} |
2637 | 2637 | ||
2638 | impl<B, C> Trait for S<B, C> where C: Fn, B: Send {} | 2638 | impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} |
2639 | 2639 | ||
2640 | fn test() { (S {}).method()<|>; } | 2640 | fn test() { (S {}).method()<|>; } |
2641 | "#, | 2641 | "#, |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 027c5ec4c..78440b258 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -190,6 +190,14 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | |||
190 | } | 190 | } |
191 | } | 191 | } |
192 | 192 | ||
193 | fn blacklisted_trait(db: &impl HirDatabase, trait_: Trait) -> bool { | ||
194 | let name = trait_.name(db).unwrap_or_else(crate::Name::missing).to_string(); | ||
195 | match &*name { | ||
196 | "Send" | "Sync" | "Sized" | "Fn" | "FnMut" | "FnOnce" => true, | ||
197 | _ => false, | ||
198 | } | ||
199 | } | ||
200 | |||
193 | fn convert_where_clauses( | 201 | fn convert_where_clauses( |
194 | db: &impl HirDatabase, | 202 | db: &impl HirDatabase, |
195 | def: GenericDef, | 203 | def: GenericDef, |
@@ -198,6 +206,19 @@ fn convert_where_clauses( | |||
198 | let generic_predicates = db.generic_predicates(def); | 206 | let generic_predicates = db.generic_predicates(def); |
199 | let mut result = Vec::with_capacity(generic_predicates.len()); | 207 | let mut result = Vec::with_capacity(generic_predicates.len()); |
200 | for pred in generic_predicates.iter() { | 208 | for pred in generic_predicates.iter() { |
209 | if pred.is_error() { | ||
210 | // HACK: Return just the single predicate (which is always false | ||
211 | // anyway), otherwise Chalk can easily get into slow situations | ||
212 | return vec![pred.clone().subst(substs).to_chalk(db)]; | ||
213 | } | ||
214 | match pred { | ||
215 | GenericPredicate::Implemented(trait_ref) => { | ||
216 | if blacklisted_trait(db, trait_ref.trait_) { | ||
217 | continue; | ||
218 | } | ||
219 | } | ||
220 | _ => {} | ||
221 | } | ||
201 | result.push(pred.clone().subst(substs).to_chalk(db)); | 222 | result.push(pred.clone().subst(substs).to_chalk(db)); |
202 | } | 223 | } |
203 | result | 224 | result |
@@ -230,6 +251,7 @@ where | |||
230 | return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) }); | 251 | return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) }); |
231 | } | 252 | } |
232 | let trait_: Trait = from_chalk(self.db, trait_id); | 253 | let trait_: Trait = from_chalk(self.db, trait_id); |
254 | debug!("trait {:?} = {:?}", trait_id, trait_.name(self.db)); | ||
233 | let generic_params = trait_.generic_params(self.db); | 255 | let generic_params = trait_.generic_params(self.db); |
234 | let bound_vars = Substs::bound_vars(&generic_params); | 256 | let bound_vars = Substs::bound_vars(&generic_params); |
235 | let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db); | 257 | let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db); |
@@ -250,6 +272,7 @@ where | |||
250 | fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { | 272 | fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { |
251 | debug!("struct_datum {:?}", struct_id); | 273 | debug!("struct_datum {:?}", struct_id); |
252 | let type_ctor = from_chalk(self.db, struct_id); | 274 | let type_ctor = from_chalk(self.db, struct_id); |
275 | debug!("struct {:?} = {:?}", struct_id, type_ctor); | ||
253 | // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor | 276 | // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor |
254 | // FIXME extract this to a method on Ty | 277 | // FIXME extract this to a method on Ty |
255 | let (num_params, where_clauses, upstream) = match type_ctor { | 278 | let (num_params, where_clauses, upstream) = match type_ctor { |
@@ -358,7 +381,11 @@ where | |||
358 | if trait_id == UNKNOWN_TRAIT { | 381 | if trait_id == UNKNOWN_TRAIT { |
359 | return Vec::new(); | 382 | return Vec::new(); |
360 | } | 383 | } |
361 | let trait_ = from_chalk(self.db, trait_id); | 384 | let trait_: Trait = from_chalk(self.db, trait_id); |
385 | let blacklisted = blacklisted_trait(self.db, trait_); | ||
386 | if blacklisted { | ||
387 | return Vec::new(); | ||
388 | } | ||
362 | let result: Vec<_> = self | 389 | let result: Vec<_> = self |
363 | .db | 390 | .db |
364 | .impls_for_trait(self.krate, trait_) | 391 | .impls_for_trait(self.krate, trait_) |