aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/resolve.rs25
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs14
-rw-r--r--crates/ra_hir/src/ty/tests.rs41
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs29
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
4use ra_syntax::ast; 4use ra_syntax::ast;
5 5
6use rustc_hash::FxHashMap; 6use rustc_hash::{FxHashMap, FxHashSet};
7 7
8use crate::{ 8use 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]
2505fn method_resolution_trait_from_prelude() {
2506 let (mut db, pos) = MockDatabase::with_position(
2507 r#"
2508//- /main.rs
2509struct S;
2510impl Clone for S {}
2511
2512fn test() {
2513 S.clone()<|>;
2514}
2515
2516//- /lib.rs
2517#[prelude_import] use foo::*;
2518
2519mod 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]
2505fn method_resolution_where_clause_for_unknown_trait() { 2534fn 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
2623trait Send {} 2652trait SendX {}
2624 2653
2625struct S1; impl Send for S1; 2654struct S1; impl SendX for S1;
2626struct S2; impl Send for S2; 2655struct S2; impl SendX for S2;
2627struct U1; 2656struct U1;
2628 2657
2629trait Trait { fn method(self); } 2658trait Trait { fn method(self); }
2630 2659
2631struct X1<A, B> {} 2660struct X1<A, B> {}
2632impl<A, B> Send for X1<A, B> where A: Send, B: Send {} 2661impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
2633 2662
2634struct S<B, C> {} 2663struct S<B, C> {}
2635 2664
2636trait Fn {} 2665trait FnX {}
2637 2666
2638impl<B, C> Trait for S<B, C> where C: Fn, B: Send {} 2667impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
2639 2668
2640fn test() { (S {}).method()<|>; } 2669fn 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
193fn 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
193fn convert_where_clauses( 201fn 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_)