Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a52accc

Browse files
lowrVeykril
authored andcommitted
Implement RustIrDatabase::impl_provided_for() for ChalkContext
1 parent 000ce5d commit a52accc

File tree

1 file changed

+130
-67
lines changed

1 file changed

+130
-67
lines changed

crates/hir-ty/src/chalk_db.rs

Lines changed: 130 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! The implementation of `RustIrDatabase` for Chalk, which provides information
22
//! about the code that Chalk needs.
33
use core::ops;
4-
use std::{iter, sync::Arc};
4+
use std::{iter, ops::ControlFlow, sync::Arc};
55

66
use tracing::debug;
77

@@ -136,81 +136,91 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
136136
_ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
137137
};
138138

139-
let trait_module = trait_.module(self.db.upcast());
140-
let type_module = match self_ty_fp {
141-
Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
142-
Some(TyFingerprint::ForeignType(type_id)) => {
143-
Some(from_foreign_def_id(type_id).module(self.db.upcast()))
144-
}
145-
Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
146-
_ => None,
147-
};
148-
149-
let mut def_blocks =
150-
[trait_module.containing_block(), type_module.and_then(|it| it.containing_block())];
151-
152-
// Note: Since we're using impls_for_trait, only impls where the trait
153-
// can be resolved should ever reach Chalk. impl_datum relies on that
154-
// and will panic if the trait can't be resolved.
155-
let in_deps = self.db.trait_impls_in_deps(self.krate);
156-
let in_self = self.db.trait_impls_in_crate(self.krate);
157-
158-
let block_impls = iter::successors(self.block, |&block_id| {
159-
cov_mark::hit!(block_local_impls);
160-
self.db.block_def_map(block_id).parent().and_then(|module| module.containing_block())
161-
})
162-
.inspect(|&block_id| {
163-
// make sure we don't search the same block twice
164-
def_blocks.iter_mut().for_each(|block| {
165-
if *block == Some(block_id) {
166-
*block = None;
167-
}
168-
});
169-
})
170-
.filter_map(|block_id| self.db.trait_impls_in_block(block_id));
171-
172139
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
140+
173141
let mut result = vec![];
174-
match fps {
175-
[] => {
176-
debug!("Unrestricted search for {:?} impls...", trait_);
177-
let mut f = |impls: &TraitImpls| {
178-
result.extend(impls.for_trait(trait_).map(id_to_chalk));
179-
};
180-
f(&in_self);
181-
in_deps.iter().map(ops::Deref::deref).for_each(&mut f);
182-
block_impls.for_each(|it| f(&it));
183-
def_blocks
184-
.into_iter()
185-
.flatten()
186-
.filter_map(|it| self.db.trait_impls_in_block(it))
187-
.for_each(|it| f(&it));
188-
}
189-
fps => {
190-
let mut f =
191-
|impls: &TraitImpls| {
192-
result.extend(fps.iter().flat_map(|fp| {
193-
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
194-
}));
195-
};
196-
f(&in_self);
197-
in_deps.iter().map(ops::Deref::deref).for_each(&mut f);
198-
block_impls.for_each(|it| f(&it));
199-
def_blocks
200-
.into_iter()
201-
.flatten()
202-
.filter_map(|it| self.db.trait_impls_in_block(it))
203-
.for_each(|it| f(&it));
204-
}
205-
}
142+
if fps.is_empty() {
143+
debug!("Unrestricted search for {:?} impls...", trait_);
144+
self.for_trait_impls(trait_, self_ty_fp, |impls| {
145+
result.extend(impls.for_trait(trait_).map(id_to_chalk));
146+
ControlFlow::Continue(())
147+
})
148+
} else {
149+
self.for_trait_impls(trait_, self_ty_fp, |impls| {
150+
result.extend(
151+
fps.iter().flat_map(move |fp| {
152+
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
153+
}),
154+
);
155+
ControlFlow::Continue(())
156+
})
157+
};
206158

207159
debug!("impls_for_trait returned {} impls", result.len());
208160
result
209161
}
210162
fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind<Interner>) -> bool {
211163
debug!("impl_provided_for {:?}, {:?}", auto_trait_id, kind);
212-
false // FIXME
164+
165+
let trait_id = from_chalk_trait_id(auto_trait_id);
166+
let self_ty = kind.clone().intern(Interner);
167+
// We cannot filter impls by `TyFingerprint` for the following types:
168+
let self_ty_fp = match kind {
169+
// because we need to find any impl whose Self type is a ref with the same mutability
170+
// (we don't care about the inner type).
171+
TyKind::Ref(..) => None,
172+
// because we need to find any impl whose Self type is a tuple with the same arity.
173+
TyKind::Tuple(..) => None,
174+
_ => TyFingerprint::for_trait_impl(&self_ty),
175+
};
176+
177+
let check_kind = |impl_id| {
178+
let impl_self_ty = self.db.impl_self_ty(impl_id);
179+
// NOTE(skip_binders): it's safe to skip binders here as we don't check substitutions.
180+
let impl_self_kind = impl_self_ty.skip_binders().kind(Interner);
181+
182+
match (kind, impl_self_kind) {
183+
(TyKind::Adt(id_a, _), TyKind::Adt(id_b, _)) => id_a == id_b,
184+
(TyKind::AssociatedType(id_a, _), TyKind::AssociatedType(id_b, _)) => id_a == id_b,
185+
(TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a == scalar_b,
186+
(TyKind::Str, TyKind::Str) => true,
187+
(TyKind::Tuple(arity_a, _), TyKind::Tuple(arity_b, _)) => arity_a == arity_b,
188+
(TyKind::OpaqueType(id_a, _), TyKind::OpaqueType(id_b, _)) => id_a == id_b,
189+
(TyKind::Slice(_), TyKind::Slice(_)) => true,
190+
(TyKind::FnDef(id_a, _), TyKind::FnDef(id_b, _)) => id_a == id_b,
191+
(TyKind::Ref(id_a, _, _), TyKind::Ref(id_b, _, _)) => id_a == id_b,
192+
(TyKind::Raw(id_a, _), TyKind::Raw(id_b, _)) => id_a == id_b,
193+
(TyKind::Never, TyKind::Never) => true,
194+
(TyKind::Array(_, _), TyKind::Array(_, _)) => true,
195+
(TyKind::Closure(id_a, _), TyKind::Closure(id_b, _)) => id_a == id_b,
196+
(TyKind::Coroutine(id_a, _), TyKind::Coroutine(id_b, _)) => id_a == id_b,
197+
(TyKind::CoroutineWitness(id_a, _), TyKind::CoroutineWitness(id_b, _)) => {
198+
id_a == id_b
199+
}
200+
(TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => id_a == id_b,
201+
(TyKind::Error, TyKind::Error) => true,
202+
(_, _) => false,
203+
}
204+
};
205+
206+
if let Some(fp) = self_ty_fp {
207+
self.for_trait_impls(trait_id, self_ty_fp, |impls| {
208+
match impls.for_trait_and_self_ty(trait_id, fp).any(check_kind) {
209+
true => ControlFlow::Break(()),
210+
false => ControlFlow::Continue(()),
211+
}
212+
})
213+
} else {
214+
self.for_trait_impls(trait_id, self_ty_fp, |impls| {
215+
match impls.for_trait(trait_id).any(check_kind) {
216+
true => ControlFlow::Break(()),
217+
false => ControlFlow::Continue(()),
218+
}
219+
})
220+
}
221+
.is_break()
213222
}
223+
214224
fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
215225
self.db.associated_ty_value(self.krate, id)
216226
}
@@ -489,6 +499,59 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
489499
}
490500
}
491501

502+
impl<'a> ChalkContext<'a> {
503+
fn for_trait_impls(
504+
&self,
505+
trait_id: hir_def::TraitId,
506+
self_ty_fp: Option<TyFingerprint>,
507+
mut f: impl FnMut(&TraitImpls) -> ControlFlow<()>,
508+
) -> ControlFlow<()> {
509+
// Note: Since we're using `impls_for_trait` and `impl_provided_for`,
510+
// only impls where the trait can be resolved should ever reach Chalk.
511+
// `impl_datum` relies on that and will panic if the trait can't be resolved.
512+
let in_deps = self.db.trait_impls_in_deps(self.krate);
513+
let in_self = self.db.trait_impls_in_crate(self.krate);
514+
let trait_module = trait_id.module(self.db.upcast());
515+
let type_module = match self_ty_fp {
516+
Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
517+
Some(TyFingerprint::ForeignType(type_id)) => {
518+
Some(from_foreign_def_id(type_id).module(self.db.upcast()))
519+
}
520+
Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
521+
_ => None,
522+
};
523+
524+
let mut def_blocks =
525+
[trait_module.containing_block(), type_module.and_then(|it| it.containing_block())];
526+
527+
let block_impls = iter::successors(self.block, |&block_id| {
528+
cov_mark::hit!(block_local_impls);
529+
self.db.block_def_map(block_id).parent().and_then(|module| module.containing_block())
530+
})
531+
.inspect(|&block_id| {
532+
// make sure we don't search the same block twice
533+
def_blocks.iter_mut().for_each(|block| {
534+
if *block == Some(block_id) {
535+
*block = None;
536+
}
537+
});
538+
})
539+
.filter_map(|block_id| self.db.trait_impls_in_block(block_id));
540+
f(&in_self)?;
541+
for it in in_deps.iter().map(ops::Deref::deref) {
542+
f(it)?;
543+
}
544+
for it in block_impls {
545+
f(&it)?;
546+
}
547+
for it in def_blocks.into_iter().flatten().filter_map(|it| self.db.trait_impls_in_block(it))
548+
{
549+
f(&it)?;
550+
}
551+
ControlFlow::Continue(())
552+
}
553+
}
554+
492555
impl chalk_ir::UnificationDatabase<Interner> for &dyn HirDatabase {
493556
fn fn_def_variance(
494557
&self,

0 commit comments

Comments
 (0)