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)
- }
-
- fn process_backedge<'c, I>(&mut self, cycle: I,
- _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>)
- where I: Clone + Iterator<Item=&'c PendingPredicateObligation<'tcx>>,
- {
- if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
- debug!("process_child_obligations: coinductive match");
- } else {
- let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
- self.selcx.infcx().report_overflow_error_cycle(&cycle);
+ // 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![];
}
- }
-}
-/// Return the set of type variables contained in a trait ref
-fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
- t: ty::PolyTraitRef<'tcx>) -> Vec<Ty<'tcx>>
-{
- t.skip_binder() // ok b/c this check doesn't care about regions
- .input_types()
- .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t))
- .filter(|t| t.has_infer_types())
- .flat_map(|t| t.walk())
- .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false })
- .collect()
-}
+ let obligation = &mut pending_obligation.obligation;
-/// 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);
+ if obligation.predicate.has_infer_types() {
+ obligation.predicate =
+ self.selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate);
}
- 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 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 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);
+ 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))
+ 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::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 = 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(),
- });
+ 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![]))
}
- 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()
- });
+ // 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![]))
}
- 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)
+ 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))
}
- 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::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 selcx.infcx().closure_kind(closure_def_id, closure_substs) {
- Some(closure_kind) => {
- if closure_kind.extends(kind) {
- Ok(Some(vec![]))
- } else {
- Err(CodeSelectionError(Unimplemented))
+ 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)
}
- }
- 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)
+ 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)))
}
- 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::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 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)))
+ 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(),
+ })))
}
- } else {
- Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
- span: obligation.cause.span,
- kind: ErrKind::CouldNotResolve.into(),
- })))
+ },
+ None => {
+ pending_obligation.stalled_on = substs.types().collect();
+ Ok(None)
}
- },
- None => {
- pending_obligation.stalled_on = substs.types().collect();
- Ok(None)
}
}
}
}
}
}
+
+ fn process_backedge<'c, I>(&mut self, cycle: I,
+ _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>)
+ where I: Clone + Iterator<Item=&'c PendingPredicateObligation<'tcx>>,
+ {
+ if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
+ debug!("process_child_obligations: coinductive match");
+ } else {
+ let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
+ self.selcx.infcx().report_overflow_error_cycle(&cycle);
+ }
+ }
+}
+
+/// Return the set of type variables contained in a trait ref
+fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
+ t: ty::PolyTraitRef<'tcx>) -> Vec<Ty<'tcx>>
+{
+ t.skip_binder() // ok b/c this check doesn't care about regions
+ .input_types()
+ .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t))
+ .filter(|t| t.has_infer_types())
+ .flat_map(|t| t.walk())
+ .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false })
+ .collect()
}
fn to_fulfillment_error<'tcx>(