Skip to content

Commit

Permalink
rustc: split GenericPredicates of a method from its parent predicates.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Aug 17, 2016
1 parent 3e74e5b commit 6f5e455
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 150 deletions.
26 changes: 12 additions & 14 deletions src/librustc/traits/select.rs
Expand Up @@ -2897,20 +2897,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// obligation will normalize to `<$0 as Iterator>::Item = $1` and
// `$1: Copy`, so we must ensure the obligations are emitted in
// that order.
let predicates = tcx
.lookup_predicates(def_id)
.predicates.iter()
.flat_map(|predicate| {
let predicate =
normalize_with_depth(self, cause.clone(), recursion_depth,
&predicate.subst(tcx, substs));
predicate.obligations.into_iter().chain(
Some(Obligation {
cause: cause.clone(),
recursion_depth: recursion_depth,
predicate: predicate.value
}))
}).collect();
let predicates = tcx.lookup_predicates(def_id);
assert_eq!(predicates.parent, None);
let predicates = predicates.predicates.iter().flat_map(|predicate| {
let predicate = normalize_with_depth(self, cause.clone(), recursion_depth,
&predicate.subst(tcx, substs));
predicate.obligations.into_iter().chain(
Some(Obligation {
cause: cause.clone(),
recursion_depth: recursion_depth,
predicate: predicate.value
}))
}).collect();
self.infcx().plug_leaks(skol_map, snapshot, &predicates)
}
}
Expand Down
25 changes: 18 additions & 7 deletions src/librustc/ty/mod.rs
Expand Up @@ -768,27 +768,38 @@ pub struct Generics<'tcx> {
/// Bounds on generics.
#[derive(Clone)]
pub struct GenericPredicates<'tcx> {
pub parent: Option<DefId>,
pub predicates: Vec<Predicate<'tcx>>,
}

impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
pub fn empty() -> GenericPredicates<'tcx> {
GenericPredicates {
predicates: vec![]
}
}

pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>)
-> InstantiatedPredicates<'tcx> {
let mut instantiated = InstantiatedPredicates::empty();
self.instantiate_into(tcx, &mut instantiated, substs);
instantiated
}
pub fn instantiate_own(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>)
-> InstantiatedPredicates<'tcx> {
InstantiatedPredicates {
predicates: self.predicates.subst(tcx, substs),
predicates: self.predicates.subst(tcx, substs)
}
}

fn instantiate_into(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
instantiated: &mut InstantiatedPredicates<'tcx>,
substs: &Substs<'tcx>) {
if let Some(def_id) = self.parent {
tcx.lookup_predicates(def_id).instantiate_into(tcx, instantiated, substs);
}
instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs)))
}

pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
poly_trait_ref: &ty::PolyTraitRef<'tcx>)
-> InstantiatedPredicates<'tcx>
{
assert_eq!(self.parent, None);
InstantiatedPredicates {
predicates: self.predicates.iter().map(|pred| {
pred.subst_supertrait(tcx, poly_trait_ref)
Expand Down
12 changes: 0 additions & 12 deletions src/librustc/ty/structural_impls.rs
Expand Up @@ -832,18 +832,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::GenericPredicates {
predicates: self.predicates.fold_with(folder),
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.predicates.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_metadata/decoder.rs
Expand Up @@ -1591,6 +1591,7 @@ fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc,
let doc = reader::get_doc(base_doc, tag);

ty::GenericPredicates {
parent: item_parent_item(cdata, doc),
predicates: reader::tagged_docs(doc, tag_predicate).map(|predicate_doc| {
doc_predicate(cdata, predicate_doc, tcx)
}).collect()
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_metadata/encoder.rs
Expand Up @@ -525,6 +525,9 @@ fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
tag: usize)
{
rbml_w.start_tag(tag);
if let Some(def_id) = predicates.parent {
rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id));
}
for predicate in &predicates.predicates {
rbml_w.wr_tagged_u32(tag_predicate,
index.add_xref(XRef::Predicate(predicate.clone())));
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/astconv.rs
Expand Up @@ -1726,6 +1726,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let predicates = bounds.predicates(tcx, ty);
let predicates = tcx.lift_to_global(&predicates).unwrap();
tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
parent: None,
predicates: predicates
});

Expand Down
30 changes: 10 additions & 20 deletions src/librustc_typeck/check/compare_method.rs
Expand Up @@ -211,29 +211,18 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
return;
}

// Depend on trait/impl predicates always being before method's own predicates,
// to be able to split method predicates into "inherited" and method-specific.
let trait_predicates = tcx.lookup_predicates(trait_m.container_id()).predicates;
let impl_predicates = tcx.lookup_predicates(impl_m.container_id()).predicates;
let trait_method_start = trait_predicates.len();
let impl_method_start = impl_predicates.len();
assert_eq!(&trait_predicates[..], &trait_m.predicates.predicates[..trait_method_start]);
assert_eq!(&impl_predicates[..], &impl_m.predicates.predicates[..impl_method_start]);

tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();

// Normalize the associated types in the trait_bounds.
let trait_bounds = trait_m.predicates.instantiate(tcx, trait_to_skol_substs);

// Create obligations for each predicate declared by the impl
// definition in the context of the trait's parameter
// environment. We can't just use `impl_env.caller_bounds`,
// however, because we want to replace all late-bound regions with
// region variables.
let impl_bounds = impl_m.predicates.instantiate(tcx, impl_to_skol_substs);
let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap());
let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs);

debug!("compare_impl_method: impl_bounds={:?}", impl_bounds);
debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);

// This is the only tricky bit of the new way we check implementation methods
// We need to build a set of predicates where only the FnSpace bounds
Expand All @@ -242,14 +231,14 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
//
// We then register the obligations from the impl_m and check to see
// if all constraints hold.
let hybrid_preds = impl_bounds.predicates[..impl_method_start].iter()
.chain(trait_bounds.predicates[trait_method_start..].iter());
hybrid_preds.predicates.extend(
trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);

// Construct trait parameter environment and then shift it into the skolemized viewpoint.
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.cloned().collect());
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
let trait_param_env = traits::normalize_param_env_or_error(tcx,
trait_param_env,
normalize_cause.clone());
Expand All @@ -261,12 +250,13 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,

let mut selcx = traits::SelectionContext::new(&infcx);

let (impl_pred_fns, _) =
let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs);
let (impl_m_own_bounds, _) =
infcx.replace_late_bound_regions_with_fresh_var(
impl_m_span,
infer::HigherRankedType,
&ty::Binder(impl_bounds.predicates[impl_method_start..].to_vec()));
for predicate in impl_pred_fns {
&ty::Binder(impl_m_own_bounds.predicates));
for predicate in impl_m_own_bounds {
let traits::Normalized { value: predicate, .. } =
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);

Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/check/dropck.rs
Expand Up @@ -184,6 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
// 'a:'b and T:'b into region inference constraints. It is simpler
// just to look for all the predicates directly.

assert_eq!(dtor_predicates.parent, None);
for predicate in &dtor_predicates.predicates {
// (We do not need to worry about deep analysis of type
// expressions etc because the Drop impls are already forced
Expand Down
12 changes: 9 additions & 3 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -1612,8 +1612,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
bounds: &ty::GenericPredicates<'tcx>)
-> ty::InstantiatedPredicates<'tcx>
{
let result = bounds.instantiate(self.tcx, substs);
let result = self.normalize_associated_types_in(span, &result.predicates);
debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}",
bounds,
substs,
result);
ty::InstantiatedPredicates {
predicates: self.instantiate_type_scheme(span, substs, &bounds.predicates)
predicates: result
}
}

Expand Down Expand Up @@ -4210,8 +4216,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
_ => {}
}
let scheme = self.tcx.lookup_item_type(def.def_id());
let type_predicates = self.tcx.lookup_predicates(def.def_id());

// Now we have to compare the types that the user *actually*
// provided against the types that were *expected*. If the user
Expand Down Expand Up @@ -4296,6 +4300,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

// The things we are substituting into the type should not contain
// escaping late-bound regions, and nor should the base type scheme.
let scheme = self.tcx.lookup_item_type(def.def_id());
let type_predicates = self.tcx.lookup_predicates(def.def_id());
assert!(!substs.has_escaping_regions());
assert!(!scheme.ty.has_escaping_regions());

Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/check/regionck.rs
Expand Up @@ -1754,6 +1754,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
//
// we can thus deduce that `<T as SomeTrait<'a>>::SomeType : 'a`.
let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id);
assert_eq!(trait_predicates.parent, None);
let predicates = trait_predicates.predicates.as_slice().to_vec();
traits::elaborate_predicates(self.tcx, predicates)
.filter_map(|predicate| {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/check/wfcheck.rs
Expand Up @@ -454,6 +454,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {

let item_def_id = self.tcx().map.local_def_id(item.id);
let ty_predicates = self.tcx().lookup_predicates(item_def_id);
assert_eq!(ty_predicates.parent, None);
let variances = self.tcx().item_variances(item_def_id);

let mut constrained_parameters: HashSet<_> =
Expand Down

0 comments on commit 6f5e455

Please sign in to comment.