Auto merge of #41605 - tschottdorf:param-env, r=nikomatsakis

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.
This commit is contained in:
bors 2017-05-02 20:44:03 +00:00
commit 4d81b14b80
7 changed files with 59 additions and 18 deletions

View file

@ -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();
@ -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);
@ -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))
})
}

View file

@ -32,7 +32,7 @@
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::*;
@ -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> {
@ -107,6 +108,7 @@ fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> {
substs: RefCell::new(FxHashSet()),
region: RefCell::new(FxHashSet()),
existential_predicates: RefCell::new(FxHashSet()),
predicates: RefCell::new(FxHashSet()),
}
}
@ -1130,6 +1132,13 @@ fn borrow<'a>(&'a self) -> &'a [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,
@ -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)
);
@ -1443,6 +1453,19 @@ pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'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()
@ -1481,6 +1504,12 @@ pub fn mk_existential_predicates<I: InternAs<[ExistentialPredicate<'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))

View file

@ -747,7 +747,7 @@ pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, '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`
@ -876,7 +876,7 @@ pub fn subst_supertrait(&self, tcx: TyCtxt<'a, 'gcx, '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>
}
@ -928,18 +928,18 @@ pub fn dep_node(&self) -> DepNode<DefId> {
}
}
#[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>,
@ -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
@ -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 {
@ -2441,7 +2441,7 @@ pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
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()),
@ -2516,7 +2516,7 @@ pub fn construct_parameter_environment(self,
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()),

View file

@ -313,6 +313,9 @@ pub fn struct_lockstep_tails(self,
///
/// 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>>)

View file

@ -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,

View file

@ -893,7 +893,7 @@ fn assemble_where_clause_candidates(&mut self,
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) {

View file

@ -1687,7 +1687,7 @@ fn declared_generic_bounds_from_env(&self, generic: GenericKind<'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