Skip to content

Rollup of 3 pull requests #41464

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 16 commits into from
Apr 22, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
move the uses of the trans caches into rustc::traits
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
commit 6d86f81eb1bd2d36d1e75958fd1f53648e82f407
147 changes: 143 additions & 4 deletions src/librustc/traits/trans/mod.rs
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading