Skip to content

Commit

Permalink
introduce tcx.normalize_erasing_regions(..) operaton [VIC]
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Mar 13, 2018
1 parent ca87d24 commit 211d9ad
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/librustc/session/mod.rs
Expand Up @@ -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>,
}

Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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()),
Expand Down
1 change: 1 addition & 0 deletions src/librustc/traits/query/mod.rs
Expand Up @@ -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>>>;
Expand Down
81 changes: 81 additions & 0 deletions 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))
}
}
8 changes: 7 additions & 1 deletion src/librustc/ty/maps/config.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion src/librustc/ty/maps/mod.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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>
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/ty/maps/plumbing.rs
Expand Up @@ -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 |
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_traits/lib.rs
Expand Up @@ -19,13 +19,15 @@

#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
extern crate syntax;
extern crate syntax_pos;

mod dropck_outlives;
mod normalize_projection_ty;
mod normalize_erasing_regions;
mod util;

use rustc::ty::maps::Providers;
Expand All @@ -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
};
}
37 changes: 37 additions & 0 deletions 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),
}
})
}

0 comments on commit 211d9ad

Please sign in to comment.