diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2018-02-21 11:24:13 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2018-03-13 11:22:07 -0400 |
| commit | 211d9ad7db19fcb23f0200786595b8b170382609 (patch) | |
| tree | d66fc1df64c2767fa5c0dc42e08559dfd0eeae9a | |
| parent | ca87d24467c46c07961f1b6450dabfb9674913da (diff) | |
| download | rust-211d9ad7db19fcb23f0200786595b8b170382609.tar.gz rust-211d9ad7db19fcb23f0200786595b8b170382609.zip | |
introduce `tcx.normalize_erasing_regions(..)` operaton [VIC]
| -rw-r--r-- | src/librustc/session/mod.rs | 5 | ||||
| -rw-r--r-- | src/librustc/traits/query/mod.rs | 1 | ||||
| -rw-r--r-- | src/librustc/traits/query/normalize_erasing_regions.rs | 81 | ||||
| -rw-r--r-- | src/librustc/ty/maps/config.rs | 8 | ||||
| -rw-r--r-- | src/librustc/ty/maps/mod.rs | 7 | ||||
| -rw-r--r-- | src/librustc/ty/maps/plumbing.rs | 3 | ||||
| -rw-r--r-- | src/librustc_traits/lib.rs | 4 | ||||
| -rw-r--r-- | src/librustc_traits/normalize_erasing_regions.rs | 37 |
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), + } + }) +} |
