@@ -8,7 +8,7 @@ use rustc_infer::traits::query::NoSolution;
88use rustc_infer:: traits:: Reveal ;
99use rustc_middle:: traits:: solve:: inspect:: ProbeKind ;
1010use rustc_middle:: traits:: solve:: {
11- CandidateSource , CanonicalResponse , Certainty , Goal , QueryResult ,
11+ CandidateSource , CanonicalResponse , Certainty , Goal , MaybeCause , QueryResult ,
1212} ;
1313use rustc_middle:: traits:: BuiltinImplSource ;
1414use rustc_middle:: ty:: fast_reject:: { SimplifiedType , TreatParams } ;
@@ -276,25 +276,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
276276 & mut self ,
277277 goal : Goal < ' tcx , G > ,
278278 ) -> Vec < Candidate < ' tcx > > {
279- let dummy_candidate = |this : & mut EvalCtxt < ' _ , ' tcx > , certainty| {
280- let source = CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Misc ) ;
281- let result = this. evaluate_added_goals_and_make_canonical_response ( certainty) . unwrap ( ) ;
282- let mut dummy_probe = this. inspect . new_probe ( ) ;
283- dummy_probe. probe_kind ( ProbeKind :: TraitCandidate { source, result : Ok ( result) } ) ;
284- this. inspect . finish_probe ( dummy_probe) ;
285- vec ! [ Candidate { source, result } ]
286- } ;
287-
288279 let Some ( normalized_self_ty) =
289280 self . try_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
290281 else {
291282 debug ! ( "overflow while evaluating self type" ) ;
292- return dummy_candidate ( self , Certainty :: OVERFLOW ) ;
283+ return self . forced_ambiguity ( MaybeCause :: Overflow ) ;
293284 } ;
294285
295286 if normalized_self_ty. is_ty_var ( ) {
296287 debug ! ( "self type has been normalized to infer" ) ;
297- return dummy_candidate ( self , Certainty :: AMBIGUOUS ) ;
288+ return self . forced_ambiguity ( MaybeCause :: Ambiguity ) ;
298289 }
299290
300291 let goal =
@@ -315,11 +306,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
315306
316307 self . assemble_param_env_candidates ( goal, & mut candidates) ;
317308
318- self . assemble_coherence_unknowable_candidates ( goal, & mut candidates) ;
309+ match self . solver_mode ( ) {
310+ SolverMode :: Normal => self . discard_impls_shadowed_by_env ( goal, & mut candidates) ,
311+ SolverMode :: Coherence => {
312+ self . assemble_coherence_unknowable_candidates ( goal, & mut candidates)
313+ }
314+ }
319315
320316 candidates
321317 }
322318
319+ fn forced_ambiguity ( & mut self , cause : MaybeCause ) -> Vec < Candidate < ' tcx > > {
320+ let source = CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Misc ) ;
321+ let certainty = Certainty :: Maybe ( cause) ;
322+ let result = self . evaluate_added_goals_and_make_canonical_response ( certainty) . unwrap ( ) ;
323+ let mut dummy_probe = self . inspect . new_probe ( ) ;
324+ dummy_probe. probe_kind ( ProbeKind :: TraitCandidate { source, result : Ok ( result) } ) ;
325+ self . inspect . finish_probe ( dummy_probe) ;
326+ vec ! [ Candidate { source, result } ]
327+ }
328+
323329 #[ instrument( level = "debug" , skip_all) ]
324330 fn assemble_non_blanket_impl_candidates < G : GoalKind < ' tcx > > (
325331 & mut self ,
@@ -792,11 +798,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
792798 candidates : & mut Vec < Candidate < ' tcx > > ,
793799 ) {
794800 let tcx = self . tcx ( ) ;
795- match self . solver_mode ( ) {
796- SolverMode :: Normal => return ,
797- SolverMode :: Coherence => { }
798- } ;
799-
800801 let result = self . probe_misc_candidate ( "coherence unknowable" ) . enter ( |ecx| {
801802 let trait_ref = goal. predicate . trait_ref ( tcx) ;
802803 #[ derive( Debug ) ]
@@ -826,6 +827,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
826827 }
827828 }
828829
830+ /// If there's a where-bound for the current goal, do not use any impl candidates
831+ /// to prove the current goal. Most importantly, if there is a where-bound which does
832+ /// not specify any associated types, we do not allow normalizing the associated type
833+ /// by using an impl, even if it would apply.
834+ ///
835+ /// <https://github.com/rust-lang/trait-system-refactor-initiative/issues/76>
836+ // FIXME(@lcnr): The current structure here makes me unhappy and feels ugly. idk how
837+ // to improve this however. However, this should make it fairly straightforward to refine
838+ // the filtering going forward, so it seems alright-ish for now.
839+ fn discard_impls_shadowed_by_env < G : GoalKind < ' tcx > > (
840+ & mut self ,
841+ goal : Goal < ' tcx , G > ,
842+ candidates : & mut Vec < Candidate < ' tcx > > ,
843+ ) {
844+ let tcx = self . tcx ( ) ;
845+ let trait_goal: Goal < ' tcx , ty:: TraitPredicate < ' tcx > > =
846+ goal. with ( tcx, goal. predicate . trait_ref ( tcx) ) ;
847+ let mut trait_candidates_from_env = Vec :: new ( ) ;
848+ self . assemble_param_env_candidates ( trait_goal, & mut trait_candidates_from_env) ;
849+ self . assemble_alias_bound_candidates ( trait_goal, & mut trait_candidates_from_env) ;
850+ if !trait_candidates_from_env. is_empty ( ) {
851+ let trait_env_result = self . merge_candidates ( trait_candidates_from_env) ;
852+ match trait_env_result. unwrap ( ) . value . certainty {
853+ // If proving the trait goal succeeds by using the env,
854+ // we freely drop all impl candidates.
855+ //
856+ // FIXME(@lcnr): It feels like this could easily hide
857+ // a forced ambiguity candidate added earlier.
858+ // This feels dangerous.
859+ Certainty :: Yes => {
860+ candidates. retain ( |c| match c. source {
861+ CandidateSource :: Impl ( _) | CandidateSource :: BuiltinImpl ( _) => false ,
862+ CandidateSource :: ParamEnv ( _) | CandidateSource :: AliasBound => true ,
863+ } ) ;
864+ }
865+ // If it is still ambiguous we instead just force the whole goal
866+ // to be ambig and wait for inference constraints. See
867+ // tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs
868+ Certainty :: Maybe ( cause) => {
869+ * candidates = self . forced_ambiguity ( cause) ;
870+ }
871+ }
872+ }
873+ }
874+
829875 /// If there are multiple ways to prove a trait or projection goal, we have
830876 /// to somehow try to merge the candidates into one. If that fails, we return
831877 /// ambiguity.
@@ -838,34 +884,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
838884 let responses = candidates. iter ( ) . map ( |c| c. result ) . collect :: < Vec < _ > > ( ) ;
839885 if let Some ( result) = self . try_merge_responses ( & responses) {
840886 return Ok ( result) ;
887+ } else {
888+ self . flounder ( & responses)
841889 }
842-
843- // We then check whether we should prioritize `ParamEnv` candidates.
844- //
845- // Doing so is incomplete and would therefore be unsound during coherence.
846- match self . solver_mode ( ) {
847- SolverMode :: Coherence => ( ) ,
848- // Prioritize `ParamEnv` candidates only if they do not guide inference.
849- //
850- // This is still incomplete as we may add incorrect region bounds.
851- SolverMode :: Normal => {
852- let param_env_responses = candidates
853- . iter ( )
854- . filter ( |c| {
855- matches ! (
856- c. source,
857- CandidateSource :: ParamEnv ( _) | CandidateSource :: AliasBound
858- )
859- } )
860- . map ( |c| c. result )
861- . collect :: < Vec < _ > > ( ) ;
862- if let Some ( result) = self . try_merge_responses ( & param_env_responses) {
863- // We strongly prefer alias and param-env bounds here, even if they affect inference.
864- // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/11.
865- return Ok ( result) ;
866- }
867- }
868- }
869- self . flounder ( & responses)
870890 }
871891}
0 commit comments