2
2
3
3
#[cfg(doc)]
4
4
use super::trait_goals::structural_traits::*;
5
- use super::EvalCtxt;
5
+ use super::{EvalCtxt, SolverMode};
6
+ use crate::traits::coherence;
6
7
use itertools::Itertools;
7
8
use rustc_hir::def_id::DefId;
8
9
use rustc_infer::traits::query::NoSolution;
@@ -87,6 +88,8 @@ pub(super) enum CandidateSource {
87
88
pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
88
89
fn self_ty(self) -> Ty<'tcx>;
89
90
91
+ fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
92
+
90
93
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
91
94
92
95
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
@@ -244,15 +247,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
244
247
245
248
self.assemble_object_bound_candidates(goal, &mut candidates);
246
249
250
+ self.assemble_coherence_unknowable_candidates(goal, &mut candidates);
251
+
247
252
candidates
248
253
}
249
254
250
255
/// If the self type of a goal is a projection, computing the relevant candidates is difficult.
251
256
///
252
257
/// To deal with this, we first try to normalize the self type and add the candidates for the normalized
253
- /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in
254
- /// this case as projections as self types add
255
- // FIXME complete the unfinished sentence above
258
+ /// self type to the list of candidates in case that succeeds. We also have to consider candidates with the
259
+ /// projection as a self type as well
256
260
fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
257
261
&mut self,
258
262
goal: Goal<'tcx, G>,
@@ -468,25 +472,49 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
468
472
}
469
473
}
470
474
475
+ fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
476
+ &mut self,
477
+ goal: Goal<'tcx, G>,
478
+ candidates: &mut Vec<Candidate<'tcx>>,
479
+ ) {
480
+ match self.solver_mode() {
481
+ SolverMode::Normal => return,
482
+ SolverMode::Coherence => {
483
+ let trait_ref = goal.predicate.trait_ref(self.tcx());
484
+ match coherence::trait_ref_is_knowable(self.tcx(), trait_ref) {
485
+ Ok(()) => {}
486
+ Err(_) => match self
487
+ .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
488
+ {
489
+ Ok(result) => candidates
490
+ .push(Candidate { source: CandidateSource::BuiltinImpl, result }),
491
+ // FIXME: This will be reachable at some point if we're in
492
+ // `assemble_candidates_after_normalizing_self_ty` and we get a
493
+ // universe error. We'll deal with it at this point.
494
+ Err(NoSolution) => bug!("coherence candidate resulted in NoSolution"),
495
+ },
496
+ }
497
+ }
498
+ }
499
+ }
500
+
471
501
#[instrument(level = "debug", skip(self), ret)]
472
- pub(super) fn merge_candidates_and_discard_reservation_impls (
502
+ pub(super) fn merge_candidates (
473
503
&mut self,
474
504
mut candidates: Vec<Candidate<'tcx>>,
475
505
) -> QueryResult<'tcx> {
476
506
match candidates.len() {
477
507
0 => return Err(NoSolution),
478
- 1 => return Ok(self.discard_reservation_impl( candidates.pop().unwrap() ).result),
508
+ 1 => return Ok(candidates.pop().unwrap().result),
479
509
_ => {}
480
510
}
481
511
482
512
if candidates.len() > 1 {
483
513
let mut i = 0;
484
514
'outer: while i < candidates.len() {
485
515
for j in (0..candidates.len()).filter(|&j| i != j) {
486
- if self.trait_candidate_should_be_dropped_in_favor_of(
487
- &candidates[i],
488
- &candidates[j],
489
- ) {
516
+ if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
517
+ {
490
518
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
491
519
candidates.swap_remove(i);
492
520
continue 'outer;
@@ -511,11 +539,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
511
539
}
512
540
}
513
541
514
- // FIXME: What if there are >1 candidates left with the same response, and one is a reservation impl?
515
- Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
542
+ Ok(candidates.pop().unwrap().result)
516
543
}
517
544
518
- fn trait_candidate_should_be_dropped_in_favor_of (
545
+ fn candidate_should_be_dropped_in_favor_of (
519
546
&self,
520
547
candidate: &Candidate<'tcx>,
521
548
other: &Candidate<'tcx>,
@@ -528,20 +555,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
528
555
| (CandidateSource::BuiltinImpl, _) => false,
529
556
}
530
557
}
531
-
532
- fn discard_reservation_impl(&mut self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
533
- if let CandidateSource::Impl(def_id) = candidate.source {
534
- if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
535
- debug!("Selected reservation impl");
536
- // We assemble all candidates inside of a probe so by
537
- // making a new canonical response here our result will
538
- // have no constraints.
539
- candidate.result = self
540
- .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
541
- .unwrap();
542
- }
543
- }
544
-
545
- candidate
546
- }
547
558
}
0 commit comments