@@ -284,6 +284,21 @@ where
284
284
) -> Vec < Candidate < I > > ;
285
285
}
286
286
287
+ /// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit
288
+ /// candidate assembly to param-env and alias-bound candidates.
289
+ ///
290
+ /// On top of being a micro-optimization, as it avoids doing unnecessary work when
291
+ /// a param-env trait bound candidate shadows impls for normalization, this is also
292
+ /// required to prevent query cycles due to RPITIT inference. See the issue at:
293
+ /// <https://github.com/rust-lang/trait-system-refactor-initiative/issues/173>.
294
+ pub ( super ) enum AssembleCandidatesFrom {
295
+ All ,
296
+ /// Only assemble candidates from the environment and alias bounds, ignoring
297
+ /// user-written and built-in impls. We only expect `ParamEnv` and `AliasBound`
298
+ /// candidates to be assembled.
299
+ EnvAndBounds ,
300
+ }
301
+
287
302
impl < D , I > EvalCtxt < ' _ , D >
288
303
where
289
304
D : SolverDelegate < Interner = I > ,
@@ -292,6 +307,7 @@ where
292
307
pub ( super ) fn assemble_and_evaluate_candidates < G : GoalKind < D > > (
293
308
& mut self ,
294
309
goal : Goal < I , G > ,
310
+ assemble_from : AssembleCandidatesFrom ,
295
311
) -> Vec < Candidate < I > > {
296
312
let Ok ( normalized_self_ty) =
297
313
self . structurally_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
@@ -318,16 +334,18 @@ where
318
334
}
319
335
}
320
336
321
- self . assemble_impl_candidates ( goal, & mut candidates) ;
322
-
323
- self . assemble_builtin_impl_candidates ( goal, & mut candidates) ;
324
-
325
337
self . assemble_alias_bound_candidates ( goal, & mut candidates) ;
326
-
327
- self . assemble_object_bound_candidates ( goal, & mut candidates) ;
328
-
329
338
self . assemble_param_env_candidates ( goal, & mut candidates) ;
330
339
340
+ match assemble_from {
341
+ AssembleCandidatesFrom :: All => {
342
+ self . assemble_impl_candidates ( goal, & mut candidates) ;
343
+ self . assemble_builtin_impl_candidates ( goal, & mut candidates) ;
344
+ self . assemble_object_bound_candidates ( goal, & mut candidates) ;
345
+ }
346
+ AssembleCandidatesFrom :: EnvAndBounds => { }
347
+ }
348
+
331
349
candidates
332
350
}
333
351
@@ -750,6 +768,9 @@ where
750
768
} )
751
769
}
752
770
771
+ /// Assemble and merge candidates for goals which are related to an underlying trait
772
+ /// goal. Right now, this is normalizes-to and host effect goals.
773
+ ///
753
774
/// We sadly can't simply take all possible candidates for normalization goals
754
775
/// and check whether they result in the same constraints. We want to make sure
755
776
/// that trying to normalize an alias doesn't result in constraints which aren't
@@ -778,47 +799,41 @@ where
778
799
///
779
800
/// See trait-system-refactor-initiative#124 for more details.
780
801
#[ instrument( level = "debug" , skip( self , inject_normalize_to_rigid_candidate) , ret) ]
781
- pub ( super ) fn merge_candidates (
802
+ pub ( super ) fn assemble_and_merge_candidates < G : GoalKind < D > > (
782
803
& mut self ,
783
804
proven_via : Option < TraitGoalProvenVia > ,
784
- candidates : Vec < Candidate < I > > ,
805
+ goal : Goal < I , G > ,
785
806
inject_normalize_to_rigid_candidate : impl FnOnce ( & mut EvalCtxt < ' _ , D > ) -> QueryResult < I > ,
786
807
) -> QueryResult < I > {
787
808
let Some ( proven_via) = proven_via else {
788
809
// We don't care about overflow. If proving the trait goal overflowed, then
789
810
// it's enough to report an overflow error for that, we don't also have to
790
811
// overflow during normalization.
791
- return Ok ( self . make_ambiguous_response_no_constraints ( MaybeCause :: Ambiguity ) ) ;
812
+ return Ok ( self . forced_ambiguity ( MaybeCause :: Ambiguity ) ? . result ) ;
792
813
} ;
793
814
794
815
match proven_via {
795
816
TraitGoalProvenVia :: ParamEnv | TraitGoalProvenVia :: AliasBound => {
796
- let mut considered_candidates = Vec :: new ( ) ;
797
- considered_candidates. extend (
798
- candidates
799
- . iter ( )
800
- . filter ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) )
801
- . map ( |c| c. result ) ,
802
- ) ;
803
-
804
817
// Even when a trait bound has been proven using a where-bound, we
805
818
// still need to consider alias-bounds for normalization, see
806
- // tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
807
- //
819
+ // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
820
+ let candidates_from_env_and_bounds: Vec < _ > = self
821
+ . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: EnvAndBounds ) ;
822
+
808
823
// We still need to prefer where-bounds over alias-bounds however.
809
- // See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs.
810
- //
811
- // FIXME(const_trait_impl): should this behavior also be used by
812
- // constness checking. Doing so is *at least theoretically* breaking,
813
- // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
814
- if considered_candidates . is_empty ( ) {
815
- considered_candidates . extend (
816
- candidates
817
- . iter ( )
818
- . filter ( |c| matches ! ( c . source , CandidateSource :: AliasBound ) )
819
- . map ( |c| c . result ) ,
820
- ) ;
821
- }
824
+ // See ` tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs` .
825
+ let mut considered_candidates : Vec < _ > = if candidates_from_env_and_bounds
826
+ . iter ( )
827
+ . any ( |c| matches ! ( c . source , CandidateSource :: ParamEnv ( _ ) ) )
828
+ {
829
+ candidates_from_env_and_bounds
830
+ . into_iter ( )
831
+ . filter ( |c| matches ! ( c . source , CandidateSource :: ParamEnv ( _ ) ) )
832
+ . map ( |c| c . result )
833
+ . collect ( )
834
+ } else {
835
+ candidates_from_env_and_bounds . into_iter ( ) . map ( |c| c . result ) . collect ( )
836
+ } ;
822
837
823
838
// If the trait goal has been proven by using the environment, we want to treat
824
839
// aliases as rigid if there are no applicable projection bounds in the environment.
@@ -835,6 +850,9 @@ where
835
850
}
836
851
}
837
852
TraitGoalProvenVia :: Misc => {
853
+ let candidates =
854
+ self . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: All ) ;
855
+
838
856
// Prefer "orphaned" param-env normalization predicates, which are used
839
857
// (for example, and ideally only) when proving item bounds for an impl.
840
858
let candidates_from_env: Vec < _ > = candidates
0 commit comments