Skip to content

Commit

Permalink
move projection mode into parameter environment
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Jun 1, 2017
1 parent 4ed2eda commit 6c4b961
Show file tree
Hide file tree
Showing 28 changed files with 110 additions and 99 deletions.
58 changes: 22 additions & 36 deletions src/librustc/infer/mod.rs
Expand Up @@ -174,11 +174,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FxHashSet<traits::TraitErrorKey<'tcx>>>,

// Sadly, the behavior of projection varies a bit depending on the
// stage of compilation. The specifics are given in the
// documentation for `Reveal`.
projection_mode: Reveal,

// When an error occurs, we want to avoid reporting "derived"
// errors that are due to this original failure. Normally, we
// handle this with the `err_count_on_creation` count, which
Expand Down Expand Up @@ -406,54 +401,54 @@ pub trait InferEnv<'a, 'tcx> {
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>);
ty::ParamEnv<'tcx>);
}

impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
impl<'a, 'tcx> InferEnv<'a, 'tcx> for Reveal {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(None, None, None)
ty::ParamEnv<'tcx>) {
(None, None, ty::ParamEnv::empty(self))
}
}

impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParamEnv<'tcx> {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(None, None, Some(self))
ty::ParamEnv<'tcx>) {
(None, None, self)
}
}

impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(Some(self.0), None, Some(self.1))
ty::ParamEnv<'tcx>) {
(Some(self.0), None, self.1)
}
}

impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(None, Some(self.0), Some(self.1))
ty::ParamEnv<'tcx>) {
(None, Some(self.0), self.1)
}
}

impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
ty::ParamEnv<'tcx>) {
let def_id = tcx.hir.body_owner_def_id(self);
(Some(tcx.typeck_tables_of(def_id)),
None,
Some(tcx.param_env(def_id)))
tcx.param_env(def_id))
}
}

Expand All @@ -465,23 +460,18 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
arena: DroplessArena,
fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
tables: Option<&'a ty::TypeckTables<'gcx>>,
param_env: Option<ty::ParamEnv<'gcx>>,
projection_mode: Reveal,
param_env: ty::ParamEnv<'gcx>,
}

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self,
env: E,
projection_mode: Reveal)
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
let (tables, fresh_tables, param_env) = env.to_parts(self);
InferCtxtBuilder {
global_tcx: self,
arena: DroplessArena::new(),
fresh_tables: fresh_tables.map(RefCell::new),
tables: tables,
param_env: param_env,
projection_mode: projection_mode,
}
}

Expand All @@ -498,12 +488,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
region_vars: RegionVarBindings::new(self),
param_env: param_env.unwrap(),
param_env: param_env,
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FxHashSet()),
projection_mode: Reveal::UserFacing,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(),
in_snapshot: Cell::new(false),
Expand All @@ -520,13 +509,11 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
ref arena,
ref fresh_tables,
tables,
ref mut param_env,
projection_mode,
param_env,
} = *self;
let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
});
let param_env = param_env.take().unwrap_or_else(|| ty::ParamEnv::empty());
global_tcx.enter_local(arena, |tcx| f(InferCtxt {
tcx: tcx,
tables: tables,
Expand All @@ -539,7 +526,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
reported_trait_errors: RefCell::new(FxHashSet()),
projection_mode: projection_mode,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: tcx.sess.err_count(),
in_snapshot: Cell::new(false),
Expand Down Expand Up @@ -643,11 +629,15 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
return value;
}

self.infer_ctxt((), Reveal::All).enter(|infcx| {
self.infer_ctxt(Reveal::All).enter(|infcx| {
value.trans_normalize(&infcx)
})
}

/// Does a best-effort to normalize any associated types in
/// `value`; this includes revealing specializable types, so this
/// should be not be used during type-checking, but only during
/// optimization and code generation.
pub fn normalize_associated_type_in_env<T>(
self, value: &T, env: ty::ParamEnv<'tcx>
) -> T
Expand All @@ -661,7 +651,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
return value;
}

self.infer_ctxt(env, Reveal::All).enter(|infcx| {
self.infer_ctxt(env.reveal_all()).enter(|infcx| {
value.trans_normalize(&infcx)
})
}
Expand Down Expand Up @@ -728,10 +718,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}

pub fn projection_mode(&self) -> Reveal {
self.projection_mode
}

pub fn is_in_snapshot(&self) -> bool {
self.in_snapshot.get()
}
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/middle/intrinsicck.rs
Expand Up @@ -11,7 +11,6 @@
use hir::def::Def;
use hir::def_id::DefId;
use infer::InferCtxt;
use traits::Reveal;
use ty::{self, Ty, TyCtxt};
use ty::layout::{LayoutError, Pointer, SizeSkeleton};

Expand Down Expand Up @@ -140,7 +139,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {

fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let body = self.tcx.hir.body(body_id);
self.tcx.infer_ctxt(body_id, Reveal::All).enter(|infcx| {
self.tcx.infer_ctxt(body_id).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
Expand Down
9 changes: 5 additions & 4 deletions src/librustc/traits/mod.rs
Expand Up @@ -477,9 +477,10 @@ 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 = ty::ParamEnv::new(tcx.intern_predicates(&predicates));
let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
unnormalized_env.reveal);

tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(elaborated_env).enter(|infcx| {
let predicates = match fully_normalize(
&infcx, cause,
// You would really want to pass infcx.param_env.caller_bounds here,
Expand Down Expand Up @@ -528,7 +529,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_param_env_or_error: resolved predicates={:?}",
predicates);

ty::ParamEnv::new(tcx.intern_predicates(&predicates))
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
})
}

Expand Down Expand Up @@ -590,7 +591,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_and_test_predicates(predicates={:?})",
predicates);

tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
tcx.infer_ctxt(Reveal::All).enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = FulfillmentContext::new();
let cause = ObligationCause::dummy();
Expand Down
16 changes: 9 additions & 7 deletions src/librustc/traits/project.rs
Expand Up @@ -36,7 +36,7 @@ use util::common::FN_OUTPUT_NAME;

/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Reveal {
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
Expand Down Expand Up @@ -278,12 +278,14 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
match ty.sty {
ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*)
// Only normalize `impl Trait` after type-checking, usually in trans.
if self.selcx.projection_mode() == Reveal::All {
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.fold_ty(concrete_ty)
} else {
ty
match self.param_env.reveal {
Reveal::UserFacing => ty,

Reveal::All => {
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.fold_ty(concrete_ty)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/select.rs
Expand Up @@ -324,7 +324,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}

pub fn projection_mode(&self) -> Reveal {
self.infcx.projection_mode()
self.param_env().reveal
}

/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/traits/specialize/mod.rs
Expand Up @@ -122,7 +122,7 @@ pub fn find_associated_item<'a, 'tcx>(
let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
match ancestors.defs(tcx, item.name, item.kind).next() {
Some(node_item) => {
let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
let substs = tcx.infer_ctxt(Reveal::All).enter(|infcx| {
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
let substs = translate_substs(&infcx, impl_data.impl_def_id,
substs, node_item.node);
Expand Down Expand Up @@ -184,7 +184,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();

// Create a infcx, taking the predicates of impl1 as assumptions:
let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
let result = tcx.infer_ctxt(penv).enter(|infcx| {
// Normalize the trait reference. The WF rules ought to ensure
// that this always succeeds.
let impl1_trait_ref =
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/specialize/specialization_graph.rs
Expand Up @@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Children {
let possible_sibling = *slot;

let tcx = tcx.global_tcx();
let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let (le, ge) = tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| {
let overlap = traits::overlapping_impls(&infcx,
possible_sibling,
impl_def_id);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/trans/mod.rs
Expand Up @@ -46,7 +46,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {

// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
self.infer_ctxt((), Reveal::All).enter(|infcx| {
self.infer_ctxt(Reveal::All).enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);

let obligation_cause = ObligationCause::misc(span,
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/ty/maps.rs
Expand Up @@ -906,6 +906,12 @@ define_maps! { <'tcx>
[] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
[] is_object_safe: ObjectSafety(DefId) -> bool,

// Get the ParameterEnvironment for a given item; this environment
// will be in "user-facing" mode, meaning that it is suitabe for
// type-checking etc, and it does not normalize specializable
// associated types. This is almost always what you want,
// unless you are doing MIR optimizations, in which case you
// might want to use `reveal_all()` method to change modes.
[] param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>,

// Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
Expand Down
14 changes: 10 additions & 4 deletions src/librustc/ty/mod.rs
Expand Up @@ -1191,6 +1191,11 @@ pub struct ParamEnv<'tcx> {
/// the set of bounds on the in-scope type parameters, translated
/// into Obligations, and elaborated and normalized.
pub caller_bounds: &'tcx Slice<ty::Predicate<'tcx>>,

/// Typically, this is `Reveal::UserFacing`, but during trans we
/// want `Reveal::All` -- note that this is always paired with an
/// empty environment. To get that, use `ParamEnv::reveal()`.
pub reveal: traits::Reveal,
}

impl<'tcx> ParamEnv<'tcx> {
Expand Down Expand Up @@ -1218,7 +1223,7 @@ impl<'tcx> ParamEnv<'tcx> {
}
} else {
ParamEnvAnd {
param_env: ParamEnv::empty(),
param_env: ParamEnv::empty(self.reveal),
value: value,
}
}
Expand Down Expand Up @@ -2467,8 +2472,8 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option

/// See `ParamEnv` struct def'n for details.
fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ParamEnv<'tcx> {
def_id: DefId)
-> ParamEnv<'tcx> {
// Compute the bounds on Self and the type parameters.

let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
Expand All @@ -2486,7 +2491,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// are any errors at that point, so after type checking you can be
// sure that this will succeed without errors anyway.

let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates));
let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
traits::Reveal::UserFacing);

let body_id = tcx.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
tcx.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id)
Expand Down

0 comments on commit 6c4b961

Please sign in to comment.