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