Skip to content

Cache projections in trans #35761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub enum DepNode<D: Clone + Debug> {
// which would yield an overly conservative dep-graph.
TraitItems(D),
ReprHints(D),
TraitSelect(D, Vec<D>),
TraitSelect(Vec<D>),
}

impl<D: Clone + Debug> DepNode<D> {
Expand Down Expand Up @@ -237,10 +237,9 @@ impl<D: Clone + Debug> DepNode<D> {
TraitImpls(ref d) => op(d).map(TraitImpls),
TraitItems(ref d) => op(d).map(TraitItems),
ReprHints(ref d) => op(d).map(ReprHints),
TraitSelect(ref d, ref type_ds) => {
let d = try_opt!(op(d));
TraitSelect(ref type_ds) => {
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
Some(TraitSelect(d, type_ds))
Some(TraitSelect(type_ds))
}
}
}
Expand Down
92 changes: 24 additions & 68 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,

// This is a temporary field used for toggling on normalization in the inference context,
// as we move towards the approach described here:
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
// At a point sometime in the future normalization will be done by the typing context
// directly.
normalize: bool,

// Sadly, the behavior of projection varies a bit depending on the
// stage of compilation. The specifics are given in the
// documentation for `Reveal`.
Expand Down Expand Up @@ -458,7 +451,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tables: Option<RefCell<ty::Tables<'tcx>>>,
param_env: Option<ty::ParameterEnvironment<'gcx>>,
projection_mode: Reveal,
normalize: bool
}

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
Expand All @@ -473,19 +465,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
tables: tables.map(RefCell::new),
param_env: param_env,
projection_mode: projection_mode,
normalize: false
}
}

pub fn normalizing_infer_ctxt(self, projection_mode: Reveal)
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
InferCtxtBuilder {
global_tcx: self,
arenas: ty::CtxtArenas::new(),
tables: None,
param_env: None,
projection_mode: projection_mode,
normalize: false
}
}

Expand All @@ -506,7 +485,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
evaluation_cache: traits::EvaluationCache::new(),
projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FnvHashSet()),
normalize: false,
projection_mode: Reveal::NotSpecializable,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(),
Expand All @@ -525,7 +503,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
ref tables,
ref mut param_env,
projection_mode,
normalize
} = *self;
let tables = if let Some(ref tables) = *tables {
InferTables::Local(tables)
Expand All @@ -547,7 +524,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
reported_trait_errors: RefCell::new(FnvHashSet()),
normalize: normalize,
projection_mode: projection_mode,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: tcx.sess.err_count(),
Expand Down Expand Up @@ -683,6 +659,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
}

/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
/// for use after type-check has completed, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
pub fn drain_fulfillment_cx_or_panic<T>(&self,
span: Span,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
Expand All @@ -692,47 +677,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
{
debug!("drain_fulfillment_cx_or_panic()");

let when = "resolving bounds after type-checking";
let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
Ok(v) => v,
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
match fulfill_cx.select_all_or_error(self) {
Ok(()) => { }
Err(errors) => {
span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
errors);
}
};
}

let result = self.resolve_type_vars_if_possible(result);
let result = self.tcx.erase_regions(&result);

match self.tcx.lift_to_global(&v) {
Some(v) => v,
match self.tcx.lift_to_global(&result) {
Some(result) => result,
None => {
span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
span_bug!(span, "Uninferred types/regions in `{:?}`", result);
}
}
}

/// Finishes processes any obligations that remain in the fulfillment
/// context, and then "freshens" and returns `result`. This is
/// primarily used during normalization and other cases where
/// processing the obligations in `fulfill_cx` may cause type
/// inference variables that appear in `result` to be unified, and
/// hence we need to process those obligations to get the complete
/// picture of the type.
pub fn drain_fulfillment_cx<T>(&self,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> Result<T,Vec<traits::FulfillmentError<'tcx>>>
where T : TypeFoldable<'tcx>
{
debug!("drain_fulfillment_cx(result={:?})",
result);

// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
fulfill_cx.select_all_or_error(self)?;

let result = self.resolve_type_vars_if_possible(result);
Ok(self.tcx.erase_regions(&result))
}

pub fn projection_mode(&self) -> Reveal {
self.projection_mode
}
Expand Down Expand Up @@ -1702,17 +1668,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}

let closure_ty = self.tcx.closure_type(def_id, substs);
if self.normalize {
let closure_ty = self.tcx.erase_regions(&closure_ty);

if !closure_ty.has_projection_types() {
return closure_ty;
}

self.normalize_projections_in(&closure_ty)
} else {
closure_ty
}
closure_ty
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't need to exist anymore AFAICT.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't need to exist anymore AFAICT.

Why do you say that? Certainly, it is still called, e.g. from the trait code -- and it seems like it still serves a purpose (drawing the types for local closures from the inference tables). But maybe I'm forgetting some subtle point here?

Copy link
Member

@eddyb eddyb Sep 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only exists because it's doing something different than self.tcx.closure_type(def_id, substs), but not after your changes. The InferTables enum might also be removable Nevermind, that's mainly there for lifetime issues.

EDIT: wait, that's also wrong, it's on tables - the tcx one is global-context-only.
EDIT2: no, there's also dynamic shenanigans with cross-crate loading. Forget about changing this.

}
}

Expand Down
37 changes: 20 additions & 17 deletions src/librustc/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.unwrap()
.subst(tcx, &penv.free_substs);

let result = tcx.normalizing_infer_ctxt(Reveal::ExactMatch).enter(|mut infcx| {
let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| {
// Normalize the trait reference, adding any obligations
// that arise into the impl1 assumptions.
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
Expand Down Expand Up @@ -207,24 +207,27 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
for oblig in obligations.into_iter() {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
match fulfill_cx.select_all_or_error(infcx) {
Err(errors) => {
// no dice!
debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
{:?}",
source_trait_ref,
target_trait_ref,
errors,
infcx.parameter_environment.caller_bounds);
Err(())
}

if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) {
// no dice!
debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
{:?}",
source_trait_ref,
target_trait_ref,
errors,
infcx.parameter_environment.caller_bounds);
Err(())
} else {
debug!("fulfill_implication: an impl for {:?} specializes {:?}",
source_trait_ref,
target_trait_ref);
Ok(()) => {
debug!("fulfill_implication: an impl for {:?} specializes {:?}",
source_trait_ref,
target_trait_ref);

// Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_type_vars_if_possible(&target_substs))
// Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_type_vars_if_possible(&target_substs))
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,8 +958,9 @@ impl<'tcx> TraitPredicate<'tcx> {
_ =>
None
})
.chain(iter::once(self.def_id()))
.collect();
DepNode::TraitSelect(self.def_id(), def_ids)
DepNode::TraitSelect(def_ids)
}

pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ impl LateLintPass for VariantSizeDifferences {
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
let t = cx.tcx.node_id_to_type(it.id);
let layout = cx.tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t);
ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", t, e)
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1128,7 +1128,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance

let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty;
let fn_ty = ccx.tcx().erase_regions(&fn_ty);
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty);
let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);

let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
Expand All @@ -1151,7 +1151,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
attributes::set_frame_pointer_elimination(ccx, llfndecl);

let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty;
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &ctor_ty);
let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);

let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
Expand Down Expand Up @@ -1894,7 +1894,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
};

let codegen_units = time(time_passes, "codegen unit partitioning", || {
partitioning::partition(scx.tcx(),
partitioning::partition(scx,
items.iter().cloned(),
strategy,
&inlining_map,
Expand Down
20 changes: 10 additions & 10 deletions src/librustc_trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use base;
use base::*;
use build::*;
use closure;
use common::{self, Block, Result, CrateContext, FunctionContext};
use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
use consts;
use debuginfo::DebugLoc;
use declare;
Expand All @@ -37,7 +37,7 @@ use monomorphize::{self, Instance};
use trans_item::TransItem;
use type_of;
use Disr;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::hir;

use syntax_pos::DUMMY_SP;
Expand Down Expand Up @@ -97,7 +97,7 @@ impl<'tcx> Callee<'tcx> {
return Callee::trait_method(ccx, trait_id, def_id, substs);
}

let fn_ty = def_ty(tcx, def_id, substs);
let fn_ty = def_ty(ccx.shared(), def_id, substs);
if let ty::TyFnDef(_, _, f) = fn_ty.sty {
if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
return Callee {
Expand Down Expand Up @@ -155,20 +155,20 @@ impl<'tcx> Callee<'tcx> {
vtable_closure.substs,
trait_closure_kind);

let method_ty = def_ty(tcx, def_id, substs);
let method_ty = def_ty(ccx.shared(), def_id, substs);
Callee::ptr(llfn, method_ty)
}
traits::VtableFnPointer(vtable_fn_pointer) => {
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);

let method_ty = def_ty(tcx, def_id, substs);
let method_ty = def_ty(ccx.shared(), def_id, substs);
Callee::ptr(llfn, method_ty)
}
traits::VtableObject(ref data) => {
Callee {
data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
ty: def_ty(tcx, def_id, substs)
ty: def_ty(ccx.shared(), def_id, substs)
}
}
vtable => {
Expand Down Expand Up @@ -244,12 +244,12 @@ impl<'tcx> Callee<'tcx> {
}

/// Given a DefId and some Substs, produces the monomorphic item type.
fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>)
-> Ty<'tcx> {
let ty = tcx.lookup_item_type(def_id).ty;
monomorphize::apply_param_substs(tcx, substs, &ty)
let ty = shared.tcx().lookup_item_type(def_id).ty;
monomorphize::apply_param_substs(shared, substs, &ty)
}

/// Translates an adapter that implements the `Fn` trait for a fn
Expand Down Expand Up @@ -407,7 +407,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let substs = tcx.normalize_associated_type(&substs);
let instance = Instance::new(def_id, substs);
let item_ty = ccx.tcx().lookup_item_type(def_id).ty;
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &item_ty);
let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);

if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
return (llfn, fn_ty);
Expand Down
Loading