Skip to content

Commit 0f57564

Browse files
bors[bot]flodiebold
andcommitted
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]>
2 parents 02ba107 + bc59f83 commit 0f57564

File tree

4 files changed

+83
-26
lines changed

4 files changed

+83
-26
lines changed

crates/ra_hir/src/resolve.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33

44
use ra_syntax::ast;
55

6-
use rustc_hash::FxHashMap;
6+
use rustc_hash::{FxHashMap, FxHashSet};
77

88
use crate::{
99
ModuleDef, Trait,
@@ -193,19 +193,18 @@ impl Resolver {
193193
names
194194
}
195195

196-
pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
197-
// FIXME prelude
198-
self.scopes
199-
.iter()
200-
.rev()
201-
.flat_map(|scope| {
202-
match scope {
203-
Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()),
204-
_ => None,
196+
pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> {
197+
let mut traits = FxHashSet::default();
198+
for scope in &self.scopes {
199+
if let Scope::ModuleScope(m) = scope {
200+
if let Some(prelude) = m.crate_def_map.prelude() {
201+
let prelude_def_map = db.crate_def_map(prelude.krate);
202+
traits.extend(prelude_def_map[prelude.module_id].scope.traits());
205203
}
206-
.into_iter()
207-
})
208-
.flatten()
204+
traits.extend(m.crate_def_map[m.module_id].scope.traits());
205+
}
206+
}
207+
traits
209208
}
210209

211210
fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {

crates/ra_hir/src/ty/method_resolution.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ impl CrateImplBlocks {
7575

7676
let target_ty = impl_block.target_ty(db);
7777

78-
if let Some(tr) = impl_block.target_trait_ref(db) {
79-
self.impls_by_trait
80-
.entry(tr.trait_)
81-
.or_insert_with(Vec::new)
82-
.push((module.module_id, impl_id));
78+
if impl_block.target_trait(db).is_some() {
79+
if let Some(tr) = impl_block.target_trait_ref(db) {
80+
self.impls_by_trait
81+
.entry(tr.trait_)
82+
.or_insert_with(Vec::new)
83+
.push((module.module_id, impl_id));
84+
}
8385
} else {
8486
if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
8587
self.impls
@@ -183,7 +185,7 @@ fn iterate_trait_method_candidates<T>(
183185
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
184186
) -> Option<T> {
185187
let krate = resolver.krate()?;
186-
'traits: for t in resolver.traits_in_scope() {
188+
'traits: for t in resolver.traits_in_scope(db) {
187189
let data = t.trait_data(db);
188190
// we'll be lazy about checking whether the type implements the
189191
// trait, but if we find out it doesn't, we'll skip the rest of the

crates/ra_hir/src/ty/tests.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,6 +2501,35 @@ fn test() { (&S).foo()<|>; }
25012501
assert_eq!(t, "u128");
25022502
}
25032503

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+
25042533
#[test]
25052534
fn method_resolution_where_clause_for_unknown_trait() {
25062535
// The blanket impl shouldn't apply because we can't even resolve UnknownTrait
@@ -2620,22 +2649,22 @@ fn method_resolution_slow() {
26202649
let t = type_at(
26212650
r#"
26222651
//- /main.rs
2623-
trait Send {}
2652+
trait SendX {}
26242653
2625-
struct S1; impl Send for S1;
2626-
struct S2; impl Send for S2;
2654+
struct S1; impl SendX for S1;
2655+
struct S2; impl SendX for S2;
26272656
struct U1;
26282657
26292658
trait Trait { fn method(self); }
26302659
26312660
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 {}
26332662
26342663
struct S<B, C> {}
26352664
2636-
trait Fn {}
2665+
trait FnX {}
26372666
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 {}
26392668
26402669
fn test() { (S {}).method()<|>; }
26412670
"#,

crates/ra_hir/src/ty/traits/chalk.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
190190
}
191191
}
192192

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+
193201
fn convert_where_clauses(
194202
db: &impl HirDatabase,
195203
def: GenericDef,
@@ -198,6 +206,19 @@ fn convert_where_clauses(
198206
let generic_predicates = db.generic_predicates(def);
199207
let mut result = Vec::with_capacity(generic_predicates.len());
200208
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+
}
201222
result.push(pred.clone().subst(substs).to_chalk(db));
202223
}
203224
result
@@ -230,6 +251,7 @@ where
230251
return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) });
231252
}
232253
let trait_: Trait = from_chalk(self.db, trait_id);
254+
debug!("trait {:?} = {:?}", trait_id, trait_.name(self.db));
233255
let generic_params = trait_.generic_params(self.db);
234256
let bound_vars = Substs::bound_vars(&generic_params);
235257
let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db);
@@ -250,6 +272,7 @@ where
250272
fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
251273
debug!("struct_datum {:?}", struct_id);
252274
let type_ctor = from_chalk(self.db, struct_id);
275+
debug!("struct {:?} = {:?}", struct_id, type_ctor);
253276
// FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
254277
// FIXME extract this to a method on Ty
255278
let (num_params, where_clauses, upstream) = match type_ctor {
@@ -358,7 +381,11 @@ where
358381
if trait_id == UNKNOWN_TRAIT {
359382
return Vec::new();
360383
}
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+
}
362389
let result: Vec<_> = self
363390
.db
364391
.impls_for_trait(self.krate, trait_)

0 commit comments

Comments
 (0)