Rollup merge of #144948 - lcnr:change-candidate-handling, r=compiler-errors
we only merge candidates for trait and normalizes-to goals so change `fn try_merge_responses` to `fn try_merge_candidates` and just use candidates everywhere. Potentially slightly faster than the alternative :3 r? ``@compiler-errors`` ``@BoxyUwU``
This commit is contained in:
commit
f7520353ab
3 changed files with 48 additions and 69 deletions
|
|
@ -959,36 +959,23 @@ where
|
|||
// Even when a trait bound has been proven using a where-bound, we
|
||||
// still need to consider alias-bounds for normalization, see
|
||||
// `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
|
||||
let candidates_from_env_and_bounds: Vec<_> = self
|
||||
let mut candidates: Vec<_> = self
|
||||
.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
|
||||
|
||||
// We still need to prefer where-bounds over alias-bounds however.
|
||||
// See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
|
||||
let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds
|
||||
.iter()
|
||||
.any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
{
|
||||
candidates_from_env_and_bounds
|
||||
.into_iter()
|
||||
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.map(|c| c.result)
|
||||
.collect()
|
||||
} else {
|
||||
candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect()
|
||||
};
|
||||
|
||||
// If the trait goal has been proven by using the environment, we want to treat
|
||||
// aliases as rigid if there are no applicable projection bounds in the environment.
|
||||
if considered_candidates.is_empty() {
|
||||
if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
|
||||
considered_candidates.push(response);
|
||||
}
|
||||
if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
|
||||
candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
|
||||
} else if candidates.is_empty() {
|
||||
// If the trait goal has been proven by using the environment, we want to treat
|
||||
// aliases as rigid if there are no applicable projection bounds in the environment.
|
||||
return inject_normalize_to_rigid_candidate(self);
|
||||
}
|
||||
|
||||
if let Some(response) = self.try_merge_responses(&considered_candidates) {
|
||||
if let Some(response) = self.try_merge_candidates(&candidates) {
|
||||
Ok(response)
|
||||
} else {
|
||||
self.flounder(&considered_candidates)
|
||||
self.flounder(&candidates)
|
||||
}
|
||||
}
|
||||
TraitGoalProvenVia::Misc => {
|
||||
|
|
@ -998,11 +985,9 @@ where
|
|||
// Prefer "orphaned" param-env normalization predicates, which are used
|
||||
// (for example, and ideally only) when proving item bounds for an impl.
|
||||
let candidates_from_env: Vec<_> = candidates
|
||||
.iter()
|
||||
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.map(|c| c.result)
|
||||
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.collect();
|
||||
if let Some(response) = self.try_merge_responses(&candidates_from_env) {
|
||||
if let Some(response) = self.try_merge_candidates(&candidates_from_env) {
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
|
|
@ -1012,12 +997,10 @@ where
|
|||
// means we can just ignore inference constraints and don't have to special-case
|
||||
// constraining the normalized-to `term`.
|
||||
self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
|
||||
|
||||
let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
|
||||
if let Some(response) = self.try_merge_responses(&responses) {
|
||||
if let Some(response) = self.try_merge_candidates(&candidates) {
|
||||
Ok(response)
|
||||
} else {
|
||||
self.flounder(&responses)
|
||||
self.flounder(&candidates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use tracing::instrument;
|
|||
|
||||
pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
|
||||
use crate::delegate::SolverDelegate;
|
||||
use crate::solve::assembly::Candidate;
|
||||
|
||||
/// How many fixpoint iterations we should attempt inside of the solver before bailing
|
||||
/// with overflow.
|
||||
|
|
@ -244,50 +245,51 @@ where
|
|||
///
|
||||
/// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn try_merge_responses(
|
||||
fn try_merge_candidates(
|
||||
&mut self,
|
||||
responses: &[CanonicalResponse<I>],
|
||||
candidates: &[Candidate<I>],
|
||||
) -> Option<CanonicalResponse<I>> {
|
||||
if responses.is_empty() {
|
||||
if candidates.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let one = responses[0];
|
||||
if responses[1..].iter().all(|&resp| resp == one) {
|
||||
let one: CanonicalResponse<I> = candidates[0].result;
|
||||
if candidates[1..].iter().all(|candidate| candidate.result == one) {
|
||||
return Some(one);
|
||||
}
|
||||
|
||||
responses
|
||||
candidates
|
||||
.iter()
|
||||
.find(|response| {
|
||||
response.value.certainty == Certainty::Yes
|
||||
&& has_no_inference_or_external_constraints(**response)
|
||||
.find(|candidate| {
|
||||
candidate.result.value.certainty == Certainty::Yes
|
||||
&& has_no_inference_or_external_constraints(candidate.result)
|
||||
})
|
||||
.copied()
|
||||
.map(|candidate| candidate.result)
|
||||
}
|
||||
|
||||
fn bail_with_ambiguity(&mut self, responses: &[CanonicalResponse<I>]) -> CanonicalResponse<I> {
|
||||
debug_assert!(responses.len() > 1);
|
||||
let maybe_cause = responses.iter().fold(MaybeCause::Ambiguity, |maybe_cause, response| {
|
||||
// Pull down the certainty of `Certainty::Yes` to ambiguity when combining
|
||||
// these responses, b/c we're combining more than one response and this we
|
||||
// don't know which one applies.
|
||||
let candidate = match response.value.certainty {
|
||||
Certainty::Yes => MaybeCause::Ambiguity,
|
||||
Certainty::Maybe(candidate) => candidate,
|
||||
};
|
||||
maybe_cause.or(candidate)
|
||||
});
|
||||
fn bail_with_ambiguity(&mut self, candidates: &[Candidate<I>]) -> CanonicalResponse<I> {
|
||||
debug_assert!(candidates.len() > 1);
|
||||
let maybe_cause =
|
||||
candidates.iter().fold(MaybeCause::Ambiguity, |maybe_cause, candidates| {
|
||||
// Pull down the certainty of `Certainty::Yes` to ambiguity when combining
|
||||
// these responses, b/c we're combining more than one response and this we
|
||||
// don't know which one applies.
|
||||
let candidate = match candidates.result.value.certainty {
|
||||
Certainty::Yes => MaybeCause::Ambiguity,
|
||||
Certainty::Maybe(candidate) => candidate,
|
||||
};
|
||||
maybe_cause.or(candidate)
|
||||
});
|
||||
self.make_ambiguous_response_no_constraints(maybe_cause)
|
||||
}
|
||||
|
||||
/// If we fail to merge responses we flounder and return overflow or ambiguity.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn flounder(&mut self, responses: &[CanonicalResponse<I>]) -> QueryResult<I> {
|
||||
if responses.is_empty() {
|
||||
fn flounder(&mut self, candidates: &[Candidate<I>]) -> QueryResult<I> {
|
||||
if candidates.is_empty() {
|
||||
return Err(NoSolution);
|
||||
} else {
|
||||
Ok(self.bail_with_ambiguity(responses))
|
||||
Ok(self.bail_with_ambiguity(candidates))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1346,11 +1346,10 @@ where
|
|||
mut candidates: Vec<Candidate<I>>,
|
||||
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
|
||||
if let TypingMode::Coherence = self.typing_mode() {
|
||||
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
|
||||
return if let Some(response) = self.try_merge_responses(&all_candidates) {
|
||||
return if let Some(response) = self.try_merge_candidates(&candidates) {
|
||||
Ok((response, Some(TraitGoalProvenVia::Misc)))
|
||||
} else {
|
||||
self.flounder(&all_candidates).map(|r| (r, None))
|
||||
self.flounder(&candidates).map(|r| (r, None))
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1375,11 +1374,9 @@ where
|
|||
.any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
|
||||
if has_non_global_where_bounds {
|
||||
let where_bounds: Vec<_> = candidates
|
||||
.iter()
|
||||
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.map(|c| c.result)
|
||||
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.collect();
|
||||
return if let Some(response) = self.try_merge_responses(&where_bounds) {
|
||||
return if let Some(response) = self.try_merge_candidates(&where_bounds) {
|
||||
Ok((response, Some(TraitGoalProvenVia::ParamEnv)))
|
||||
} else {
|
||||
Ok((self.bail_with_ambiguity(&where_bounds), None))
|
||||
|
|
@ -1388,11 +1385,9 @@ where
|
|||
|
||||
if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
|
||||
let alias_bounds: Vec<_> = candidates
|
||||
.iter()
|
||||
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
|
||||
.map(|c| c.result)
|
||||
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound))
|
||||
.collect();
|
||||
return if let Some(response) = self.try_merge_responses(&alias_bounds) {
|
||||
return if let Some(response) = self.try_merge_candidates(&alias_bounds) {
|
||||
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
|
||||
} else {
|
||||
Ok((self.bail_with_ambiguity(&alias_bounds), None))
|
||||
|
|
@ -1417,11 +1412,10 @@ where
|
|||
TraitGoalProvenVia::Misc
|
||||
};
|
||||
|
||||
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
|
||||
if let Some(response) = self.try_merge_responses(&all_candidates) {
|
||||
if let Some(response) = self.try_merge_candidates(&candidates) {
|
||||
Ok((response, Some(proven_via)))
|
||||
} else {
|
||||
self.flounder(&all_candidates).map(|r| (r, None))
|
||||
self.flounder(&candidates).map(|r| (r, None))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue