22
33#[ cfg( doc) ]
44use super :: trait_goals:: structural_traits:: * ;
5- use super :: EvalCtxt ;
5+ use super :: { EvalCtxt , SolverMode } ;
6+ use crate :: traits:: coherence;
67use itertools:: Itertools ;
78use rustc_hir:: def_id:: DefId ;
89use rustc_infer:: traits:: query:: NoSolution ;
@@ -87,6 +88,8 @@ pub(super) enum CandidateSource {
8788pub ( super ) trait GoalKind < ' tcx > : TypeFoldable < TyCtxt < ' tcx > > + Copy + Eq {
8889 fn self_ty ( self ) -> Ty < ' tcx > ;
8990
91+ fn trait_ref ( self , tcx : TyCtxt < ' tcx > ) -> ty:: TraitRef < ' tcx > ;
92+
9093 fn with_self_ty ( self , tcx : TyCtxt < ' tcx > , self_ty : Ty < ' tcx > ) -> Self ;
9194
9295 fn trait_def_id ( self , tcx : TyCtxt < ' tcx > ) -> DefId ;
@@ -244,15 +247,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
244247
245248 self . assemble_object_bound_candidates ( goal, & mut candidates) ;
246249
250+ self . assemble_coherence_unknowable_candidates ( goal, & mut candidates) ;
251+
247252 candidates
248253 }
249254
250255 /// If the self type of a goal is a projection, computing the relevant candidates is difficult.
251256 ///
252257 /// 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
256260 fn assemble_candidates_after_normalizing_self_ty < G : GoalKind < ' tcx > > (
257261 & mut self ,
258262 goal : Goal < ' tcx , G > ,
@@ -468,25 +472,49 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
468472 }
469473 }
470474
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+
471501 #[ instrument( level = "debug" , skip( self ) , ret) ]
472- pub ( super ) fn merge_candidates_and_discard_reservation_impls (
502+ pub ( super ) fn merge_candidates (
473503 & mut self ,
474504 mut candidates : Vec < Candidate < ' tcx > > ,
475505 ) -> QueryResult < ' tcx > {
476506 match candidates. len ( ) {
477507 0 => return Err ( NoSolution ) ,
478- 1 => return Ok ( self . discard_reservation_impl ( candidates. pop ( ) . unwrap ( ) ) . result ) ,
508+ 1 => return Ok ( candidates. pop ( ) . unwrap ( ) . result ) ,
479509 _ => { }
480510 }
481511
482512 if candidates. len ( ) > 1 {
483513 let mut i = 0 ;
484514 ' outer: while i < candidates. len ( ) {
485515 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+ {
490518 debug ! ( candidate = ?candidates[ i] , "Dropping candidate #{}/{}" , i, candidates. len( ) ) ;
491519 candidates. swap_remove ( i) ;
492520 continue ' outer;
@@ -511,11 +539,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
511539 }
512540 }
513541
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 )
516543 }
517544
518- fn trait_candidate_should_be_dropped_in_favor_of (
545+ fn candidate_should_be_dropped_in_favor_of (
519546 & self ,
520547 candidate : & Candidate < ' tcx > ,
521548 other : & Candidate < ' tcx > ,
@@ -528,20 +555,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
528555 | ( CandidateSource :: BuiltinImpl , _) => false ,
529556 }
530557 }
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- }
547558}
0 commit comments