@@ -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 ,
@@ -779,18 +785,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
779785 }
780786 }
781787
788+ /// In coherence we have to not only care about all impls we know about, but
789+ /// also consider impls which may get added in a downstream or sibling crate
790+ /// or which an upstream impl may add in a minor release.
791+ ///
792+ /// To do so we add an ambiguous candidate in case such an unknown impl could
793+ /// apply to the current goal.
782794 #[ instrument( level = "debug" , skip_all) ]
783795 fn assemble_coherence_unknowable_candidates < G : GoalKind < ' tcx > > (
784796 & mut self ,
785797 goal : Goal < ' tcx , G > ,
786798 candidates : & mut Vec < Candidate < ' tcx > > ,
787799 ) {
788800 let tcx = self . tcx ( ) ;
789- match self . solver_mode ( ) {
790- SolverMode :: Normal => return ,
791- SolverMode :: Coherence => { }
792- } ;
793-
794801 let result = self . probe_misc_candidate ( "coherence unknowable" ) . enter ( |ecx| {
795802 let trait_ref = goal. predicate . trait_ref ( tcx) ;
796803 #[ derive( Debug ) ]
@@ -820,6 +827,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
820827 }
821828 }
822829
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+
823875 /// If there are multiple ways to prove a trait or projection goal, we have
824876 /// to somehow try to merge the candidates into one. If that fails, we return
825877 /// ambiguity.
@@ -832,34 +884,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
832884 let responses = candidates. iter ( ) . map ( |c| c. result ) . collect :: < Vec < _ > > ( ) ;
833885 if let Some ( result) = self . try_merge_responses ( & responses) {
834886 return Ok ( result) ;
887+ } else {
888+ self . flounder ( & responses)
835889 }
836-
837- // We then check whether we should prioritize `ParamEnv` candidates.
838- //
839- // Doing so is incomplete and would therefore be unsound during coherence.
840- match self . solver_mode ( ) {
841- SolverMode :: Coherence => ( ) ,
842- // Prioritize `ParamEnv` candidates only if they do not guide inference.
843- //
844- // This is still incomplete as we may add incorrect region bounds.
845- SolverMode :: Normal => {
846- let param_env_responses = candidates
847- . iter ( )
848- . filter ( |c| {
849- matches ! (
850- c. source,
851- CandidateSource :: ParamEnv ( _) | CandidateSource :: AliasBound
852- )
853- } )
854- . map ( |c| c. result )
855- . collect :: < Vec < _ > > ( ) ;
856- if let Some ( result) = self . try_merge_responses ( & param_env_responses) {
857- // We strongly prefer alias and param-env bounds here, even if they affect inference.
858- // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/11.
859- return Ok ( result) ;
860- }
861- }
862- }
863- self . flounder ( & responses)
864890 }
865891}
0 commit comments