Auto merge of #149533 - adwinwhite:skip-trait-goal-if-possible, r= · rust-lang/rust@405e127 (original) (raw)
`@@ -17,7 +17,6 @@ use rustc_type_ir::{
`
17
17
`};
`
18
18
`use tracing::{debug, instrument};
`
19
19
``
20
``
`-
use super::trait_goals::TraitGoalProvenVia;
`
21
20
`use super::{has_only_region_constraints, inspect};
`
22
21
`use crate::delegate::SolverDelegate;
`
23
22
`use crate::solve::inspect::ProbeKind;
`
`@@ -363,13 +362,15 @@ pub(super) enum AssembleCandidatesFrom {
`
363
362
`` /// user-written and built-in impls. We only expect ParamEnv and AliasBound
``
364
363
`/// candidates to be assembled.
`
365
364
`EnvAndBounds,
`
``
365
`+
Impl,
`
366
366
`}
`
367
367
``
368
368
`impl AssembleCandidatesFrom {
`
369
369
`fn should_assemble_impl_candidates(&self) -> bool {
`
370
370
`match self {
`
371
371
`AssembleCandidatesFrom::All => true,
`
372
372
`AssembleCandidatesFrom::EnvAndBounds => false,
`
``
373
`+
AssembleCandidatesFrom::Impl => true,
`
373
374
`}
`
374
375
`}
`
375
376
`}
`
`@@ -426,11 +427,14 @@ where
`
426
427
`return (candidates, failed_candidate_info);
`
427
428
`}
`
428
429
``
429
``
`-
self.assemble_alias_bound_candidates(goal, &mut candidates);
`
430
``
`-
self.assemble_param_env_candidates(goal, &mut candidates, &mut failed_candidate_info);
`
431
``
-
432
430
`match assemble_from {
`
433
431
`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
`+
);
`
434
438
`self.assemble_builtin_impl_candidates(goal, &mut candidates);
`
435
439
`// For performance we only assemble impls if there are no candidates
`
436
440
`// which would shadow them. This is necessary to avoid hangs in rayon,
`
`@@ -457,6 +461,12 @@ where
`
457
461
`}
`
458
462
`}
`
459
463
`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
`+
);
`
460
470
`// This is somewhat inconsistent and may make #57893 slightly easier to exploit.
`
461
471
`// However, it matches the behavior of the old solver. See
`
462
472
`` // tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs.
``
`@@ -466,6 +476,10 @@ where
`
466
476
`self.assemble_object_bound_candidates(goal, &mut candidates);
`
467
477
`}
`
468
478
`}
`
``
479
`+
AssembleCandidatesFrom::Impl => {
`
``
480
`+
self.assemble_builtin_impl_candidates(goal, &mut candidates);
`
``
481
`+
self.assemble_impl_candidates(goal, &mut candidates);
`
``
482
`+
}
`
469
483
`}
`
470
484
``
471
485
`(candidates, failed_candidate_info)
`
`@@ -1097,112 +1111,6 @@ where
`
1097
1111
`}
`
1098
1112
`}
`
1099
1113
``
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>(
`
1132
``
`-
&mut self,
`
1133
``
`-
proven_via: Option,
`
1134
``
`-
goal: Goal<I, G>,
`
1135
``
`-
inject_forced_ambiguity_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> Option<QueryResult>,
`
1136
``
`-
inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult,
`
1137
``
`-
) -> QueryResult {
`
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
``
-
1206
1114
`/// Compute whether a param-env assumption is global or non-global after normalizing it.
`
1207
1115
`///
`
1208
1116
`/// This is necessary because, for example, given:
`