Skip to content

Commit 937c1cc

Browse files
committed
we only merge candiates for trait and normalizes-to goals
1 parent e1b9081 commit 937c1cc

File tree

3 files changed

+48
-69
lines changed

3 files changed

+48
-69
lines changed

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -959,36 +959,23 @@ where
959959
// Even when a trait bound has been proven using a where-bound, we
960960
// still need to consider alias-bounds for normalization, see
961961
// `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
962-
let candidates_from_env_and_bounds: Vec<_> = self
962+
let mut candidates: Vec<_> = self
963963
.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
964964

965965
// We still need to prefer where-bounds over alias-bounds however.
966966
// See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
967-
let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds
968-
.iter()
969-
.any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
970-
{
971-
candidates_from_env_and_bounds
972-
.into_iter()
973-
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
974-
.map(|c| c.result)
975-
.collect()
976-
} else {
977-
candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect()
978-
};
979-
980-
// If the trait goal has been proven by using the environment, we want to treat
981-
// aliases as rigid if there are no applicable projection bounds in the environment.
982-
if considered_candidates.is_empty() {
983-
if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
984-
considered_candidates.push(response);
985-
}
967+
if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
968+
candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
969+
} else if candidates.is_empty() {
970+
// If the trait goal has been proven by using the environment, we want to treat
971+
// aliases as rigid if there are no applicable projection bounds in the environment.
972+
return inject_normalize_to_rigid_candidate(self);
986973
}
987974

988-
if let Some(response) = self.try_merge_responses(&considered_candidates) {
975+
if let Some(response) = self.try_merge_candidates(&candidates) {
989976
Ok(response)
990977
} else {
991-
self.flounder(&considered_candidates)
978+
self.flounder(&candidates)
992979
}
993980
}
994981
TraitGoalProvenVia::Misc => {
@@ -998,11 +985,9 @@ where
998985
// Prefer "orphaned" param-env normalization predicates, which are used
999986
// (for example, and ideally only) when proving item bounds for an impl.
1000987
let candidates_from_env: Vec<_> = candidates
1001-
.iter()
1002-
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
1003-
.map(|c| c.result)
988+
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
1004989
.collect();
1005-
if let Some(response) = self.try_merge_responses(&candidates_from_env) {
990+
if let Some(response) = self.try_merge_candidates(&candidates_from_env) {
1006991
return Ok(response);
1007992
}
1008993

@@ -1012,12 +997,10 @@ where
1012997
// means we can just ignore inference constraints and don't have to special-case
1013998
// constraining the normalized-to `term`.
1014999
self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
1015-
1016-
let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
1017-
if let Some(response) = self.try_merge_responses(&responses) {
1000+
if let Some(response) = self.try_merge_candidates(&candidates) {
10181001
Ok(response)
10191002
} else {
1020-
self.flounder(&responses)
1003+
self.flounder(&candidates)
10211004
}
10221005
}
10231006
}

compiler/rustc_next_trait_solver/src/solve/mod.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use tracing::instrument;
2929

3030
pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
3131
use crate::delegate::SolverDelegate;
32+
use crate::solve::assembly::Candidate;
3233

3334
/// How many fixpoint iterations we should attempt inside of the solver before bailing
3435
/// with overflow.
@@ -244,50 +245,51 @@ where
244245
///
245246
/// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
246247
#[instrument(level = "trace", skip(self), ret)]
247-
fn try_merge_responses(
248+
fn try_merge_candidates(
248249
&mut self,
249-
responses: &[CanonicalResponse<I>],
250+
candidates: &[Candidate<I>],
250251
) -> Option<CanonicalResponse<I>> {
251-
if responses.is_empty() {
252+
if candidates.is_empty() {
252253
return None;
253254
}
254255

255-
let one = responses[0];
256-
if responses[1..].iter().all(|&resp| resp == one) {
256+
let one: CanonicalResponse<I> = candidates[0].result;
257+
if candidates[1..].iter().all(|candidate| candidate.result == one) {
257258
return Some(one);
258259
}
259260

260-
responses
261+
candidates
261262
.iter()
262-
.find(|response| {
263-
response.value.certainty == Certainty::Yes
264-
&& has_no_inference_or_external_constraints(**response)
263+
.find(|candidate| {
264+
candidate.result.value.certainty == Certainty::Yes
265+
&& has_no_inference_or_external_constraints(candidate.result)
265266
})
266-
.copied()
267+
.map(|candidate| candidate.result)
267268
}
268269

269-
fn bail_with_ambiguity(&mut self, responses: &[CanonicalResponse<I>]) -> CanonicalResponse<I> {
270-
debug_assert!(responses.len() > 1);
271-
let maybe_cause = responses.iter().fold(MaybeCause::Ambiguity, |maybe_cause, response| {
272-
// Pull down the certainty of `Certainty::Yes` to ambiguity when combining
273-
// these responses, b/c we're combining more than one response and this we
274-
// don't know which one applies.
275-
let candidate = match response.value.certainty {
276-
Certainty::Yes => MaybeCause::Ambiguity,
277-
Certainty::Maybe(candidate) => candidate,
278-
};
279-
maybe_cause.or(candidate)
280-
});
270+
fn bail_with_ambiguity(&mut self, candidates: &[Candidate<I>]) -> CanonicalResponse<I> {
271+
debug_assert!(candidates.len() > 1);
272+
let maybe_cause =
273+
candidates.iter().fold(MaybeCause::Ambiguity, |maybe_cause, candidates| {
274+
// Pull down the certainty of `Certainty::Yes` to ambiguity when combining
275+
// these responses, b/c we're combining more than one response and this we
276+
// don't know which one applies.
277+
let candidate = match candidates.result.value.certainty {
278+
Certainty::Yes => MaybeCause::Ambiguity,
279+
Certainty::Maybe(candidate) => candidate,
280+
};
281+
maybe_cause.or(candidate)
282+
});
281283
self.make_ambiguous_response_no_constraints(maybe_cause)
282284
}
283285

284286
/// If we fail to merge responses we flounder and return overflow or ambiguity.
285287
#[instrument(level = "trace", skip(self), ret)]
286-
fn flounder(&mut self, responses: &[CanonicalResponse<I>]) -> QueryResult<I> {
287-
if responses.is_empty() {
288+
fn flounder(&mut self, candidates: &[Candidate<I>]) -> QueryResult<I> {
289+
if candidates.is_empty() {
288290
return Err(NoSolution);
289291
} else {
290-
Ok(self.bail_with_ambiguity(responses))
292+
Ok(self.bail_with_ambiguity(candidates))
291293
}
292294
}
293295

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,11 +1346,10 @@ where
13461346
mut candidates: Vec<Candidate<I>>,
13471347
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
13481348
if let TypingMode::Coherence = self.typing_mode() {
1349-
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1350-
return if let Some(response) = self.try_merge_responses(&all_candidates) {
1349+
return if let Some(response) = self.try_merge_candidates(&candidates) {
13511350
Ok((response, Some(TraitGoalProvenVia::Misc)))
13521351
} else {
1353-
self.flounder(&all_candidates).map(|r| (r, None))
1352+
self.flounder(&candidates).map(|r| (r, None))
13541353
};
13551354
}
13561355

@@ -1375,11 +1374,9 @@ where
13751374
.any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
13761375
if has_non_global_where_bounds {
13771376
let where_bounds: Vec<_> = candidates
1378-
.iter()
1379-
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
1380-
.map(|c| c.result)
1377+
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
13811378
.collect();
1382-
return if let Some(response) = self.try_merge_responses(&where_bounds) {
1379+
return if let Some(response) = self.try_merge_candidates(&where_bounds) {
13831380
Ok((response, Some(TraitGoalProvenVia::ParamEnv)))
13841381
} else {
13851382
Ok((self.bail_with_ambiguity(&where_bounds), None))
@@ -1388,11 +1385,9 @@ where
13881385

13891386
if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
13901387
let alias_bounds: Vec<_> = candidates
1391-
.iter()
1392-
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
1393-
.map(|c| c.result)
1388+
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound))
13941389
.collect();
1395-
return if let Some(response) = self.try_merge_responses(&alias_bounds) {
1390+
return if let Some(response) = self.try_merge_candidates(&alias_bounds) {
13961391
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
13971392
} else {
13981393
Ok((self.bail_with_ambiguity(&alias_bounds), None))
@@ -1417,11 +1412,10 @@ where
14171412
TraitGoalProvenVia::Misc
14181413
};
14191414

1420-
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
1421-
if let Some(response) = self.try_merge_responses(&all_candidates) {
1415+
if let Some(response) = self.try_merge_candidates(&candidates) {
14221416
Ok((response, Some(proven_via)))
14231417
} else {
1424-
self.flounder(&all_candidates).map(|r| (r, None))
1418+
self.flounder(&candidates).map(|r| (r, None))
14251419
}
14261420
}
14271421

0 commit comments

Comments
 (0)