@@ -8,7 +8,7 @@ use rustc_infer::traits::query::NoSolution;
8
8
use rustc_infer:: traits:: Reveal ;
9
9
use rustc_middle:: traits:: solve:: inspect:: ProbeKind ;
10
10
use rustc_middle:: traits:: solve:: {
11
- CandidateSource , CanonicalResponse , Certainty , Goal , QueryResult ,
11
+ CandidateSource , CanonicalResponse , Certainty , Goal , MaybeCause , QueryResult ,
12
12
} ;
13
13
use rustc_middle:: traits:: BuiltinImplSource ;
14
14
use rustc_middle:: ty:: fast_reject:: { SimplifiedType , TreatParams } ;
@@ -276,25 +276,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
276
276
& mut self ,
277
277
goal : Goal < ' tcx , G > ,
278
278
) -> 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
-
288
279
let Some ( normalized_self_ty) =
289
280
self . try_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
290
281
else {
291
282
debug ! ( "overflow while evaluating self type" ) ;
292
- return dummy_candidate ( self , Certainty :: OVERFLOW ) ;
283
+ return self . forced_ambiguity ( MaybeCause :: Overflow ) ;
293
284
} ;
294
285
295
286
if normalized_self_ty. is_ty_var ( ) {
296
287
debug ! ( "self type has been normalized to infer" ) ;
297
- return dummy_candidate ( self , Certainty :: AMBIGUOUS ) ;
288
+ return self . forced_ambiguity ( MaybeCause :: Ambiguity ) ;
298
289
}
299
290
300
291
let goal =
@@ -315,11 +306,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
315
306
316
307
self . assemble_param_env_candidates ( goal, & mut candidates) ;
317
308
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
+ }
319
315
320
316
candidates
321
317
}
322
318
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
+
323
329
#[ instrument( level = "debug" , skip_all) ]
324
330
fn assemble_non_blanket_impl_candidates < G : GoalKind < ' tcx > > (
325
331
& mut self ,
@@ -779,18 +785,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
779
785
}
780
786
}
781
787
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.
782
794
#[ instrument( level = "debug" , skip_all) ]
783
795
fn assemble_coherence_unknowable_candidates < G : GoalKind < ' tcx > > (
784
796
& mut self ,
785
797
goal : Goal < ' tcx , G > ,
786
798
candidates : & mut Vec < Candidate < ' tcx > > ,
787
799
) {
788
800
let tcx = self . tcx ( ) ;
789
- match self . solver_mode ( ) {
790
- SolverMode :: Normal => return ,
791
- SolverMode :: Coherence => { }
792
- } ;
793
-
794
801
let result = self . probe_misc_candidate ( "coherence unknowable" ) . enter ( |ecx| {
795
802
let trait_ref = goal. predicate . trait_ref ( tcx) ;
796
803
#[ derive( Debug ) ]
@@ -820,6 +827,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
820
827
}
821
828
}
822
829
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
+
823
875
/// If there are multiple ways to prove a trait or projection goal, we have
824
876
/// to somehow try to merge the candidates into one. If that fails, we return
825
877
/// ambiguity.
@@ -832,34 +884,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
832
884
let responses = candidates. iter ( ) . map ( |c| c. result ) . collect :: < Vec < _ > > ( ) ;
833
885
if let Some ( result) = self . try_merge_responses ( & responses) {
834
886
return Ok ( result) ;
887
+ } else {
888
+ self . flounder ( & responses)
835
889
}
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)
864
890
}
865
891
}
0 commit comments