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