diff options
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 41 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 29 |
4 files changed, 83 insertions, 26 deletions
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 707556ef8..2fb219908 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -3,7 +3,7 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use ra_syntax::ast; | 4 | use ra_syntax::ast; |
5 | 5 | ||
6 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::{FxHashMap, FxHashSet}; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | ModuleDef, Trait, | 9 | ModuleDef, Trait, |
@@ -193,19 +193,18 @@ impl Resolver { | |||
193 | names | 193 | names |
194 | } | 194 | } |
195 | 195 | ||
196 | pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { | 196 | pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> { |
197 | // FIXME prelude | 197 | let mut traits = FxHashSet::default(); |
198 | self.scopes | 198 | for scope in &self.scopes { |
199 | .iter() | 199 | if let Scope::ModuleScope(m) = scope { |
200 | .rev() | 200 | if let Some(prelude) = m.crate_def_map.prelude() { |
201 | .flat_map(|scope| { | 201 | let prelude_def_map = db.crate_def_map(prelude.krate); |
202 | match scope { | 202 | traits.extend(prelude_def_map[prelude.module_id].scope.traits()); |
203 | Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()), | ||
204 | _ => None, | ||
205 | } | 203 | } |
206 | .into_iter() | 204 | traits.extend(m.crate_def_map[m.module_id].scope.traits()); |
207 | }) | 205 | } |
208 | .flatten() | 206 | } |
207 | traits | ||
209 | } | 208 | } |
210 | 209 | ||
211 | fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { | 210 | fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index d8b8c836c..34817a5ec 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -75,11 +75,13 @@ impl CrateImplBlocks { | |||
75 | 75 | ||
76 | let target_ty = impl_block.target_ty(db); | 76 | let target_ty = impl_block.target_ty(db); |
77 | 77 | ||
78 | if let Some(tr) = impl_block.target_trait_ref(db) { | 78 | if impl_block.target_trait(db).is_some() { |
79 | self.impls_by_trait | 79 | if let Some(tr) = impl_block.target_trait_ref(db) { |
80 | .entry(tr.trait_) | 80 | self.impls_by_trait |
81 | .or_insert_with(Vec::new) | 81 | .entry(tr.trait_) |
82 | .push((module.module_id, impl_id)); | 82 | .or_insert_with(Vec::new) |
83 | .push((module.module_id, impl_id)); | ||
84 | } | ||
83 | } else { | 85 | } else { |
84 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | 86 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { |
85 | self.impls | 87 | self.impls |
@@ -183,7 +185,7 @@ fn iterate_trait_method_candidates<T>( | |||
183 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 185 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
184 | ) -> Option<T> { | 186 | ) -> Option<T> { |
185 | let krate = resolver.krate()?; | 187 | let krate = resolver.krate()?; |
186 | 'traits: for t in resolver.traits_in_scope() { | 188 | 'traits: for t in resolver.traits_in_scope(db) { |
187 | let data = t.trait_data(db); | 189 | let data = t.trait_data(db); |
188 | // we'll be lazy about checking whether the type implements the | 190 | // we'll be lazy about checking whether the type implements the |
189 | // trait, but if we find out it doesn't, we'll skip the rest of the | 191 | // trait, but if we find out it doesn't, we'll skip the rest of the |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 59c85daed..978cc2587 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2502,6 +2502,35 @@ fn test() { (&S).foo()<|>; } | |||
2502 | } | 2502 | } |
2503 | 2503 | ||
2504 | #[test] | 2504 | #[test] |
2505 | fn method_resolution_trait_from_prelude() { | ||
2506 | let (mut db, pos) = MockDatabase::with_position( | ||
2507 | r#" | ||
2508 | //- /main.rs | ||
2509 | struct S; | ||
2510 | impl Clone for S {} | ||
2511 | |||
2512 | fn test() { | ||
2513 | S.clone()<|>; | ||
2514 | } | ||
2515 | |||
2516 | //- /lib.rs | ||
2517 | #[prelude_import] use foo::*; | ||
2518 | |||
2519 | mod foo { | ||
2520 | trait Clone { | ||
2521 | fn clone(&self) -> Self; | ||
2522 | } | ||
2523 | } | ||
2524 | "#, | ||
2525 | ); | ||
2526 | db.set_crate_graph_from_fixture(crate_graph! { | ||
2527 | "main": ("/main.rs", ["other_crate"]), | ||
2528 | "other_crate": ("/lib.rs", []), | ||
2529 | }); | ||
2530 | assert_eq!("S", type_at_pos(&db, pos)); | ||
2531 | } | ||
2532 | |||
2533 | #[test] | ||
2505 | fn method_resolution_where_clause_for_unknown_trait() { | 2534 | fn method_resolution_where_clause_for_unknown_trait() { |
2506 | // The blanket impl shouldn't apply because we can't even resolve UnknownTrait | 2535 | // The blanket impl shouldn't apply because we can't even resolve UnknownTrait |
2507 | let t = type_at( | 2536 | let t = type_at( |
@@ -2620,22 +2649,22 @@ fn method_resolution_slow() { | |||
2620 | let t = type_at( | 2649 | let t = type_at( |
2621 | r#" | 2650 | r#" |
2622 | //- /main.rs | 2651 | //- /main.rs |
2623 | trait Send {} | 2652 | trait SendX {} |
2624 | 2653 | ||
2625 | struct S1; impl Send for S1; | 2654 | struct S1; impl SendX for S1; |
2626 | struct S2; impl Send for S2; | 2655 | struct S2; impl SendX for S2; |
2627 | struct U1; | 2656 | struct U1; |
2628 | 2657 | ||
2629 | trait Trait { fn method(self); } | 2658 | trait Trait { fn method(self); } |
2630 | 2659 | ||
2631 | struct X1<A, B> {} | 2660 | struct X1<A, B> {} |
2632 | impl<A, B> Send for X1<A, B> where A: Send, B: Send {} | 2661 | impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {} |
2633 | 2662 | ||
2634 | struct S<B, C> {} | 2663 | struct S<B, C> {} |
2635 | 2664 | ||
2636 | trait Fn {} | 2665 | trait FnX {} |
2637 | 2666 | ||
2638 | impl<B, C> Trait for S<B, C> where C: Fn, B: Send {} | 2667 | impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} |
2639 | 2668 | ||
2640 | fn test() { (S {}).method()<|>; } | 2669 | fn test() { (S {}).method()<|>; } |
2641 | "#, | 2670 | "#, |
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_) |