|
3 | 3 | use super::infcx_ext::InferCtxtExt;
|
4 | 4 | #[cfg(doc)]
|
5 | 5 | use super::trait_goals::structural_traits::*;
|
6 |
| -use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult}; |
| 6 | +use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; |
7 | 7 | use rustc_hir::def_id::DefId;
|
8 | 8 | use rustc_infer::traits::query::NoSolution;
|
9 | 9 | use rustc_infer::traits::util::elaborate_predicates;
|
@@ -399,10 +399,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
399 | 399 | ty::Alias(_, alias_ty) => alias_ty,
|
400 | 400 | };
|
401 | 401 |
|
402 |
| - for (assumption, _) in self |
403 |
| - .tcx() |
404 |
| - .bound_explicit_item_bounds(alias_ty.def_id) |
405 |
| - .subst_iter_copied(self.tcx(), alias_ty.substs) |
| 402 | + for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) |
406 | 403 | {
|
407 | 404 | match G::consider_assumption(self, goal, assumption) {
|
408 | 405 | Ok(result) => {
|
@@ -462,4 +459,78 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
462 | 459 | }
|
463 | 460 | }
|
464 | 461 | }
|
| 462 | + |
| 463 | + #[instrument(level = "debug", skip(self), ret)] |
| 464 | + pub(super) fn merge_candidates_and_discard_reservation_impls( |
| 465 | + &mut self, |
| 466 | + mut candidates: Vec<Candidate<'tcx>>, |
| 467 | + ) -> QueryResult<'tcx> { |
| 468 | + match candidates.len() { |
| 469 | + 0 => return Err(NoSolution), |
| 470 | + 1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result), |
| 471 | + _ => {} |
| 472 | + } |
| 473 | + |
| 474 | + if candidates.len() > 1 { |
| 475 | + let mut i = 0; |
| 476 | + 'outer: while i < candidates.len() { |
| 477 | + for j in (0..candidates.len()).filter(|&j| i != j) { |
| 478 | + if self.trait_candidate_should_be_dropped_in_favor_of( |
| 479 | + &candidates[i], |
| 480 | + &candidates[j], |
| 481 | + ) { |
| 482 | + debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); |
| 483 | + candidates.swap_remove(i); |
| 484 | + continue 'outer; |
| 485 | + } |
| 486 | + } |
| 487 | + |
| 488 | + debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len()); |
| 489 | + i += 1; |
| 490 | + } |
| 491 | + |
| 492 | + // If there are *STILL* multiple candidates, give up |
| 493 | + // and report ambiguity. |
| 494 | + if candidates.len() > 1 { |
| 495 | + let certainty = if candidates.iter().all(|x| { |
| 496 | + matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow)) |
| 497 | + }) { |
| 498 | + Certainty::Maybe(MaybeCause::Overflow) |
| 499 | + } else { |
| 500 | + Certainty::AMBIGUOUS |
| 501 | + }; |
| 502 | + return self.make_canonical_response(certainty); |
| 503 | + } |
| 504 | + } |
| 505 | + |
| 506 | + Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result) |
| 507 | + } |
| 508 | + |
| 509 | + fn trait_candidate_should_be_dropped_in_favor_of( |
| 510 | + &self, |
| 511 | + candidate: &Candidate<'tcx>, |
| 512 | + other: &Candidate<'tcx>, |
| 513 | + ) -> bool { |
| 514 | + // FIXME: implement this |
| 515 | + match (candidate.source, other.source) { |
| 516 | + (CandidateSource::Impl(_), _) |
| 517 | + | (CandidateSource::ParamEnv(_), _) |
| 518 | + | (CandidateSource::AliasBound, _) |
| 519 | + | (CandidateSource::BuiltinImpl, _) => false, |
| 520 | + } |
| 521 | + } |
| 522 | + |
| 523 | + fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> { |
| 524 | + if let CandidateSource::Impl(def_id) = candidate.source { |
| 525 | + if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) { |
| 526 | + debug!("Selected reservation impl"); |
| 527 | + // We assemble all candidates inside of a probe so by |
| 528 | + // making a new canonical response here our result will |
| 529 | + // have no constraints. |
| 530 | + candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(); |
| 531 | + } |
| 532 | + } |
| 533 | + |
| 534 | + candidate |
| 535 | + } |
465 | 536 | }
|
0 commit comments