-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Refactor trans some more to pave way for incremental compilation #41355
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
bors
merged 9 commits into
rust-lang:master
from
nikomatsakis:incr-comp-refactor-trans-2
Apr 22, 2017
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
8289e5a
introduce `is_foreign_item` query
nikomatsakis 4c31750
remove `translation_items` from `SharedCrateContext`
nikomatsakis 39a58c3
introduce the rather simpler symbol-cache in place of symbol-map
nikomatsakis c446cb0
just take `tcx` where we can
nikomatsakis 264f237
make `reachable_set` ref-counted
nikomatsakis e48a759
sort `provide`
nikomatsakis f4c183b
move the trans trait caches into tcx
nikomatsakis 8552745
use Symbol/InternedString in the cache
nikomatsakis 6d86f81
move the uses of the trans caches into rustc::traits
nikomatsakis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
// Copyright 2012-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. | ||
|
||
// This file contains various trait resolution methods used by trans. | ||
// They all assume regions can be erased and monomorphic types. It | ||
// seems likely that they should eventually be merged into more | ||
// general routines. | ||
|
||
use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; | ||
use hir::def_id::DefId; | ||
use infer::TransNormalize; | ||
use std::cell::RefCell; | ||
use std::marker::PhantomData; | ||
use syntax::ast; | ||
use syntax_pos::Span; | ||
use traits::{FulfillmentContext, Obligation, ObligationCause, Reveal, SelectionContext, Vtable}; | ||
use ty::{self, Ty, TyCtxt}; | ||
use ty::subst::{Subst, Substs}; | ||
use ty::fold::{TypeFoldable, TypeFolder}; | ||
use util::common::MemoizationMap; | ||
|
||
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { | ||
/// Attempts to resolve an obligation to a vtable.. The result is | ||
/// a shallow vtable resolution -- meaning that we do not | ||
/// (necessarily) resolve all nested obligations on the impl. Note | ||
/// that type check should guarantee to us that all nested | ||
/// obligations *could be* resolved if we wanted to. | ||
pub fn trans_fulfill_obligation(self, | ||
span: Span, | ||
trait_ref: ty::PolyTraitRef<'tcx>) | ||
-> Vtable<'tcx, ()> | ||
{ | ||
// Remove any references to regions; this helps improve caching. | ||
let trait_ref = self.erase_regions(&trait_ref); | ||
|
||
self.trans_trait_caches.trait_cache.memoize(trait_ref, || { | ||
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", | ||
trait_ref, trait_ref.def_id()); | ||
|
||
// 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| { | ||
let mut selcx = SelectionContext::new(&infcx); | ||
|
||
let obligation_cause = ObligationCause::misc(span, | ||
ast::DUMMY_NODE_ID); | ||
let obligation = Obligation::new(obligation_cause, | ||
trait_ref.to_poly_trait_predicate()); | ||
|
||
let selection = match selcx.select(&obligation) { | ||
Ok(Some(selection)) => selection, | ||
Ok(None) => { | ||
// Ambiguity can happen when monomorphizing during trans | ||
// expands to some humongo type that never occurred | ||
// statically -- this humongo type can then overflow, | ||
// leading to an ambiguous result. So report this as an | ||
// overflow bug, since I believe this is the only case | ||
// where ambiguity can result. | ||
debug!("Encountered ambiguity selecting `{:?}` during trans, \ | ||
presuming due to overflow", | ||
trait_ref); | ||
self.sess.span_fatal(span, | ||
"reached the recursion limit during monomorphization \ | ||
(selection ambiguity)"); | ||
} | ||
Err(e) => { | ||
span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", | ||
e, trait_ref) | ||
} | ||
}; | ||
|
||
debug!("fulfill_obligation: selection={:?}", selection); | ||
|
||
// Currently, we use a fulfillment context to completely resolve | ||
// all nested obligations. This is because they can inform the | ||
// inference of the impl's type parameters. | ||
let mut fulfill_cx = FulfillmentContext::new(); | ||
let vtable = selection.map(|predicate| { | ||
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); | ||
fulfill_cx.register_predicate_obligation(&infcx, predicate); | ||
}); | ||
let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); | ||
|
||
info!("Cache miss: {:?} => {:?}", trait_ref, vtable); | ||
vtable | ||
}) | ||
}) | ||
} | ||
|
||
/// Monomorphizes a type from the AST by first applying the in-scope | ||
/// substitutions and then normalizing any associated types. | ||
pub fn trans_apply_param_substs<T>(self, | ||
param_substs: &Substs<'tcx>, | ||
value: &T) | ||
-> T | ||
where T: TransNormalize<'tcx> | ||
{ | ||
debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); | ||
let substituted = value.subst(self, param_substs); | ||
let substituted = self.erase_regions(&substituted); | ||
AssociatedTypeNormalizer::new(self).fold(&substituted) | ||
} | ||
} | ||
|
||
struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { | ||
tcx: TyCtxt<'a, 'gcx, 'gcx>, | ||
} | ||
|
||
impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { | ||
fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { | ||
AssociatedTypeNormalizer { tcx } | ||
} | ||
|
||
fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T { | ||
if !value.has_projection_types() { | ||
value.clone() | ||
} else { | ||
value.fold_with(self) | ||
} | ||
} | ||
} | ||
|
||
impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { | ||
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { | ||
self.tcx | ||
} | ||
|
||
fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { | ||
if !ty.has_projection_types() { | ||
ty | ||
} else { | ||
self.tcx.trans_trait_caches.project_cache.memoize(ty, || { | ||
debug!("AssociatedTypeNormalizer: ty={:?}", ty); | ||
self.tcx.normalize_associated_type(&ty) | ||
}) | ||
} | ||
} | ||
} | ||
|
||
/// Specializes caches used in trans -- in particular, they assume all | ||
/// types are fully monomorphized and that free regions can be erased. | ||
pub struct TransTraitCaches<'tcx> { | ||
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>, | ||
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>, | ||
} | ||
|
||
impl<'tcx> TransTraitCaches<'tcx> { | ||
pub fn new(graph: DepGraph) -> Self { | ||
TransTraitCaches { | ||
trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())), | ||
project_cache: RefCell::new(DepTrackingMap::new(graph)), | ||
} | ||
} | ||
} | ||
|
||
// Implement DepTrackingMapConfig for `trait_cache` | ||
pub struct TraitSelectionCache<'tcx> { | ||
data: PhantomData<&'tcx ()> | ||
} | ||
|
||
impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { | ||
type Key = ty::PolyTraitRef<'tcx>; | ||
type Value = Vtable<'tcx, ()>; | ||
fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> { | ||
key.to_poly_trait_predicate().dep_node() | ||
} | ||
} | ||
|
||
// # Global Cache | ||
|
||
pub struct ProjectionCache<'gcx> { | ||
data: PhantomData<&'gcx ()> | ||
} | ||
|
||
impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { | ||
type Key = Ty<'gcx>; | ||
type Value = Ty<'gcx>; | ||
fn to_dep_node(key: &Self::Key) -> DepNode<DefId> { | ||
// Ideally, we'd just put `key` into the dep-node, but we | ||
// can't put full types in there. So just collect up all the | ||
// def-ids of structs/enums as well as any traits that we | ||
// project out of. It doesn't matter so much what we do here, | ||
// except that if we are too coarse, we'll create overly | ||
// coarse edges between impls and the trans. For example, if | ||
// we just used the def-id of things we are projecting out of, | ||
// then the key for `<Foo as SomeTrait>::T` and `<Bar as | ||
// SomeTrait>::T` would both share a dep-node | ||
// (`TraitSelect(SomeTrait)`), and hence the impls for both | ||
// `Foo` and `Bar` would be considered inputs. So a change to | ||
// `Bar` would affect things that just normalized `Foo`. | ||
// Anyway, this heuristic is not ideal, but better than | ||
// nothing. | ||
let def_ids: Vec<DefId> = | ||
key.walk() | ||
.filter_map(|t| match t.sty { | ||
ty::TyAdt(adt_def, _) => Some(adt_def.did), | ||
ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), | ||
_ => None, | ||
}) | ||
.collect(); | ||
|
||
DepNode::ProjectionCache { def_ids: def_ids } | ||
} | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no similar method to remove on the
CrateStore
trait?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, there is such a method, it gets called quite a few times. I can work on refactoring those away.