@@ -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 =
@@ -317,9 +308,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
317
308
318
309
self . assemble_coherence_unknowable_candidates ( goal, & mut candidates) ;
319
310
311
+ self . discard_impls_shadowed_by_env ( goal, & mut candidates) ;
312
+
320
313
candidates
321
314
}
322
315
316
+ fn forced_ambiguity ( & mut self , cause : MaybeCause ) -> Vec < Candidate < ' tcx > > {
317
+ let source = CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Misc ) ;
318
+ let certainty = Certainty :: Maybe ( cause) ;
319
+ let result = self . evaluate_added_goals_and_make_canonical_response ( certainty) . unwrap ( ) ;
320
+ let mut dummy_probe = self . inspect . new_probe ( ) ;
321
+ dummy_probe. probe_kind ( ProbeKind :: TraitCandidate { source, result : Ok ( result) } ) ;
322
+ self . inspect . finish_probe ( dummy_probe) ;
323
+ vec ! [ Candidate { source, result } ]
324
+ }
325
+
323
326
#[ instrument( level = "debug" , skip_all) ]
324
327
fn assemble_non_blanket_impl_candidates < G : GoalKind < ' tcx > > (
325
328
& mut self ,
@@ -826,6 +829,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
826
829
}
827
830
}
828
831
832
+ /// If there's a where-bound for the current goal, do not use any impl candidates
833
+ /// to prove the current goal. Most importantly, if there is a where-bound which does
834
+ /// not specify any associated types, we do not allow normalizing the associated type
835
+ /// by using an impl, even if it would apply.
836
+ ///
837
+ /// https://github.com/rust-lang/trait-system-refactor-initiative/issues/76
838
+ // FIXME(@lcnr): The current structure here makes me unhappy and feels ugly. idk how
839
+ // to improve this however. However, this should make it fairly straightforward to refine
840
+ // the filtering going forward, so it seems alright-ish for now.
841
+ fn discard_impls_shadowed_by_env < G : GoalKind < ' tcx > > (
842
+ & mut self ,
843
+ goal : Goal < ' tcx , G > ,
844
+ candidates : & mut Vec < Candidate < ' tcx > > ,
845
+ ) {
846
+ let tcx = self . tcx ( ) ;
847
+ let trait_goal: Goal < ' tcx , ty:: TraitPredicate < ' tcx > > =
848
+ goal. with ( tcx, goal. predicate . trait_ref ( tcx) ) ;
849
+ let mut trait_candidates_from_env = Vec :: new ( ) ;
850
+ self . assemble_param_env_candidates ( trait_goal, & mut trait_candidates_from_env) ;
851
+ self . assemble_alias_bound_candidates ( trait_goal, & mut trait_candidates_from_env) ;
852
+ if !trait_candidates_from_env. is_empty ( ) {
853
+ let trait_env_result = self . merge_candidates ( trait_candidates_from_env) ;
854
+ match trait_env_result. unwrap ( ) . value . certainty {
855
+ // If proving the trait goal succeeds by using the env,
856
+ // we freely drop all impl candidates.
857
+ //
858
+ // FIXME(@lcnr): It feels like this could easily hide
859
+ // a forced ambiguity candidate added earlier.
860
+ // This feels dangerous.
861
+ Certainty :: Yes => {
862
+ candidates. retain ( |c| match c. source {
863
+ CandidateSource :: Impl ( _) | CandidateSource :: BuiltinImpl ( _) => false ,
864
+ CandidateSource :: ParamEnv ( _) | CandidateSource :: AliasBound => true ,
865
+ } ) ;
866
+ }
867
+ // If it is still ambiguous we instead just force the whole goal
868
+ // to be ambig and wait for inference constraints. See
869
+ // tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs
870
+ Certainty :: Maybe ( cause) => {
871
+ * candidates = self . forced_ambiguity ( cause) ;
872
+ }
873
+ }
874
+ }
875
+ }
876
+
829
877
/// If there are multiple ways to prove a trait or projection goal, we have
830
878
/// to somehow try to merge the candidates into one. If that fails, we return
831
879
/// ambiguity.
@@ -838,34 +886,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
838
886
let responses = candidates. iter ( ) . map ( |c| c. result ) . collect :: < Vec < _ > > ( ) ;
839
887
if let Some ( result) = self . try_merge_responses ( & responses) {
840
888
return Ok ( result) ;
889
+ } else {
890
+ self . flounder ( & responses)
841
891
}
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)
870
892
}
871
893
}
0 commit comments