@@ -17,7 +17,6 @@ use rustc_type_ir::{
1717} ;
1818use tracing:: { debug, instrument} ;
1919
20- use super :: trait_goals:: TraitGoalProvenVia ;
2120use super :: { has_only_region_constraints, inspect} ;
2221use crate :: delegate:: SolverDelegate ;
2322use crate :: solve:: inspect:: ProbeKind ;
@@ -363,13 +362,15 @@ pub(super) enum AssembleCandidatesFrom {
363362 /// user-written and built-in impls. We only expect `ParamEnv` and `AliasBound`
364363 /// candidates to be assembled.
365364 EnvAndBounds ,
365+ Impl ,
366366}
367367
368368impl AssembleCandidatesFrom {
369369 fn should_assemble_impl_candidates ( & self ) -> bool {
370370 match self {
371371 AssembleCandidatesFrom :: All => true ,
372372 AssembleCandidatesFrom :: EnvAndBounds => false ,
373+ AssembleCandidatesFrom :: Impl => true ,
373374 }
374375 }
375376}
@@ -426,11 +427,14 @@ where
426427 return ( candidates, failed_candidate_info) ;
427428 }
428429
429- self . assemble_alias_bound_candidates ( goal, & mut candidates) ;
430- self . assemble_param_env_candidates ( goal, & mut candidates, & mut failed_candidate_info) ;
431-
432430 match assemble_from {
433431 AssembleCandidatesFrom :: All => {
432+ self . assemble_alias_bound_candidates ( goal, & mut candidates) ;
433+ self . assemble_param_env_candidates (
434+ goal,
435+ & mut candidates,
436+ & mut failed_candidate_info,
437+ ) ;
434438 self . assemble_builtin_impl_candidates ( goal, & mut candidates) ;
435439 // For performance we only assemble impls if there are no candidates
436440 // which would shadow them. This is necessary to avoid hangs in rayon,
@@ -457,6 +461,12 @@ where
457461 }
458462 }
459463 AssembleCandidatesFrom :: EnvAndBounds => {
464+ self . assemble_alias_bound_candidates ( goal, & mut candidates) ;
465+ self . assemble_param_env_candidates (
466+ goal,
467+ & mut candidates,
468+ & mut failed_candidate_info,
469+ ) ;
460470 // This is somewhat inconsistent and may make #57893 slightly easier to exploit.
461471 // However, it matches the behavior of the old solver. See
462472 // `tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs`.
@@ -466,6 +476,10 @@ where
466476 self . assemble_object_bound_candidates ( goal, & mut candidates) ;
467477 }
468478 }
479+ AssembleCandidatesFrom :: Impl => {
480+ self . assemble_builtin_impl_candidates ( goal, & mut candidates) ;
481+ self . assemble_impl_candidates ( goal, & mut candidates) ;
482+ }
469483 }
470484
471485 ( candidates, failed_candidate_info)
@@ -1097,112 +1111,6 @@ where
10971111 }
10981112 }
10991113
1100- /// Assemble and merge candidates for goals which are related to an underlying trait
1101- /// goal. Right now, this is normalizes-to and host effect goals.
1102- ///
1103- /// We sadly can't simply take all possible candidates for normalization goals
1104- /// and check whether they result in the same constraints. We want to make sure
1105- /// that trying to normalize an alias doesn't result in constraints which aren't
1106- /// otherwise required.
1107- ///
1108- /// Most notably, when proving a trait goal by via a where-bound, we should not
1109- /// normalize via impls which have stricter region constraints than the where-bound:
1110- ///
1111- /// ```rust
1112- /// trait Trait<'a> {
1113- /// type Assoc;
1114- /// }
1115- ///
1116- /// impl<'a, T: 'a> Trait<'a> for T {
1117- /// type Assoc = u32;
1118- /// }
1119- ///
1120- /// fn with_bound<'a, T: Trait<'a>>(_value: T::Assoc) {}
1121- /// ```
1122- ///
1123- /// The where-bound of `with_bound` doesn't specify the associated type, so we would
1124- /// only be able to normalize `<T as Trait<'a>>::Assoc` by using the impl. This impl
1125- /// adds a `T: 'a` bound however, which would result in a region error. Given that the
1126- /// user explicitly wrote that `T: Trait<'a>` holds, this is undesirable and we instead
1127- /// treat the alias as rigid.
1128- ///
1129- /// See trait-system-refactor-initiative#124 for more details.
1130- #[ instrument( level = "debug" , skip_all, fields( proven_via, goal) , ret) ]
1131- pub ( super ) fn assemble_and_merge_candidates < G : GoalKind < D > > (
1132- & mut self ,
1133- proven_via : Option < TraitGoalProvenVia > ,
1134- goal : Goal < I , G > ,
1135- inject_forced_ambiguity_candidate : impl FnOnce ( & mut EvalCtxt < ' _ , D > ) -> Option < QueryResult < I > > ,
1136- inject_normalize_to_rigid_candidate : impl FnOnce ( & mut EvalCtxt < ' _ , D > ) -> QueryResult < I > ,
1137- ) -> QueryResult < I > {
1138- let Some ( proven_via) = proven_via else {
1139- // We don't care about overflow. If proving the trait goal overflowed, then
1140- // it's enough to report an overflow error for that, we don't also have to
1141- // overflow during normalization.
1142- //
1143- // We use `forced_ambiguity` here over `make_ambiguous_response_no_constraints`
1144- // because the former will also record a built-in candidate in the inspector.
1145- return self . forced_ambiguity ( MaybeCause :: Ambiguity ) . map ( |cand| cand. result ) ;
1146- } ;
1147-
1148- match proven_via {
1149- TraitGoalProvenVia :: ParamEnv | TraitGoalProvenVia :: AliasBound => {
1150- // Even when a trait bound has been proven using a where-bound, we
1151- // still need to consider alias-bounds for normalization, see
1152- // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
1153- let ( mut candidates, _) = self
1154- . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: EnvAndBounds ) ;
1155- debug ! ( ?candidates) ;
1156-
1157- // If the trait goal has been proven by using the environment, we want to treat
1158- // aliases as rigid if there are no applicable projection bounds in the environment.
1159- if candidates. is_empty ( ) {
1160- return inject_normalize_to_rigid_candidate ( self ) ;
1161- }
1162-
1163- // If we're normalizing an GAT, we bail if using a where-bound would constrain
1164- // its generic arguments.
1165- if let Some ( result) = inject_forced_ambiguity_candidate ( self ) {
1166- return result;
1167- }
1168-
1169- // We still need to prefer where-bounds over alias-bounds however.
1170- // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
1171- if candidates. iter ( ) . any ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) {
1172- candidates. retain ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) ;
1173- }
1174-
1175- if let Some ( ( response, _) ) = self . try_merge_candidates ( & candidates) {
1176- Ok ( response)
1177- } else {
1178- self . flounder ( & candidates)
1179- }
1180- }
1181- TraitGoalProvenVia :: Misc => {
1182- let ( mut candidates, _) =
1183- self . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: All ) ;
1184-
1185- // Prefer "orphaned" param-env normalization predicates, which are used
1186- // (for example, and ideally only) when proving item bounds for an impl.
1187- if candidates. iter ( ) . any ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) {
1188- candidates. retain ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) ;
1189- }
1190-
1191- // We drop specialized impls to allow normalization via a final impl here. In case
1192- // the specializing impl has different inference constraints from the specialized
1193- // impl, proving the trait goal is already ambiguous, so we never get here. This
1194- // means we can just ignore inference constraints and don't have to special-case
1195- // constraining the normalized-to `term`.
1196- self . filter_specialized_impls ( AllowInferenceConstraints :: Yes , & mut candidates) ;
1197- if let Some ( ( response, _) ) = self . try_merge_candidates ( & candidates) {
1198- Ok ( response)
1199- } else {
1200- self . flounder ( & candidates)
1201- }
1202- }
1203- }
1204- }
1205-
12061114 /// Compute whether a param-env assumption is global or non-global after normalizing it.
12071115 ///
12081116 /// This is necessary because, for example, given:
0 commit comments