Skip to content

Commit

Permalink
Auto merge of #41605 - tschottdorf:param-env, r=nikomatsakis
Browse files Browse the repository at this point in the history
Store interned predicates in ParameterEnvironment

See #41444. As a first step towards untangling `ParameterEnvironment`, change
its `caller_bounds` field from a `Vec` into an interned slice of
`ty::Predicate`s.

This change is intentionally well-contained and doesn't pull on any of the
loose ends. In particular, you'll note that `normalize_param_env_or_error`
now interns twice.
  • Loading branch information
bors committed May 2, 2017
2 parents 6a5fc9e + a6658d5 commit 4d81b14
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 18 deletions.
18 changes: 13 additions & 5 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
unnormalized_env);

let predicates: Vec<_> =
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.clone())
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
.filter(|p| !p.is_global()) // (*)
.collect();

Expand All @@ -477,11 +477,19 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
predicates);

let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
let elaborated_env = unnormalized_env.with_caller_bounds(tcx.intern_predicates(&predicates));

tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
let predicates = match fully_normalize(&infcx, cause,
&infcx.parameter_environment.caller_bounds) {
let predicates = match fully_normalize(
&infcx, cause,
// You would really want to pass infcx.parameter_environment.caller_bounds here,
// but that is an interned slice, and fully_normalize takes &T and returns T, so
// without further refactoring, a slice can't be used. Luckily, we still have the
// predicate vector from which we created the ParameterEnvironment in infcx, so we
// can pass that instead. It's roundabout and a bit brittle, but this code path
// ought to be refactored anyway, and until then it saves us from having to copy.
&predicates,
) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.report_fulfillment_errors(&errors);
Expand Down Expand Up @@ -520,7 +528,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_param_env_or_error: resolved predicates={:?}",
predicates);

infcx.parameter_environment.with_caller_bounds(predicates)
infcx.parameter_environment.with_caller_bounds(tcx.intern_predicates(&predicates))
})
}

Expand Down
31 changes: 30 additions & 1 deletion src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use ty::{self, TraitRef, Ty, TypeAndMut};
use ty::{TyS, TypeVariants, Slice};
use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
use hir::FreevarMap;
use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
use ty::RegionKind;
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
Expand Down Expand Up @@ -96,6 +96,7 @@ pub struct CtxtInterners<'tcx> {
substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
region: RefCell<FxHashSet<Interned<'tcx, RegionKind<'tcx>>>>,
existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>,
}

impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
Expand All @@ -107,6 +108,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
substs: RefCell::new(FxHashSet()),
region: RefCell::new(FxHashSet()),
existential_predicates: RefCell::new(FxHashSet()),
predicates: RefCell::new(FxHashSet()),
}
}

Expand Down Expand Up @@ -1130,6 +1132,13 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]>
}
}

impl<'tcx: 'lcx, 'lcx> Borrow<[Predicate<'lcx>]>
for Interned<'tcx, Slice<Predicate<'tcx>>> {
fn borrow<'a>(&'a self) -> &'a [Predicate<'lcx>] {
&self.0[..]
}
}

macro_rules! intern_method {
($lt_tcx:tt, $name:ident: $method:ident($alloc:ty,
$alloc_method:ident,
Expand Down Expand Up @@ -1224,6 +1233,7 @@ macro_rules! slice_interners {

slice_interners!(
existential_predicates: _intern_existential_predicates(ExistentialPredicate),
predicates: _intern_predicates(Predicate),
type_list: _intern_type_list(Ty),
substs: _intern_substs(Kind)
);
Expand Down Expand Up @@ -1443,6 +1453,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self._intern_existential_predicates(eps)
}

pub fn intern_predicates(self, preds: &[Predicate<'tcx>])
-> &'tcx Slice<Predicate<'tcx>> {
// FIXME consider asking the input slice to be sorted to avoid
// re-interning permutations, in which case that would be asserted
// here.
if preds.len() == 0 {
// The macro-generated method below asserts we don't intern an empty slice.
Slice::empty()
} else {
self._intern_predicates(preds)
}
}

pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx Slice<Ty<'tcx>> {
if ts.len() == 0 {
Slice::empty()
Expand Down Expand Up @@ -1481,6 +1504,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
iter.intern_with(|xs| self.intern_existential_predicates(xs))
}

pub fn mk_predicates<I: InternAs<[Predicate<'tcx>],
&'tcx Slice<Predicate<'tcx>>>>(self, iter: I)
-> I::Output {
iter.intern_with(|xs| self.intern_predicates(xs))
}

pub fn mk_type_list<I: InternAs<[Ty<'tcx>],
&'tcx Slice<Ty<'tcx>>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_type_list(xs))
Expand Down
18 changes: 9 additions & 9 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
}
}

#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum Predicate<'tcx> {
/// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be
/// the `Self` type of the trait reference and `A`, `B`, and `C`
Expand Down Expand Up @@ -876,7 +876,7 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
}
}

#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct TraitPredicate<'tcx> {
pub trait_ref: TraitRef<'tcx>
}
Expand Down Expand Up @@ -928,18 +928,18 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
}
}

#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1`
pub type PolyEquatePredicate<'tcx> = ty::Binder<EquatePredicate<'tcx>>;

#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<ty::Region<'tcx>,
ty::Region<'tcx>>;
pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;

#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct SubtypePredicate<'tcx> {
pub a_is_expected: bool,
pub a: Ty<'tcx>,
Expand Down Expand Up @@ -1173,7 +1173,7 @@ pub struct ParameterEnvironment<'tcx> {
/// Obligations that the caller must satisfy. This is basically
/// the set of bounds on the in-scope type parameters, translated
/// into Obligations, and elaborated and normalized.
pub caller_bounds: Vec<ty::Predicate<'tcx>>,
pub caller_bounds: &'tcx [ty::Predicate<'tcx>],

/// Scope that is attached to free regions for this scope. This is
/// usually the id of the fn body, but for more abstract scopes
Expand All @@ -1196,7 +1196,7 @@ pub struct ParameterEnvironment<'tcx> {

impl<'a, 'tcx> ParameterEnvironment<'tcx> {
pub fn with_caller_bounds(&self,
caller_bounds: Vec<ty::Predicate<'tcx>>)
caller_bounds: &'tcx [ty::Predicate<'tcx>])
-> ParameterEnvironment<'tcx>
{
ParameterEnvironment {
Expand Down Expand Up @@ -2441,7 +2441,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
ty::ParameterEnvironment {
free_substs: self.intern_substs(&[]),
caller_bounds: Vec::new(),
caller_bounds: Slice::empty(),
implicit_region_bound: None,
free_id_outlive: None,
is_copy_cache: RefCell::new(FxHashMap()),
Expand Down Expand Up @@ -2516,7 +2516,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let unnormalized_env = ty::ParameterEnvironment {
free_substs: free_substs,
implicit_region_bound: free_id_outlive.map(|f| tcx.mk_region(ty::ReScope(f))),
caller_bounds: predicates,
caller_bounds: tcx.intern_predicates(&predicates),
free_id_outlive: free_id_outlive,
is_copy_cache: RefCell::new(FxHashMap()),
is_sized_cache: RefCell::new(FxHashMap()),
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
///
/// FIXME callers may only have a &[Predicate], not a Vec, so that's
/// what this code should accept.
pub fn required_region_bounds(self,
erased_self_ty: Ty<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>)
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// 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_node_id);
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
let trait_param_env = impl_param_env.with_caller_bounds(
tcx.intern_predicates(&hybrid_preds.predicates));
let trait_param_env = traits::normalize_param_env_or_error(tcx,
impl_m.def_id,
trait_param_env,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
debug!("assemble_where_clause_candidates(trait_def_id={:?})",
trait_def_id);

let caller_predicates = self.parameter_environment.caller_bounds.clone();
let caller_predicates = self.parameter_environment.caller_bounds.to_vec();
for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates)
.filter_map(|p| p.to_opt_poly_trait_ref())
.filter(|b| b.def_id() == trait_def_id) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1687,7 +1687,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {

// To start, collect bounds from user:
let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx),
param_env.caller_bounds.clone());
param_env.caller_bounds.to_vec());

// Next, collect regions we scraped from the well-formedness
// constraints in the fn signature. To do that, we walk the list
Expand Down

0 comments on commit 4d81b14

Please sign in to comment.