mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Move winnowing to assembly
This commit is contained in:
parent
8987e68247
commit
654f43f34e
@ -3,7 +3,7 @@
|
|||||||
use super::infcx_ext::InferCtxtExt;
|
use super::infcx_ext::InferCtxtExt;
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use super::trait_goals::structural_traits::*;
|
use super::trait_goals::structural_traits::*;
|
||||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_infer::traits::util::elaborate_predicates;
|
use rustc_infer::traits::util::elaborate_predicates;
|
||||||
@ -459,4 +459,78 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
|
pub(super) fn merge_candidates_and_discard_reservation_impls(
|
||||||
|
&mut self,
|
||||||
|
mut candidates: Vec<Candidate<'tcx>>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
match candidates.len() {
|
||||||
|
0 => return Err(NoSolution),
|
||||||
|
1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if candidates.len() > 1 {
|
||||||
|
let mut i = 0;
|
||||||
|
'outer: while i < candidates.len() {
|
||||||
|
for j in (0..candidates.len()).filter(|&j| i != j) {
|
||||||
|
if self.trait_candidate_should_be_dropped_in_favor_of(
|
||||||
|
&candidates[i],
|
||||||
|
&candidates[j],
|
||||||
|
) {
|
||||||
|
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
|
||||||
|
candidates.swap_remove(i);
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are *STILL* multiple candidates, give up
|
||||||
|
// and report ambiguity.
|
||||||
|
if candidates.len() > 1 {
|
||||||
|
let certainty = if candidates.iter().all(|x| {
|
||||||
|
matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow))
|
||||||
|
}) {
|
||||||
|
Certainty::Maybe(MaybeCause::Overflow)
|
||||||
|
} else {
|
||||||
|
Certainty::AMBIGUOUS
|
||||||
|
};
|
||||||
|
return self.make_canonical_response(certainty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_candidate_should_be_dropped_in_favor_of(
|
||||||
|
&self,
|
||||||
|
candidate: &Candidate<'tcx>,
|
||||||
|
other: &Candidate<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
// FIXME: implement this
|
||||||
|
match (candidate.source, other.source) {
|
||||||
|
(CandidateSource::Impl(_), _)
|
||||||
|
| (CandidateSource::ParamEnv(_), _)
|
||||||
|
| (CandidateSource::AliasBound, _)
|
||||||
|
| (CandidateSource::BuiltinImpl, _) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
|
||||||
|
if let CandidateSource::Impl(def_id) = candidate.source {
|
||||||
|
if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
|
||||||
|
debug!("Selected reservation impl");
|
||||||
|
// We assemble all candidates inside of a probe so by
|
||||||
|
// making a new canonical response here our result will
|
||||||
|
// have no constraints.
|
||||||
|
candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
candidate
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::traits::{specialization_graph, translate_substs};
|
use crate::traits::{specialization_graph, translate_substs};
|
||||||
|
|
||||||
use super::assembly::{self, Candidate, CandidateSource};
|
use super::assembly;
|
||||||
use super::infcx_ext::InferCtxtExt;
|
use super::infcx_ext::InferCtxtExt;
|
||||||
use super::trait_goals::structural_traits;
|
use super::trait_goals::structural_traits;
|
||||||
use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// projection cache in the solver.
|
// projection cache in the solver.
|
||||||
if self.term_is_fully_unconstrained(goal) {
|
if self.term_is_fully_unconstrained(goal) {
|
||||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||||
self.merge_project_candidates(candidates)
|
self.merge_candidates_and_discard_reservation_impls(candidates)
|
||||||
} else {
|
} else {
|
||||||
let predicate = goal.predicate;
|
let predicate = goal.predicate;
|
||||||
let unconstrained_rhs = match predicate.term.unpack() {
|
let unconstrained_rhs = match predicate.term.unpack() {
|
||||||
@ -153,65 +153,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
|
|
||||||
self.make_canonical_response(normalization_certainty.unify_and(rhs_certainty))
|
self.make_canonical_response(normalization_certainty.unify_and(rhs_certainty))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_project_candidates(
|
|
||||||
&mut self,
|
|
||||||
mut candidates: Vec<Candidate<'tcx>>,
|
|
||||||
) -> QueryResult<'tcx> {
|
|
||||||
match candidates.len() {
|
|
||||||
0 => return Err(NoSolution),
|
|
||||||
1 => return Ok(candidates.pop().unwrap().result),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidates.len() > 1 {
|
|
||||||
let mut i = 0;
|
|
||||||
'outer: while i < candidates.len() {
|
|
||||||
for j in (0..candidates.len()).filter(|&j| i != j) {
|
|
||||||
if self.project_candidate_should_be_dropped_in_favor_of(
|
|
||||||
&candidates[i],
|
|
||||||
&candidates[j],
|
|
||||||
) {
|
|
||||||
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
|
|
||||||
candidates.swap_remove(i);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
|
|
||||||
// If there are *STILL* multiple candidates, give up
|
|
||||||
// and report ambiguity.
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidates.len() > 1 {
|
|
||||||
let certainty = if candidates.iter().all(|x| {
|
|
||||||
matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow))
|
|
||||||
}) {
|
|
||||||
Certainty::Maybe(MaybeCause::Overflow)
|
|
||||||
} else {
|
|
||||||
Certainty::AMBIGUOUS
|
|
||||||
};
|
|
||||||
return self.make_canonical_response(certainty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(candidates.pop().unwrap().result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn project_candidate_should_be_dropped_in_favor_of(
|
|
||||||
&self,
|
|
||||||
candidate: &Candidate<'tcx>,
|
|
||||||
other: &Candidate<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
// FIXME: implement this
|
|
||||||
match (candidate.source, other.source) {
|
|
||||||
(CandidateSource::Impl(_), _)
|
|
||||||
| (CandidateSource::ParamEnv(_), _)
|
|
||||||
| (CandidateSource::BuiltinImpl, _)
|
|
||||||
| (CandidateSource::AliasBound, _) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use super::assembly::{self, Candidate, CandidateSource};
|
use super::assembly;
|
||||||
use super::infcx_ext::InferCtxtExt;
|
use super::infcx_ext::InferCtxtExt;
|
||||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
@ -479,80 +479,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||||
self.merge_trait_candidates_discard_reservation_impls(candidates)
|
self.merge_candidates_and_discard_reservation_impls(candidates)
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self), ret)]
|
|
||||||
pub(super) fn merge_trait_candidates_discard_reservation_impls(
|
|
||||||
&mut self,
|
|
||||||
mut candidates: Vec<Candidate<'tcx>>,
|
|
||||||
) -> QueryResult<'tcx> {
|
|
||||||
match candidates.len() {
|
|
||||||
0 => return Err(NoSolution),
|
|
||||||
1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidates.len() > 1 {
|
|
||||||
let mut i = 0;
|
|
||||||
'outer: while i < candidates.len() {
|
|
||||||
for j in (0..candidates.len()).filter(|&j| i != j) {
|
|
||||||
if self.trait_candidate_should_be_dropped_in_favor_of(
|
|
||||||
&candidates[i],
|
|
||||||
&candidates[j],
|
|
||||||
) {
|
|
||||||
debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
|
|
||||||
candidates.swap_remove(i);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
|
|
||||||
// If there are *STILL* multiple candidates, give up
|
|
||||||
// and report ambiguity.
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidates.len() > 1 {
|
|
||||||
let certainty = if candidates.iter().all(|x| {
|
|
||||||
matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow))
|
|
||||||
}) {
|
|
||||||
Certainty::Maybe(MaybeCause::Overflow)
|
|
||||||
} else {
|
|
||||||
Certainty::AMBIGUOUS
|
|
||||||
};
|
|
||||||
return self.make_canonical_response(certainty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trait_candidate_should_be_dropped_in_favor_of(
|
|
||||||
&self,
|
|
||||||
candidate: &Candidate<'tcx>,
|
|
||||||
other: &Candidate<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
// FIXME: implement this
|
|
||||||
match (candidate.source, other.source) {
|
|
||||||
(CandidateSource::Impl(_), _)
|
|
||||||
| (CandidateSource::ParamEnv(_), _)
|
|
||||||
| (CandidateSource::AliasBound, _)
|
|
||||||
| (CandidateSource::BuiltinImpl, _) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn discard_reservation_impl(&self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> {
|
|
||||||
if let CandidateSource::Impl(def_id) = candidate.source {
|
|
||||||
if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
|
|
||||||
debug!("Selected reservation impl");
|
|
||||||
// We assemble all candidates inside of a probe so by
|
|
||||||
// making a new canonical response here our result will
|
|
||||||
// have no constraints.
|
|
||||||
candidate.result = self.make_canonical_response(Certainty::AMBIGUOUS).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
candidate
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user