aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-05-12 19:36:36 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-05-12 19:36:36 +0100
commit0f57564f78207946fdb09e0cddc21a55966b1bc5 (patch)
treee8aa2948b2bb301f453307c35311634cda5de43b /crates/ra_hir
parent02ba107bbf24b1d09e61f76bb64b7355076744c4 (diff)
parentbc59f83991a6444ff2f2364b0e942e8a82943b6d (diff)
Merge #1266
1266: Chalk integration / method resolution fixes r=matklad a=flodiebold - fix impl blocks with unresolved target trait being treated as inherent impls - add traits from prelude for method resolution, and deduplicate them - blacklist some traits from being considered in where clauses, namely `Send`, `Sync`, `Sized`, and the `Fn` traits. We don't handle these correctly yet for several reasons, and this makes us much less likely to run into cases where Chalk gets very slow (because these usually only happen if there is no solution, and that's more likely to happen for these traits). - when there's an errored where clause, return just that one (since it will be always false anyway). This also makes things easier on Chalk ;) Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-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_)