Skip to content

Commit 71f4da6

Browse files
committed
Implement RustIrDatabase::impl_provided_for() for ChalkContext
1 parent 7f38581 commit 71f4da6

File tree

1 file changed

+90
-33
lines changed

1 file changed

+90
-33
lines changed

crates/hir-ty/src/chalk_db.rs

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

55
use cov_mark::hit;
6+
use smallvec::SmallVec;
67
use syntax::SmolStr;
78
use tracing::debug;
89

@@ -108,46 +109,16 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
108109
_ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
109110
};
110111

111-
fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
112-
let block = module.containing_block()?;
113-
hit!(block_local_impls);
114-
db.trait_impls_in_block(block)
115-
}
116-
117-
// Note: Since we're using impls_for_trait, only impls where the trait
118-
// can be resolved should ever reach Chalk. impl_datum relies on that
119-
// and will panic if the trait can't be resolved.
120-
let in_deps = self.db.trait_impls_in_deps(self.krate);
121-
let in_self = self.db.trait_impls_in_crate(self.krate);
122-
let trait_module = trait_.module(self.db.upcast());
123-
let type_module = match self_ty_fp {
124-
Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
125-
Some(TyFingerprint::ForeignType(type_id)) => {
126-
Some(from_foreign_def_id(type_id).module(self.db.upcast()))
127-
}
128-
Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
129-
_ => None,
130-
};
131-
let impl_maps = [
132-
Some(in_deps),
133-
Some(in_self),
134-
local_impls(self.db, trait_module),
135-
type_module.and_then(|m| local_impls(self.db, m)),
136-
];
112+
let impl_maps = self.get_trait_impls(trait_, self_ty_fp);
137113

138114
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
139115

140116
let result: Vec<_> = if fps.is_empty() {
141117
debug!("Unrestricted search for {:?} impls...", trait_);
142-
impl_maps
143-
.iter()
144-
.filter_map(|o| o.as_ref())
145-
.flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk))
146-
.collect()
118+
impl_maps.iter().flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk)).collect()
147119
} else {
148120
impl_maps
149121
.iter()
150-
.filter_map(|o| o.as_ref())
151122
.flat_map(|impls| {
152123
fps.iter().flat_map(move |fp| {
153124
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
@@ -161,7 +132,58 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
161132
}
162133
fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind<Interner>) -> bool {
163134
debug!("impl_provided_for {:?}, {:?}", auto_trait_id, kind);
164-
false // FIXME
135+
136+
let trait_id = from_chalk_trait_id(auto_trait_id);
137+
let self_ty = kind.clone().intern(Interner);
138+
// We cannot filter impls by `TyFingerprint` for the following types:
139+
let self_ty_fp = match kind {
140+
// because we need to find any impl whose Self type is a ref with the same mutability
141+
// (we don't care about the inner type).
142+
TyKind::Ref(..) => None,
143+
// because we need to find any impl whose Self type is a tuple with the same arity.
144+
TyKind::Tuple(..) => None,
145+
_ => TyFingerprint::for_trait_impl(&self_ty),
146+
};
147+
148+
let impl_maps = self.get_trait_impls(trait_id, self_ty_fp);
149+
150+
let check_kind = |impl_id| {
151+
let impl_self_ty = self.db.impl_self_ty(impl_id);
152+
// NOTE(skip_binders): it's safe to skip binders here as we don't check substitutions.
153+
let impl_self_kind = impl_self_ty.skip_binders().kind(Interner);
154+
155+
match (kind, impl_self_kind) {
156+
(TyKind::Adt(id_a, _), TyKind::Adt(id_b, _)) => id_a == id_b,
157+
(TyKind::AssociatedType(id_a, _), TyKind::AssociatedType(id_b, _)) => id_a == id_b,
158+
(TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a == scalar_b,
159+
(TyKind::Str, TyKind::Str) => true,
160+
(TyKind::Tuple(arity_a, _), TyKind::Tuple(arity_b, _)) => arity_a == arity_b,
161+
(TyKind::OpaqueType(id_a, _), TyKind::OpaqueType(id_b, _)) => id_a == id_b,
162+
(TyKind::Slice(_), TyKind::Slice(_)) => true,
163+
(TyKind::FnDef(id_a, _), TyKind::FnDef(id_b, _)) => id_a == id_b,
164+
(TyKind::Ref(id_a, _, _), TyKind::Ref(id_b, _, _)) => id_a == id_b,
165+
(TyKind::Raw(id_a, _), TyKind::Raw(id_b, _)) => id_a == id_b,
166+
(TyKind::Never, TyKind::Never) => true,
167+
(TyKind::Array(_, _), TyKind::Array(_, _)) => true,
168+
(TyKind::Closure(id_a, _), TyKind::Closure(id_b, _)) => id_a == id_b,
169+
(TyKind::Generator(id_a, _), TyKind::Generator(id_b, _)) => id_a == id_b,
170+
(TyKind::GeneratorWitness(id_a, _), TyKind::GeneratorWitness(id_b, _)) => {
171+
id_a == id_b
172+
}
173+
(TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => id_a == id_b,
174+
(TyKind::Error, TyKind::Error) => true,
175+
(_, _) => false,
176+
}
177+
};
178+
179+
if let Some(fp) = self_ty_fp {
180+
impl_maps
181+
.iter()
182+
.flat_map(|impls| impls.for_trait_and_self_ty(trait_id, fp))
183+
.any(check_kind)
184+
} else {
185+
impl_maps.iter().flat_map(|impls| impls.for_trait(trait_id)).any(check_kind)
186+
}
165187
}
166188
fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
167189
self.db.associated_ty_value(self.krate, id)
@@ -390,6 +412,41 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
390412
}
391413
}
392414

415+
impl<'a> ChalkContext<'a> {
416+
fn get_trait_impls(
417+
&self,
418+
trait_id: hir_def::TraitId,
419+
self_ty_fp: Option<TyFingerprint>,
420+
) -> SmallVec<[Arc<TraitImpls>; 4]> {
421+
// Note: Since we're using `impls_for_trait` and `impl_provided_for`,
422+
// only impls where the trait can be resolved should ever reach Chalk.
423+
// `impl_datum` relies on that and will panic if the trait can't be resolved.
424+
let in_deps = self.db.trait_impls_in_deps(self.krate);
425+
let in_self = self.db.trait_impls_in_crate(self.krate);
426+
let trait_module = trait_id.module(self.db.upcast());
427+
let type_module = match self_ty_fp {
428+
Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
429+
Some(TyFingerprint::ForeignType(type_id)) => {
430+
Some(from_foreign_def_id(type_id).module(self.db.upcast()))
431+
}
432+
Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
433+
_ => None,
434+
};
435+
436+
[in_deps, in_self]
437+
.into_iter()
438+
.chain(self.local_impls(trait_module))
439+
.chain(type_module.and_then(|m| self.local_impls(m)))
440+
.collect()
441+
}
442+
443+
fn local_impls(&self, module: ModuleId) -> Option<Arc<TraitImpls>> {
444+
let block = module.containing_block()?;
445+
hit!(block_local_impls);
446+
self.db.trait_impls_in_block(block)
447+
}
448+
}
449+
393450
impl<'a> chalk_ir::UnificationDatabase<Interner> for &'a dyn HirDatabase {
394451
fn fn_def_variance(
395452
&self,

0 commit comments

Comments
 (0)