|
1 | 1 | //! The implementation of `RustIrDatabase` for Chalk, which provides information
|
2 | 2 | //! about the code that Chalk needs.
|
3 | 3 | use core::ops;
|
4 |
| -use std::{iter, sync::Arc}; |
| 4 | +use std::{iter, ops::ControlFlow, sync::Arc}; |
5 | 5 |
|
6 | 6 | use tracing::debug;
|
7 | 7 |
|
@@ -136,81 +136,91 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
136 | 136 | _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
|
137 | 137 | };
|
138 | 138 |
|
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 |
| - |
172 | 139 | let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
|
| 140 | + |
173 | 141 | 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 | + }; |
206 | 158 |
|
207 | 159 | debug!("impls_for_trait returned {} impls", result.len());
|
208 | 160 | result
|
209 | 161 | }
|
210 | 162 | fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind<Interner>) -> bool {
|
211 | 163 | 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() |
213 | 222 | }
|
| 223 | + |
214 | 224 | fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
|
215 | 225 | self.db.associated_ty_value(self.krate, id)
|
216 | 226 | }
|
@@ -489,6 +499,59 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
489 | 499 | }
|
490 | 500 | }
|
491 | 501 |
|
| 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 | + |
492 | 555 | impl chalk_ir::UnificationDatabase<Interner> for &dyn HirDatabase {
|
493 | 556 | fn fn_def_variance(
|
494 | 557 | &self,
|
|
0 commit comments