about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTobias Schottdorf <tobias.schottdorf@gmail.com>2017-05-02 14:37:00 -0400
committerTobias Schottdorf <tobias.schottdorf@gmail.com>2017-05-02 14:37:00 -0400
commita6658d5ff1bee0aa46224bc05985692783fd11b4 (patch)
tree372e0d96b5ad7ef24208d0f19f3065fb3ece22d7
parented1f26ddda15b2bcf613a257e813e8b02ee14dff (diff)
downloadrust-a6658d5ff1bee0aa46224bc05985692783fd11b4.tar.gz
rust-a6658d5ff1bee0aa46224bc05985692783fd11b4.zip
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.
-rw-r--r--src/librustc/traits/mod.rs18
-rw-r--r--src/librustc/ty/context.rs31
-rw-r--r--src/librustc/ty/mod.rs18
-rw-r--r--src/librustc/ty/util.rs3
-rw-r--r--src/librustc_typeck/check/compare_method.rs3
-rw-r--r--src/librustc_typeck/check/method/probe.rs2
-rw-r--r--src/librustc_typeck/check/regionck.rs2
7 files changed, 59 insertions, 18 deletions
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 4f7cb2b12a7..2f525e1b8b4 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -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))
     })
 }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 6de61013dfd..ef0240296cc 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -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::*;
@@ -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 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
             substs: RefCell::new(FxHashSet()),
             region: RefCell::new(FxHashSet()),
             existential_predicates: RefCell::new(FxHashSet()),
+            predicates: RefCell::new(FxHashSet()),
         }
     }
 
@@ -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,
@@ -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 @@ 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()
@@ -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))
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index c07f41fb223..bf0f75cf323 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -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`
@@ -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>
 }
@@ -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>,
@@ -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 @@ 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()),
@@ -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()),
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index befc4e6c5fd..24dfae3c540 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -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>>)
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 80330afaad8..9ed5528e867 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -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,
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 3cd53c378dd..c1cf5192877 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -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) {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 8a63d501da8..e4936dfc47b 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -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