use hir::def_id::DefId;
use infer::InferCtxt;
-use ty::outlives::Component;
use ty::subst::Substs;
use traits;
use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
span: Span)
-> Option<Vec<traits::PredicateObligation<'tcx>>>
{
- let mut wf = WfPredicates { infcx: infcx,
- param_env: param_env,
- body_id: body_id,
- span: span,
+ let mut wf = WfPredicates { infcx,
+ param_env,
+ body_id,
+ span,
out: vec![] };
if wf.compute(ty) {
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
wf.normalize()
}
-/// Implied bounds are region relationships that we deduce
-/// automatically. The idea is that (e.g.) a caller must check that a
-/// function's argument types are well-formed immediately before
-/// calling that fn, and hence the *callee* can assume that its
-/// argument types are well-formed. This may imply certain relationships
-/// between generic parameters. For example:
-///
-/// fn foo<'a,T>(x: &'a T)
-///
-/// can only be called with a `'a` and `T` such that `&'a T` is WF.
-/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
-#[derive(Debug)]
-pub enum ImpliedBound<'tcx> {
- RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
- RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
- RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
-}
-
-/// Compute the implied bounds that a callee/impl can assume based on
-/// the fact that caller/projector has ensured that `ty` is WF. See
-/// the `ImpliedBound` type for more details.
-pub fn implied_bounds<'a, 'gcx, 'tcx>(
- infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- body_id: ast::NodeId,
- ty: Ty<'tcx>,
- span: Span)
- -> Vec<ImpliedBound<'tcx>>
-{
- // Sometimes when we ask what it takes for T: WF, we get back that
- // U: WF is required; in that case, we push U onto this stack and
- // process it next. Currently (at least) these resulting
- // predicates are always guaranteed to be a subset of the original
- // type, so we need not fear non-termination.
- let mut wf_types = vec![ty];
-
- let mut implied_bounds = vec![];
-
- while let Some(ty) = wf_types.pop() {
- // Compute the obligations for `ty` to be well-formed. If `ty` is
- // an unresolved inference variable, just substituted an empty set
- // -- because the return type here is going to be things we *add*
- // to the environment, it's always ok for this set to be smaller
- // than the ultimate set. (Note: normally there won't be
- // unresolved inference variables here anyway, but there might be
- // during typeck under some circumstances.)
- let obligations = obligations(infcx, param_env, body_id, ty, span).unwrap_or(vec![]);
-
- // From the full set of obligations, just filter down to the
- // region relationships.
- implied_bounds.extend(
- obligations
- .into_iter()
- .flat_map(|obligation| {
- assert!(!obligation.has_escaping_regions());
- match obligation.predicate {
- ty::Predicate::Trait(..) |
- ty::Predicate::Equate(..) |
- ty::Predicate::Subtype(..) |
- ty::Predicate::Projection(..) |
- ty::Predicate::ClosureKind(..) |
- ty::Predicate::ObjectSafe(..) =>
- vec![],
-
- ty::Predicate::WellFormed(subty) => {
- wf_types.push(subty);
- vec![]
- }
-
- ty::Predicate::RegionOutlives(ref data) =>
- match infcx.tcx.no_late_bound_regions(data) {
- None =>
- vec![],
- Some(ty::OutlivesPredicate(r_a, r_b)) =>
- vec![ImpliedBound::RegionSubRegion(r_b, r_a)],
- },
-
- ty::Predicate::TypeOutlives(ref data) =>
- match infcx.tcx.no_late_bound_regions(data) {
- None => vec![],
- Some(ty::OutlivesPredicate(ty_a, r_b)) => {
- let ty_a = infcx.resolve_type_vars_if_possible(&ty_a);
- let components = infcx.tcx.outlives_components(ty_a);
- implied_bounds_from_components(r_b, components)
- }
- },
- }}));
- }
-
- implied_bounds
-}
-
-/// When we have an implied bound that `T: 'a`, we can further break
-/// this down to determine what relationships would have to hold for
-/// `T: 'a` to hold. We get to assume that the caller has validated
-/// those relationships.
-fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>,
- sup_components: Vec<Component<'tcx>>)
- -> Vec<ImpliedBound<'tcx>>
-{
- sup_components
- .into_iter()
- .flat_map(|component| {
- match component {
- Component::Region(r) =>
- vec![ImpliedBound::RegionSubRegion(sub_region, r)],
- Component::Param(p) =>
- vec![ImpliedBound::RegionSubParam(sub_region, p)],
- Component::Projection(p) =>
- vec![ImpliedBound::RegionSubProjection(sub_region, p)],
- Component::EscapingProjection(_) =>
- // If the projection has escaping regions, don't
- // try to infer any implied bounds even for its
- // free components. This is conservative, because
- // the caller will still have to prove that those
- // free components outlive `sub_region`. But the
- // idea is that the WAY that the caller proves
- // that may change in the future and we want to
- // give ourselves room to get smarter here.
- vec![],
- Component::UnresolvedInferenceVariable(..) =>
- vec![],
- }
- })
- .collect()
-}
-
struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
// A projection is well-formed if (a) the trait ref itself is
// WF and (b) the trait-ref holds. (It may also be
// normalizable and be WF that way.)
-
- self.compute_trait_ref(&data.trait_ref);
+ let trait_ref = data.trait_ref(self.infcx.tcx);
+ self.compute_trait_ref(&trait_ref);
if !data.has_escaping_regions() {
- let predicate = data.trait_ref.to_predicate();
+ let predicate = trait_ref.to_predicate();
let cause = self.cause(traits::ProjectionWf(data));
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
}