Skip to content

Commit

Permalink
move the uses of the trans caches into rustc::traits
Browse files Browse the repository at this point in the history
This makes these routines more readily available for other bits of
code. It also will help when refactoring.
  • Loading branch information
nikomatsakis committed Apr 22, 2017
1 parent 8552745 commit 6d86f81
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 154 deletions.
147 changes: 143 additions & 4 deletions src/librustc/traits/trans/mod.rs
@@ -1,15 +1,154 @@
// 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 traits::Vtable;
use ty::{self, Ty};
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> {
pub trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
pub project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
}

impl<'tcx> TransTraitCaches<'tcx> {
Expand Down
28 changes: 10 additions & 18 deletions src/librustc_trans/collector.rs
Expand Up @@ -467,13 +467,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
// have to instantiate all methods of the trait being cast to, so we
// can build the appropriate vtable.
mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => {
let target_ty = monomorphize::apply_param_substs(self.scx,
self.param_substs,
&target_ty);
let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
&target_ty);
let source_ty = operand.ty(self.mir, self.scx.tcx());
let source_ty = monomorphize::apply_param_substs(self.scx,
self.param_substs,
&source_ty);
let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
&source_ty);
let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx,
source_ty,
target_ty);
Expand All @@ -489,10 +487,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
}
mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => {
let fn_ty = operand.ty(self.mir, self.scx.tcx());
let fn_ty = monomorphize::apply_param_substs(
self.scx,
self.param_substs,
&fn_ty);
let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
&fn_ty);
visit_fn_use(self.scx, fn_ty, false, &mut self.output);
}
mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
Expand Down Expand Up @@ -534,9 +530,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
}

if let mir::Literal::Item { def_id, substs } = constant.literal {
let substs = monomorphize::apply_param_substs(self.scx,
self.param_substs,
&substs);
let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs,
&substs);
let instance = monomorphize::resolve(self.scx, def_id, substs);
collect_neighbours(self.scx, instance, self.output);
}
Expand All @@ -552,17 +547,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
match *kind {
mir::TerminatorKind::Call { ref func, .. } => {
let callee_ty = func.ty(self.mir, tcx);
let callee_ty = monomorphize::apply_param_substs(
self.scx, self.param_substs, &callee_ty);
let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
visit_fn_use(self.scx, callee_ty, true, &mut self.output);
}
mir::TerminatorKind::Drop { ref location, .. } |
mir::TerminatorKind::DropAndReplace { ref location, .. } => {
let ty = location.ty(self.mir, self.scx.tcx())
.to_ty(self.scx.tcx());
let ty = monomorphize::apply_param_substs(self.scx,
self.param_substs,
&ty);
let ty = tcx.trans_apply_param_substs(self.param_substs, &ty);
visit_drop_use(self.scx, ty, true, self.output);
}
mir::TerminatorKind::Goto { .. } |
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/common.rs
Expand Up @@ -564,7 +564,7 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
-> Ty<'tcx>
{
let ty = shared.tcx().item_type(def_id);
monomorphize::apply_param_substs(shared, substs, &ty)
shared.tcx().trans_apply_param_substs(substs, &ty)
}

/// Return the substituted type of an instance.
Expand All @@ -573,5 +573,5 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
-> Ty<'tcx>
{
let ty = instance.def.def_ty(shared.tcx());
monomorphize::apply_param_substs(shared, instance.substs, &ty)
shared.tcx().trans_apply_param_substs(instance.substs, &ty)
}
4 changes: 1 addition & 3 deletions src/librustc_trans/mir/constant.rs
Expand Up @@ -260,9 +260,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn monomorphize<T>(&self, value: &T) -> T
where T: TransNormalize<'tcx>
{
monomorphize::apply_param_substs(self.ccx.shared(),
self.substs,
value)
self.ccx.tcx().trans_apply_param_substs(self.substs, value)
}

fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_trans/mir/mod.rs
Expand Up @@ -22,7 +22,7 @@ use base;
use builder::Builder;
use common::{self, CrateContext, Funclet};
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
use monomorphize::{self, Instance};
use monomorphize::Instance;
use abi::FnType;
use type_of;

Expand Down Expand Up @@ -102,8 +102,9 @@ pub struct MirContext<'a, 'tcx:'a> {

impl<'a, 'tcx> MirContext<'a, 'tcx> {
pub fn monomorphize<T>(&self, value: &T) -> T
where T: TransNormalize<'tcx> {
monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value)
where T: TransNormalize<'tcx>
{
self.ccx.tcx().trans_apply_param_substs(self.param_substs, value)
}

pub fn set_debug_loc(&mut self, bcx: &Builder, source_info: mir::SourceInfo) {
Expand Down

0 comments on commit 6d86f81

Please sign in to comment.