Inline and remove process_predicate
.
Because it has a single callsite. This patch is large but trivial, doing the minimal amount of work (mostly `self.` insertions) necessary.
This commit is contained in:
parent
cdfd9ca088
commit
b18a22a384
@ -262,11 +262,261 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
||||
type Obligation = PendingPredicateObligation<'tcx>;
|
||||
type Error = FulfillmentErrorCode<'tcx>;
|
||||
|
||||
/// Processes a predicate obligation and returns either:
|
||||
/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true
|
||||
/// - `Ok(None)` if we don't have enough info to be sure
|
||||
/// - `Err` if the predicate does not hold
|
||||
fn process_obligation(&mut self,
|
||||
obligation: &mut Self::Obligation)
|
||||
pending_obligation: &mut Self::Obligation)
|
||||
-> Result<Option<Vec<Self::Obligation>>, Self::Error>
|
||||
{
|
||||
process_predicate(self.selcx, obligation, self.register_region_obligations)
|
||||
// if we were stalled on some unresolved variables, first check
|
||||
// whether any of them have been resolved; if not, don't bother
|
||||
// doing more work yet
|
||||
if !pending_obligation.stalled_on.is_empty() {
|
||||
if pending_obligation.stalled_on.iter().all(|&ty| {
|
||||
let resolved_ty = self.selcx.infcx().shallow_resolve(&ty);
|
||||
resolved_ty == ty // nothing changed here
|
||||
}) {
|
||||
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
|
||||
self.selcx.infcx()
|
||||
.resolve_type_vars_if_possible(&pending_obligation.obligation),
|
||||
pending_obligation.stalled_on);
|
||||
return Ok(None);
|
||||
}
|
||||
pending_obligation.stalled_on = vec![];
|
||||
}
|
||||
|
||||
let obligation = &mut pending_obligation.obligation;
|
||||
|
||||
if obligation.predicate.has_infer_types() {
|
||||
obligation.predicate =
|
||||
self.selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate);
|
||||
}
|
||||
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let trait_obligation = obligation.with(data.clone());
|
||||
|
||||
if data.is_global() && !data.has_late_bound_regions() {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
if self.selcx.infcx().predicate_must_hold(&obligation) {
|
||||
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
|
||||
data, obligation.recursion_depth);
|
||||
return Ok(Some(vec![]))
|
||||
}
|
||||
}
|
||||
|
||||
match self.selcx.select(&trait_obligation) {
|
||||
Ok(Some(vtable)) => {
|
||||
debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)",
|
||||
data, obligation.recursion_depth);
|
||||
Ok(Some(mk_pending(vtable.nested_obligations())))
|
||||
}
|
||||
Ok(None) => {
|
||||
debug!("selecting trait `{:?}` at depth {} yielded Ok(None)",
|
||||
data, obligation.recursion_depth);
|
||||
|
||||
// This is a bit subtle: for the most part, the
|
||||
// only reason we can fail to make progress on
|
||||
// trait selection is because we don't have enough
|
||||
// information about the types in the trait. One
|
||||
// exception is that we sometimes haven't decided
|
||||
// what kind of closure a closure is. *But*, in
|
||||
// that case, it turns out, the type of the
|
||||
// closure will also change, because the closure
|
||||
// also includes references to its upvars as part
|
||||
// of its type, and those types are resolved at
|
||||
// the same time.
|
||||
//
|
||||
// FIXME(#32286) logic seems false if no upvars
|
||||
pending_obligation.stalled_on =
|
||||
trait_ref_type_vars(self.selcx, data.to_poly_trait_ref());
|
||||
|
||||
debug!("process_predicate: pending obligation {:?} now stalled on {:?}",
|
||||
self.selcx.infcx().resolve_type_vars_if_possible(obligation),
|
||||
pending_obligation.stalled_on);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Err(selection_err) => {
|
||||
info!("selecting trait `{:?}` at depth {} yielded Err",
|
||||
data, obligation.recursion_depth);
|
||||
|
||||
Err(CodeSelectionError(selection_err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
|
||||
Ok(()) => Ok(Some(Vec::new())),
|
||||
Err(_) => Err(CodeSelectionError(Unimplemented)),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(ref binder) => {
|
||||
// Check if there are higher-ranked regions.
|
||||
match binder.no_late_bound_regions() {
|
||||
// If there are, inspect the underlying type further.
|
||||
None => {
|
||||
// Convert from `Binder<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`.
|
||||
let binder = binder.map_bound_ref(|pred| pred.0);
|
||||
|
||||
// Check if the type has any bound regions.
|
||||
match binder.no_late_bound_regions() {
|
||||
// If so, this obligation is an error (for now). Eventually we should be
|
||||
// able to support additional cases here, like `for<'a> &'a str: 'a`.
|
||||
None => {
|
||||
Err(CodeSelectionError(Unimplemented))
|
||||
}
|
||||
// Otherwise, we have something of the form
|
||||
// `for<'a> T: 'a where 'a not in T`, which we can treat as
|
||||
// `T: 'static`.
|
||||
Some(t_a) => {
|
||||
let r_static = self.selcx.tcx().types.re_static;
|
||||
if self.register_region_obligations {
|
||||
self.selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_static,
|
||||
cause: obligation.cause.clone(),
|
||||
});
|
||||
}
|
||||
Ok(Some(vec![]))
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there aren't, register the obligation.
|
||||
Some(ty::OutlivesPredicate(t_a, r_b)) => {
|
||||
if self.register_region_obligations {
|
||||
self.selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_b,
|
||||
cause: obligation.cause.clone()
|
||||
});
|
||||
}
|
||||
Ok(Some(vec![]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
let project_obligation = obligation.with(data.clone());
|
||||
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
|
||||
Ok(None) => {
|
||||
let tcx = self.selcx.tcx();
|
||||
pending_obligation.stalled_on =
|
||||
trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx));
|
||||
Ok(None)
|
||||
}
|
||||
Ok(Some(os)) => Ok(Some(mk_pending(os))),
|
||||
Err(e) => Err(CodeProjectionError(e))
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
if !self.selcx.tcx().is_object_safe(trait_def_id) {
|
||||
Err(CodeSelectionError(Unimplemented))
|
||||
} else {
|
||||
Ok(Some(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
|
||||
match self.selcx.infcx().closure_kind(closure_def_id, closure_substs) {
|
||||
Some(closure_kind) => {
|
||||
if closure_kind.extends(kind) {
|
||||
Ok(Some(vec![]))
|
||||
} else {
|
||||
Err(CodeSelectionError(Unimplemented))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::WellFormed(ty) => {
|
||||
match ty::wf::obligations(self.selcx.infcx(),
|
||||
obligation.param_env,
|
||||
obligation.cause.body_id,
|
||||
ty, obligation.cause.span) {
|
||||
None => {
|
||||
pending_obligation.stalled_on = vec![ty];
|
||||
Ok(None)
|
||||
}
|
||||
Some(os) => Ok(Some(mk_pending(os)))
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Subtype(ref subtype) => {
|
||||
match self.selcx.infcx().subtype_predicate(&obligation.cause,
|
||||
obligation.param_env,
|
||||
subtype) {
|
||||
None => {
|
||||
// None means that both are unresolved.
|
||||
pending_obligation.stalled_on = vec![subtype.skip_binder().a,
|
||||
subtype.skip_binder().b];
|
||||
Ok(None)
|
||||
}
|
||||
Some(Ok(ok)) => {
|
||||
Ok(Some(mk_pending(ok.obligations)))
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected,
|
||||
subtype.skip_binder().a,
|
||||
subtype.skip_binder().b);
|
||||
Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
match self.selcx.tcx().lift_to_global(&obligation.param_env) {
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
Some(param_env) => {
|
||||
match self.selcx.tcx().lift_to_global(&substs) {
|
||||
Some(substs) => {
|
||||
let instance = ty::Instance::resolve(
|
||||
self.selcx.tcx().global_tcx(),
|
||||
param_env,
|
||||
def_id,
|
||||
substs,
|
||||
);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
match self.selcx.tcx().at(obligation.cause.span)
|
||||
.const_eval(param_env.and(cid)) {
|
||||
Ok(_) => Ok(Some(vec![])),
|
||||
Err(err) => Err(CodeSelectionError(ConstEvalFailure(err)))
|
||||
}
|
||||
} else {
|
||||
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
|
||||
span: obligation.cause.span,
|
||||
kind: ErrKind::CouldNotResolve.into(),
|
||||
})))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
pending_obligation.stalled_on = substs.types().collect();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_backedge<'c, I>(&mut self, cycle: I,
|
||||
@ -295,263 +545,6 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Processes a predicate obligation and returns either:
|
||||
/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true
|
||||
/// - `Ok(None)` if we don't have enough info to be sure
|
||||
/// - `Err` if the predicate does not hold
|
||||
fn process_predicate<'a, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
|
||||
pending_obligation: &mut PendingPredicateObligation<'tcx>,
|
||||
register_region_obligations: bool)
|
||||
-> Result<Option<Vec<PendingPredicateObligation<'tcx>>>,
|
||||
FulfillmentErrorCode<'tcx>>
|
||||
{
|
||||
// if we were stalled on some unresolved variables, first check
|
||||
// whether any of them have been resolved; if not, don't bother
|
||||
// doing more work yet
|
||||
if !pending_obligation.stalled_on.is_empty() {
|
||||
if pending_obligation.stalled_on.iter().all(|&ty| {
|
||||
let resolved_ty = selcx.infcx().shallow_resolve(&ty);
|
||||
resolved_ty == ty // nothing changed here
|
||||
}) {
|
||||
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
|
||||
selcx.infcx().resolve_type_vars_if_possible(&pending_obligation.obligation),
|
||||
pending_obligation.stalled_on);
|
||||
return Ok(None);
|
||||
}
|
||||
pending_obligation.stalled_on = vec![];
|
||||
}
|
||||
|
||||
let obligation = &mut pending_obligation.obligation;
|
||||
|
||||
if obligation.predicate.has_infer_types() {
|
||||
obligation.predicate = selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate);
|
||||
}
|
||||
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let trait_obligation = obligation.with(data.clone());
|
||||
|
||||
if data.is_global() && !data.has_late_bound_regions() {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
if selcx.infcx().predicate_must_hold(&obligation) {
|
||||
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
|
||||
data, obligation.recursion_depth);
|
||||
return Ok(Some(vec![]))
|
||||
}
|
||||
}
|
||||
|
||||
match selcx.select(&trait_obligation) {
|
||||
Ok(Some(vtable)) => {
|
||||
debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)",
|
||||
data, obligation.recursion_depth);
|
||||
Ok(Some(mk_pending(vtable.nested_obligations())))
|
||||
}
|
||||
Ok(None) => {
|
||||
debug!("selecting trait `{:?}` at depth {} yielded Ok(None)",
|
||||
data, obligation.recursion_depth);
|
||||
|
||||
// This is a bit subtle: for the most part, the
|
||||
// only reason we can fail to make progress on
|
||||
// trait selection is because we don't have enough
|
||||
// information about the types in the trait. One
|
||||
// exception is that we sometimes haven't decided
|
||||
// what kind of closure a closure is. *But*, in
|
||||
// that case, it turns out, the type of the
|
||||
// closure will also change, because the closure
|
||||
// also includes references to its upvars as part
|
||||
// of its type, and those types are resolved at
|
||||
// the same time.
|
||||
//
|
||||
// FIXME(#32286) logic seems false if no upvars
|
||||
pending_obligation.stalled_on =
|
||||
trait_ref_type_vars(selcx, data.to_poly_trait_ref());
|
||||
|
||||
debug!("process_predicate: pending obligation {:?} now stalled on {:?}",
|
||||
selcx.infcx().resolve_type_vars_if_possible(obligation),
|
||||
pending_obligation.stalled_on);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Err(selection_err) => {
|
||||
info!("selecting trait `{:?}` at depth {} yielded Err",
|
||||
data, obligation.recursion_depth);
|
||||
|
||||
Err(CodeSelectionError(selection_err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
match selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
|
||||
Ok(()) => Ok(Some(Vec::new())),
|
||||
Err(_) => Err(CodeSelectionError(Unimplemented)),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(ref binder) => {
|
||||
// Check if there are higher-ranked regions.
|
||||
match binder.no_late_bound_regions() {
|
||||
// If there are, inspect the underlying type further.
|
||||
None => {
|
||||
// Convert from `Binder<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`.
|
||||
let binder = binder.map_bound_ref(|pred| pred.0);
|
||||
|
||||
// Check if the type has any bound regions.
|
||||
match binder.no_late_bound_regions() {
|
||||
// If so, this obligation is an error (for now). Eventually we should be
|
||||
// able to support additional cases here, like `for<'a> &'a str: 'a`.
|
||||
None => {
|
||||
Err(CodeSelectionError(Unimplemented))
|
||||
}
|
||||
// Otherwise, we have something of the form
|
||||
// `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
|
||||
Some(t_a) => {
|
||||
let r_static = selcx.tcx().types.re_static;
|
||||
if register_region_obligations {
|
||||
selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_static,
|
||||
cause: obligation.cause.clone(),
|
||||
});
|
||||
}
|
||||
Ok(Some(vec![]))
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there aren't, register the obligation.
|
||||
Some(ty::OutlivesPredicate(t_a, r_b)) => {
|
||||
if register_region_obligations {
|
||||
selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_b,
|
||||
cause: obligation.cause.clone()
|
||||
});
|
||||
}
|
||||
Ok(Some(vec![]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
let project_obligation = obligation.with(data.clone());
|
||||
match project::poly_project_and_unify_type(selcx, &project_obligation) {
|
||||
Ok(None) => {
|
||||
let tcx = selcx.tcx();
|
||||
pending_obligation.stalled_on =
|
||||
trait_ref_type_vars(selcx, data.to_poly_trait_ref(tcx));
|
||||
Ok(None)
|
||||
}
|
||||
Ok(Some(os)) => Ok(Some(mk_pending(os))),
|
||||
Err(e) => Err(CodeProjectionError(e))
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
if !selcx.tcx().is_object_safe(trait_def_id) {
|
||||
Err(CodeSelectionError(Unimplemented))
|
||||
} else {
|
||||
Ok(Some(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
|
||||
match selcx.infcx().closure_kind(closure_def_id, closure_substs) {
|
||||
Some(closure_kind) => {
|
||||
if closure_kind.extends(kind) {
|
||||
Ok(Some(vec![]))
|
||||
} else {
|
||||
Err(CodeSelectionError(Unimplemented))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::WellFormed(ty) => {
|
||||
match ty::wf::obligations(selcx.infcx(),
|
||||
obligation.param_env,
|
||||
obligation.cause.body_id,
|
||||
ty, obligation.cause.span) {
|
||||
None => {
|
||||
pending_obligation.stalled_on = vec![ty];
|
||||
Ok(None)
|
||||
}
|
||||
Some(os) => Ok(Some(mk_pending(os)))
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Subtype(ref subtype) => {
|
||||
match selcx.infcx().subtype_predicate(&obligation.cause,
|
||||
obligation.param_env,
|
||||
subtype) {
|
||||
None => {
|
||||
// none means that both are unresolved
|
||||
pending_obligation.stalled_on = vec![subtype.skip_binder().a,
|
||||
subtype.skip_binder().b];
|
||||
Ok(None)
|
||||
}
|
||||
Some(Ok(ok)) => {
|
||||
Ok(Some(mk_pending(ok.obligations)))
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected,
|
||||
subtype.skip_binder().a,
|
||||
subtype.skip_binder().b);
|
||||
Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
match selcx.tcx().lift_to_global(&obligation.param_env) {
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
Some(param_env) => {
|
||||
match selcx.tcx().lift_to_global(&substs) {
|
||||
Some(substs) => {
|
||||
let instance = ty::Instance::resolve(
|
||||
selcx.tcx().global_tcx(),
|
||||
param_env,
|
||||
def_id,
|
||||
substs,
|
||||
);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
match selcx.tcx().at(obligation.cause.span)
|
||||
.const_eval(param_env.and(cid)) {
|
||||
Ok(_) => Ok(Some(vec![])),
|
||||
Err(err) => Err(CodeSelectionError(ConstEvalFailure(err)))
|
||||
}
|
||||
} else {
|
||||
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
|
||||
span: obligation.cause.span,
|
||||
kind: ErrKind::CouldNotResolve.into(),
|
||||
})))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
pending_obligation.stalled_on = substs.types().collect();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_fulfillment_error<'tcx>(
|
||||
error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>)
|
||||
-> FulfillmentError<'tcx>
|
||||
|
Loading…
Reference in New Issue
Block a user