about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-02-21 11:24:13 -0500
committerNiko Matsakis <niko@alum.mit.edu>2018-03-13 11:22:07 -0400
commit211d9ad7db19fcb23f0200786595b8b170382609 (patch)
treed66fc1df64c2767fa5c0dc42e08559dfd0eeae9a
parentca87d24467c46c07961f1b6450dabfb9674913da (diff)
downloadrust-211d9ad7db19fcb23f0200786595b8b170382609.tar.gz
rust-211d9ad7db19fcb23f0200786595b8b170382609.zip
introduce `tcx.normalize_erasing_regions(..)` operaton [VIC]
-rw-r--r--src/librustc/session/mod.rs5
-rw-r--r--src/librustc/traits/query/mod.rs1
-rw-r--r--src/librustc/traits/query/normalize_erasing_regions.rs81
-rw-r--r--src/librustc/ty/maps/config.rs8
-rw-r--r--src/librustc/ty/maps/mod.rs7
-rw-r--r--src/librustc/ty/maps/plumbing.rs3
-rw-r--r--src/librustc_traits/lib.rs4
-rw-r--r--src/librustc_traits/normalize_erasing_regions.rs37
8 files changed, 143 insertions, 3 deletions
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index b986445ff84..3f52ecfc099 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -179,6 +179,8 @@ pub struct PerfStats {
     /// result had already been canonicalized.
     pub canonicalized_values_allocated: Cell<usize>,
     /// Number of times this query is invoked.
+    pub normalize_ty_after_erasing_regions: Cell<usize>,
+    /// Number of times this query is invoked.
     pub normalize_projection_ty: Cell<usize>,
 }
 
@@ -869,6 +871,8 @@ impl Session {
                  self.perf_stats.queries_canonicalized.get());
         println!("Total canonical values interned:               {}",
                  self.perf_stats.canonicalized_values_allocated.get());
+        println!("normalize_ty_after_erasing_regions:            {}",
+                 self.perf_stats.normalize_ty_after_erasing_regions.get());
         println!("normalize_projection_ty:                       {}",
                  self.perf_stats.normalize_projection_ty.get());
     }
@@ -1159,6 +1163,7 @@ pub fn build_session_(
             decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
             queries_canonicalized: Cell::new(0),
             canonicalized_values_allocated: Cell::new(0),
+            normalize_ty_after_erasing_regions: Cell::new(0),
             normalize_projection_ty: Cell::new(0),
         },
         code_stats: RefCell::new(CodeStats::new()),
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index 607344f9c67..f1f9256f825 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -20,6 +20,7 @@ use ty::{self, Ty};
 
 pub mod dropck_outlives;
 pub mod normalize;
+pub mod normalize_erasing_regions;
 
 pub type CanonicalProjectionGoal<'tcx> =
     Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs
new file mode 100644
index 00000000000..d2d8da88e2d
--- /dev/null
+++ b/src/librustc/traits/query/normalize_erasing_regions.rs
@@ -0,0 +1,81 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Methods for normalizing when you don't care about regions (and
+//! aren't doing type inference). If either of those things don't
+//! apply to you, use `infcx.normalize(...)`.
+//!
+//! The methods in this file use a `TypeFolder` to recursively process
+//! contents, invoking the underlying
+//! `normalize_ty_after_erasing_regions` query for each type found
+//! within. (This underlying query is what is cached.)
+
+use ty::{self, Ty, TyCtxt};
+use ty::fold::{TypeFoldable, TypeFolder};
+
+impl<'cx, 'tcx> TyCtxt<'cx, 'tcx, 'tcx> {
+    /// Erase the regions in `value` and then fully normalize all the
+    /// types found within. The result will also have regions erased.
+    ///
+    /// This is appropriate to use only after type-check: it assumes
+    /// that normalization will succeed, for example.
+    pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        // Erase first before we do the real query -- this keeps the
+        // cache from being too polluted.
+        let value = self.erase_regions(&value);
+        if !value.has_projections() {
+            value
+        } else {
+            value.fold_with(&mut NormalizeAfterErasingRegionsFolder {
+                tcx: self,
+                param_env: param_env,
+            })
+        }
+    }
+
+    /// If you have a `Binder<T>`, you can do this to strip out the
+    /// late-bound regions and then normalize the result, yielding up
+    /// a `T` (with regions erased). This is appropriate when the
+    /// binder is being instantiated at the call site.
+    ///
+    /// NB. Currently, higher-ranked type bounds inhibit
+    /// normalization. Therefore, each time we erase them in
+    /// translation, we need to normalize the contents.
+    pub fn normalize_erasing_late_bound_regions<T>(
+        self,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &ty::Binder<T>,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        assert!(!value.needs_subst());
+        let value = self.erase_late_bound_regions(value);
+        self.normalize_erasing_regions(param_env, value)
+    }
+}
+
+struct NormalizeAfterErasingRegionsFolder<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'cx, 'tcx> TypeFolder<'tcx, 'tcx> for NormalizeAfterErasingRegionsFolder<'cx, 'tcx> {
+    fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty))
+    }
+}
diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs
index bcd6a5ace62..487bcf1f96a 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -12,7 +12,7 @@ use dep_graph::SerializedDepNodeIndex;
 use hir::def_id::{CrateNum, DefId, DefIndex};
 use mir::interpret::{GlobalId};
 use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
-use ty::{self, Ty, TyCtxt};
+use ty::{self, ParamEnvAnd, Ty, TyCtxt};
 use ty::subst::Substs;
 use ty::maps::queries;
 
@@ -67,6 +67,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_regions<'tcx> {
+    fn describe(_tcx: TyCtxt, goal: ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
+        format!("normalizing `{:?}`", goal)
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
     fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
         format!("computing whether `{}` is `Copy`", env.value)
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 4df15b2e76b..15e309c13d5 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -38,7 +38,7 @@ use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
 use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use traits::query::normalize::NormalizationResult;
 use traits::specialization_graph;
-use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 use ty::steal::Steal;
 use ty::subst::Substs;
 use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
@@ -394,6 +394,11 @@ define_maps! { <'tcx>
         NoSolution,
     >,
 
+    /// Do not call this query directly: invoke `normalize_erasing_regions` instead.
+    [] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions(
+        ParamEnvAnd<'tcx, Ty<'tcx>>
+    ) -> Ty<'tcx>,
+
     /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
     [] fn dropck_outlives: DropckOutlives(
         CanonicalTyGoal<'tcx>
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index 64b17922049..53a3bcdba33 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -772,8 +772,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::FulfillObligation |
         DepKind::VtableMethods |
         DepKind::EraseRegionsTy |
-        DepKind::NormalizeTy |
         DepKind::NormalizeProjectionTy |
+        DepKind::NormalizeTyAfterErasingRegions |
+        DepKind::NormalizeTy |
         DepKind::DropckOutlives |
         DepKind::SubstituteNormalizeAndTestPredicates |
         DepKind::InstanceDefSizeEstimate |
diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs
index 59083dcfbf0..45d23a2733a 100644
--- a/src/librustc_traits/lib.rs
+++ b/src/librustc_traits/lib.rs
@@ -19,6 +19,7 @@
 
 #[macro_use]
 extern crate log;
+#[macro_use]
 extern crate rustc;
 extern crate rustc_data_structures;
 extern crate syntax;
@@ -26,6 +27,7 @@ extern crate syntax_pos;
 
 mod dropck_outlives;
 mod normalize_projection_ty;
+mod normalize_erasing_regions;
 mod util;
 
 use rustc::ty::maps::Providers;
@@ -35,6 +37,8 @@ pub fn provide(p: &mut Providers) {
         dropck_outlives: dropck_outlives::dropck_outlives,
         adt_dtorck_constraint: dropck_outlives::adt_dtorck_constraint,
         normalize_projection_ty: normalize_projection_ty::normalize_projection_ty,
+        normalize_ty_after_erasing_regions:
+            normalize_erasing_regions::normalize_ty_after_erasing_regions,
         ..*p
     };
 }
diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs
new file mode 100644
index 00000000000..805bf1030b3
--- /dev/null
+++ b/src/librustc_traits/normalize_erasing_regions.rs
@@ -0,0 +1,37 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::traits::{Normalized, ObligationCause};
+use rustc::traits::query::NoSolution;
+use rustc::ty::{ParamEnvAnd, Ty, TyCtxt};
+use rustc::util::common::CellUsizeExt;
+
+crate fn normalize_ty_after_erasing_regions<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> Ty<'tcx> {
+    let ParamEnvAnd { param_env, value } = goal;
+    tcx.sess.perf_stats.normalize_ty_after_erasing_regions.increment();
+    tcx.infer_ctxt().enter(|infcx| {
+        let cause = ObligationCause::dummy();
+        match infcx.at(&cause, param_env).normalize(&value) {
+            Ok(Normalized { value: normalized_value, obligations: _ }) => {
+                //                                   ^^^^^^^^^^^
+                //                   We don't care about the `obligations`,
+                //                   they are always only region relations,
+                //                   and we are about to erase those anyway.
+                let normalized_value = infcx.resolve_type_vars_if_possible(&normalized_value);
+                let normalized_value = infcx.tcx.erase_regions(&normalized_value);
+                tcx.lift_to_global(&normalized_value).unwrap()
+            }
+            Err(NoSolution) => bug!("could not fully normalize `{:?}`", value),
+        }
+    })
+}