rustc: Split local type contexts interners from the global one.
This commit is contained in:
parent
31a07b0ce6
commit
a1c170fc35
65 changed files with 1144 additions and 702 deletions
|
|
@ -24,6 +24,7 @@ use middle::free_region::FreeRegionMap;
|
|||
use middle::mem_categorization as mc;
|
||||
use middle::mem_categorization::McResult;
|
||||
use middle::region::CodeExtent;
|
||||
use mir::tcx::LvalueTy;
|
||||
use ty::subst;
|
||||
use ty::subst::Substs;
|
||||
use ty::subst::Subst;
|
||||
|
|
@ -35,7 +36,7 @@ use ty::fold::TypeFoldable;
|
|||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use traits::{self, PredicateObligations, ProjectionMode};
|
||||
use rustc_data_structures::unify::{self, UnificationTable};
|
||||
use std::cell::{Cell, RefCell, Ref};
|
||||
use std::cell::{Cell, RefCell, Ref, RefMut};
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::codemap;
|
||||
|
|
@ -72,10 +73,36 @@ pub type Bound<T> = Option<T>;
|
|||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
|
||||
|
||||
/// A version of &ty::Tables which can be global or local.
|
||||
/// Only the local version supports borrow_mut.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum InferTables<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
Global(&'a RefCell<ty::Tables<'gcx>>),
|
||||
Local(&'a RefCell<ty::Tables<'tcx>>)
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferTables<'a, 'gcx, 'tcx> {
|
||||
pub fn borrow(self) -> Ref<'a, ty::Tables<'tcx>> {
|
||||
match self {
|
||||
InferTables::Global(tables) => tables.borrow(),
|
||||
InferTables::Local(tables) => tables.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_mut(self) -> RefMut<'a, ty::Tables<'tcx>> {
|
||||
match self {
|
||||
InferTables::Global(_) => {
|
||||
bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking");
|
||||
}
|
||||
InferTables::Local(tables) => tables.borrow_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
||||
pub tables: &'a RefCell<ty::Tables<'tcx>>,
|
||||
pub tables: InferTables<'a, 'gcx, 'tcx>,
|
||||
|
||||
// We instantiate UnificationTable with bounds<Ty> because the
|
||||
// types that might instantiate a general type variable have an
|
||||
|
|
@ -390,48 +417,106 @@ impl fmt::Display for FixupError {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx, 'tcx> {
|
||||
pub fn enter<F, R>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: Option<ty::Tables<'tcx>>,
|
||||
param_env: Option<ty::ParameterEnvironment<'tcx>>,
|
||||
projection_mode: ProjectionMode,
|
||||
f: F) -> R
|
||||
where F: for<'b> FnOnce(InferCtxt<'b, 'tcx, 'tcx>) -> R
|
||||
/// Helper type of a temporary returned by tcx.infer_ctxt(...).
|
||||
/// Necessary because we can't write the following bound:
|
||||
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>).
|
||||
pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
||||
arenas: ty::CtxtArenas<'tcx>,
|
||||
tables: Option<RefCell<ty::Tables<'tcx>>>,
|
||||
param_env: Option<ty::ParameterEnvironment<'gcx>>,
|
||||
projection_mode: ProjectionMode,
|
||||
normalize: bool
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
pub fn infer_ctxt(self,
|
||||
tables: Option<ty::Tables<'tcx>>,
|
||||
param_env: Option<ty::ParameterEnvironment<'gcx>>,
|
||||
projection_mode: ProjectionMode)
|
||||
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
InferCtxtBuilder {
|
||||
global_tcx: self,
|
||||
arenas: ty::CtxtArenas::new(),
|
||||
tables: tables.map(RefCell::new),
|
||||
param_env: param_env,
|
||||
projection_mode: projection_mode,
|
||||
normalize: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalizing_infer_ctxt(self, projection_mode: ProjectionMode)
|
||||
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
InferCtxtBuilder {
|
||||
global_tcx: self,
|
||||
arenas: ty::CtxtArenas::new(),
|
||||
tables: None,
|
||||
param_env: None,
|
||||
projection_mode: projection_mode,
|
||||
normalize: false
|
||||
}
|
||||
}
|
||||
|
||||
/// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck
|
||||
/// for MemCategorizationContext/ExprUseVisitor.
|
||||
/// If any inference functionality is used, ICEs will occur.
|
||||
pub fn borrowck_fake_infer_ctxt(self, param_env: ty::ParameterEnvironment<'gcx>)
|
||||
-> InferCtxt<'a, 'gcx, 'gcx> {
|
||||
InferCtxt {
|
||||
tcx: self,
|
||||
tables: InferTables::Global(&self.tables),
|
||||
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
|
||||
int_unification_table: RefCell::new(UnificationTable::new()),
|
||||
float_unification_table: RefCell::new(UnificationTable::new()),
|
||||
region_vars: RegionVarBindings::new(self),
|
||||
parameter_environment: param_env,
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
reported_trait_errors: RefCell::new(FnvHashSet()),
|
||||
normalize: false,
|
||||
projection_mode: ProjectionMode::AnyFinal,
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: self.sess.err_count()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
pub fn enter<F, R>(&'tcx mut self, f: F) -> R
|
||||
where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R
|
||||
{
|
||||
let new_tables;
|
||||
let tables = if let Some(tables) = tables {
|
||||
new_tables = RefCell::new(tables);
|
||||
&new_tables
|
||||
let InferCtxtBuilder {
|
||||
global_tcx,
|
||||
ref arenas,
|
||||
ref tables,
|
||||
ref mut param_env,
|
||||
projection_mode,
|
||||
normalize
|
||||
} = *self;
|
||||
let tables = if let Some(ref tables) = *tables {
|
||||
InferTables::Local(tables)
|
||||
} else {
|
||||
&tcx.tables
|
||||
InferTables::Global(&global_tcx.tables)
|
||||
};
|
||||
f(InferCtxt {
|
||||
let param_env = param_env.take().unwrap_or_else(|| {
|
||||
global_tcx.empty_parameter_environment()
|
||||
});
|
||||
global_tcx.enter_local(arenas, |tcx| f(InferCtxt {
|
||||
tcx: tcx,
|
||||
tables: tables,
|
||||
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
|
||||
int_unification_table: RefCell::new(UnificationTable::new()),
|
||||
float_unification_table: RefCell::new(UnificationTable::new()),
|
||||
region_vars: RegionVarBindings::new(tcx),
|
||||
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
|
||||
parameter_environment: param_env,
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
reported_trait_errors: RefCell::new(FnvHashSet()),
|
||||
normalize: false,
|
||||
normalize: normalize,
|
||||
projection_mode: projection_mode,
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: tcx.sess.err_count()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn enter_normalizing<F, R>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
projection_mode: ProjectionMode,
|
||||
f: F) -> R
|
||||
where F: for<'b> FnOnce(InferCtxt<'b, 'tcx, 'tcx>) -> R
|
||||
{
|
||||
InferCtxt::enter(tcx, None, None, projection_mode, |mut infcx| {
|
||||
infcx.normalize = true;
|
||||
f(infcx)
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -459,10 +544,54 @@ pub struct CombinedSnapshot {
|
|||
region_vars_snapshot: RegionSnapshot,
|
||||
}
|
||||
|
||||
/// Helper trait for shortening the lifetimes inside a
|
||||
/// value for post-type-checking normalization.
|
||||
pub trait TransNormalize<'gcx>: TypeFoldable<'gcx> {
|
||||
fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! items { ($($item:item)+) => ($($item)+) }
|
||||
macro_rules! impl_trans_normalize {
|
||||
($lt_gcx:tt, $($ty:ty),+) => {
|
||||
items!($(impl<$lt_gcx> TransNormalize<$lt_gcx> for $ty {
|
||||
fn trans_normalize<'a, 'tcx>(&self,
|
||||
infcx: &InferCtxt<'a, $lt_gcx, 'tcx>)
|
||||
-> Self {
|
||||
infcx.normalize_projections_in(self)
|
||||
}
|
||||
})+);
|
||||
}
|
||||
}
|
||||
|
||||
impl_trans_normalize!('gcx,
|
||||
Ty<'gcx>,
|
||||
&'gcx Substs<'gcx>,
|
||||
ty::FnSig<'gcx>,
|
||||
ty::FnOutput<'gcx>,
|
||||
&'gcx ty::BareFnTy<'gcx>,
|
||||
ty::ClosureSubsts<'gcx>,
|
||||
ty::PolyTraitRef<'gcx>
|
||||
);
|
||||
|
||||
impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
|
||||
fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self {
|
||||
match *self {
|
||||
LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx) },
|
||||
LvalueTy::Downcast { adt_def, substs, variant_index } => {
|
||||
LvalueTy::Downcast {
|
||||
adt_def: adt_def,
|
||||
substs: substs.trans_normalize(infcx),
|
||||
variant_index: variant_index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Callable from trans only!
|
||||
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
pub fn normalize_associated_type<T>(self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
where T: TransNormalize<'tcx>
|
||||
{
|
||||
debug!("normalize_associated_type(t={:?})", value);
|
||||
|
||||
|
|
@ -472,15 +601,15 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
return value;
|
||||
}
|
||||
|
||||
InferCtxt::enter(self, None, None, ProjectionMode::Any, |infcx| {
|
||||
infcx.normalize_projections_in(&value)
|
||||
self.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
|
||||
value.trans_normalize(&infcx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
fn normalize_projections_in<T>(&self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
fn normalize_projections_in<T>(&self, value: &T) -> T::Lifted
|
||||
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
|
||||
{
|
||||
let mut selcx = traits::SelectionContext::new(self);
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
|
|
@ -503,16 +632,21 @@ pub fn drain_fulfillment_cx_or_panic<T>(&self,
|
|||
span: Span,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
result: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
-> T::Lifted
|
||||
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
|
||||
{
|
||||
match self.drain_fulfillment_cx(fulfill_cx, result) {
|
||||
let when = "resolving bounds after type-checking";
|
||||
let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
|
||||
Ok(v) => v,
|
||||
Err(errors) => {
|
||||
span_bug!(
|
||||
span,
|
||||
"Encountered errors `{:?}` fulfilling during trans",
|
||||
errors);
|
||||
span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
|
||||
}
|
||||
};
|
||||
|
||||
match self.tcx.lift_to_global(&v) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1449,18 +1583,16 @@ pub fn drain_fulfillment_cx<T>(&self,
|
|||
self.resolve_type_vars_or_error(&ty)
|
||||
}
|
||||
|
||||
pub fn tables_are_tcx_tables(&self) -> bool {
|
||||
let tables: &RefCell<ty::Tables> = &self.tables;
|
||||
let tcx_tables: &RefCell<ty::Tables> = &self.tcx.tables;
|
||||
tables as *const _ as usize == tcx_tables as *const _ as usize
|
||||
}
|
||||
|
||||
pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
let ty = self.resolve_type_vars_if_possible(&ty);
|
||||
if let Some(ty) = self.tcx.lift_to_global(&ty) {
|
||||
// HACK(eddyb) Temporarily handle infer type in the global tcx.
|
||||
if !ty.needs_infer() &&
|
||||
!(ty.has_closure_types() && !self.tables_are_tcx_tables()) {
|
||||
// Even if the type may have no inference variables, during
|
||||
// type-checking closure types are in local tables only.
|
||||
let local_closures = match self.tables {
|
||||
InferTables::Local(_) => ty.has_closure_types(),
|
||||
InferTables::Global(_) => false
|
||||
};
|
||||
if !local_closures {
|
||||
return ty.moves_by_default(self.tcx.global_tcx(), self.param_env(), span);
|
||||
}
|
||||
}
|
||||
|
|
@ -1527,7 +1659,7 @@ pub fn drain_fulfillment_cx<T>(&self,
|
|||
// during trans, we see closure ids from other traits.
|
||||
// That may require loading the closure data out of the
|
||||
// cstore.
|
||||
Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id))
|
||||
Some(self.tcx.closure_kind(def_id))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1536,12 +1668,13 @@ pub fn drain_fulfillment_cx<T>(&self,
|
|||
substs: ty::ClosureSubsts<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
let closure_ty =
|
||||
ty::Tables::closure_type(self.tables,
|
||||
self.tcx,
|
||||
def_id,
|
||||
substs);
|
||||
if let InferTables::Local(tables) = self.tables {
|
||||
if let Some(ty) = tables.borrow().closure_tys.get(&def_id) {
|
||||
return ty.subst(self.tcx, substs.func_substs);
|
||||
}
|
||||
}
|
||||
|
||||
let closure_ty = self.tcx.closure_type(def_id, substs);
|
||||
if self.normalize {
|
||||
let closure_ty = self.tcx.erase_regions(&closure_ty);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct ItemVisitor<'a, 'tcx: 'a> {
|
|||
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
|
||||
fn visit_const(&mut self, item_id: ast::NodeId, expr: &hir::Expr) {
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
|
||||
InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::Any, |infcx| {
|
||||
self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
|
|
@ -49,7 +49,7 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
|
||||
impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
|
||||
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
|
||||
let intrinsic = match self.infcx.tcx.lookup_item_type(def_id).ty.sty {
|
||||
ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic,
|
||||
|
|
@ -58,7 +58,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
|
|||
intrinsic && self.infcx.tcx.item_name(def_id).as_str() == "transmute"
|
||||
}
|
||||
|
||||
fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::NodeId) {
|
||||
fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>, id: ast::NodeId) {
|
||||
let sk_from = SizeSkeleton::compute(from, self.infcx);
|
||||
let sk_to = SizeSkeleton::compute(to, self.infcx);
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
// Try to display a sensible error with as much information as possible.
|
||||
let skeleton_string = |ty: Ty<'tcx>, sk| {
|
||||
let skeleton_string = |ty: Ty<'gcx>, sk| {
|
||||
match sk {
|
||||
Ok(SizeSkeleton::Known(size)) => {
|
||||
format!("{} bits", size.bits())
|
||||
|
|
@ -114,7 +114,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
|
|||
impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
|
||||
// const, static and N in [T; N].
|
||||
fn visit_expr(&mut self, expr: &hir::Expr) {
|
||||
InferCtxt::enter(self.tcx, None, None, ProjectionMode::Any, |infcx| {
|
||||
self.tcx.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
|
|
@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
|
|||
span_bug!(s, "intrinsicck: closure outside of function")
|
||||
}
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
||||
InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::Any, |infcx| {
|
||||
self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
|
|
@ -153,7 +153,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'tcx, 'tcx> {
|
||||
impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &hir::Expr) {
|
||||
if let hir::ExprPath(..) = expr.node {
|
||||
match self.infcx.tcx.resolve_expr(expr) {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ use hir::def::*;
|
|||
use hir::pat_util;
|
||||
use ty::{self, TyCtxt, ParameterEnvironment};
|
||||
use traits::{self, ProjectionMode};
|
||||
use infer::InferCtxt;
|
||||
use ty::subst::Subst;
|
||||
use lint;
|
||||
use util::nodemap::NodeMap;
|
||||
|
|
@ -1488,8 +1487,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
|
||||
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
|
||||
let t_ret_subst = t_ret.subst(self.ir.tcx, ¶m_env.free_substs);
|
||||
let is_nil = InferCtxt::enter(self.ir.tcx, None, Some(param_env),
|
||||
ProjectionMode::Any, |infcx| {
|
||||
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
|
||||
ProjectionMode::Any).enter(|infcx| {
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ pub enum LvalueTy<'tcx> {
|
|||
variant_index: usize },
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LvalueTy<'tcx> {
|
||||
impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
|
||||
pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
|
||||
LvalueTy::Ty { ty: ty }
|
||||
}
|
||||
|
||||
pub fn to_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
|
||||
pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
LvalueTy::Ty { ty } =>
|
||||
ty,
|
||||
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx> LvalueTy<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn projection_ty(self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
elem: &LvalueElem<'tcx>)
|
||||
-> LvalueTy<'tcx>
|
||||
{
|
||||
|
|
@ -99,8 +99,8 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Mir<'tcx> {
|
||||
pub fn operand_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
impl<'a, 'gcx, 'tcx> Mir<'tcx> {
|
||||
pub fn operand_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
operand: &Operand<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
|
|
@ -110,7 +110,7 @@ impl<'a, 'tcx> Mir<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn binop_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pub fn binop_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
op: BinOp,
|
||||
lhs_ty: Ty<'tcx>,
|
||||
rhs_ty: Ty<'tcx>)
|
||||
|
|
@ -134,7 +134,7 @@ impl<'a, 'tcx> Mir<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lvalue_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pub fn lvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
lvalue: &Lvalue<'tcx>)
|
||||
-> LvalueTy<'tcx>
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@ impl<'a, 'tcx> Mir<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn rvalue_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pub fn rvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
rvalue: &Rvalue<'tcx>)
|
||||
-> Option<Ty<'tcx>>
|
||||
{
|
||||
|
|
@ -205,7 +205,7 @@ impl<'a, 'tcx> Mir<'tcx> {
|
|||
))
|
||||
}
|
||||
AggregateKind::Adt(def, _, substs) => {
|
||||
Some(def.type_scheme(tcx).ty.subst(tcx, substs))
|
||||
Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs))
|
||||
}
|
||||
AggregateKind::Closure(did, substs) => {
|
||||
Some(tcx.mk_closure_from_closure_substs(did, substs))
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ struct InferIsLocal(bool);
|
|||
|
||||
/// If there are types that satisfy both impls, returns a suitably-freshened
|
||||
/// `ImplHeader` with those types substituted
|
||||
pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx, 'tcx>,
|
||||
impl1_def_id: DefId,
|
||||
impl2_def_id: DefId)
|
||||
-> Option<ty::ImplHeader<'tcx>>
|
||||
pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
impl1_def_id: DefId,
|
||||
impl2_def_id: DefId)
|
||||
-> Option<ty::ImplHeader<'tcx>>
|
||||
{
|
||||
debug!("impl_can_satisfy(\
|
||||
impl1_def_id={:?}, \
|
||||
|
|
@ -41,10 +41,10 @@ pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx, 'tcx>,
|
|||
|
||||
/// Can both impl `a` and impl `b` be satisfied by a common type (including
|
||||
/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
|
||||
fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx, 'tcx>,
|
||||
a_def_id: DefId,
|
||||
b_def_id: DefId)
|
||||
-> Option<ty::ImplHeader<'tcx>>
|
||||
fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
a_def_id: DefId,
|
||||
b_def_id: DefId)
|
||||
-> Option<ty::ImplHeader<'tcx>>
|
||||
{
|
||||
debug!("overlap(a_def_id={:?}, b_def_id={:?})",
|
||||
a_def_id,
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
|
||||
|
||||
InferCtxt::enter(tcx, None, Some(elaborated_env), ProjectionMode::AnyFinal, |infcx| {
|
||||
tcx.infer_ctxt(None, Some(elaborated_env), ProjectionMode::AnyFinal).enter(|infcx| {
|
||||
let predicates = match fully_normalize(&infcx, cause,
|
||||
&infcx.parameter_environment.caller_bounds) {
|
||||
Ok(predicates) => predicates,
|
||||
|
|
@ -454,6 +454,11 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
}
|
||||
};
|
||||
|
||||
let predicates = match tcx.lift_to_global(&predicates) {
|
||||
Some(predicates) => predicates,
|
||||
None => return infcx.parameter_environment
|
||||
};
|
||||
|
||||
debug!("normalize_param_env_or_error: resolved predicates={:?}",
|
||||
predicates);
|
||||
|
||||
|
|
@ -461,10 +466,10 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
})
|
||||
}
|
||||
|
||||
pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
value: &T)
|
||||
-> Result<T, Vec<FulfillmentError<'tcx>>>
|
||||
pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
value: &T)
|
||||
-> Result<T, Vec<FulfillmentError<'tcx>>>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
debug!("fully_normalize(value={:?})", value);
|
||||
|
|
|
|||
|
|
@ -146,14 +146,21 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
.unwrap()
|
||||
.subst(tcx, &penv.free_substs);
|
||||
|
||||
InferCtxt::enter_normalizing(tcx, ProjectionMode::Topmost, |mut infcx| {
|
||||
tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).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 } = {
|
||||
let selcx = &mut SelectionContext::new(&infcx);
|
||||
traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
|
||||
};
|
||||
penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
|
||||
penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| {
|
||||
match tcx.lift_to_global(&o.predicate) {
|
||||
Some(predicate) => predicate,
|
||||
None => {
|
||||
bug!("specializes: obligation `{:?}` has inference types/regions", o);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// Install the parameter environment, taking the predicates of impl1 as assumptions:
|
||||
infcx.parameter_environment = penv;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use std::rc::Rc;
|
|||
use super::{OverlapError, specializes};
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::InferCtxt;
|
||||
use traits::{self, ProjectionMode};
|
||||
use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable};
|
||||
use ty::fast_reject::{self, SimplifiedType};
|
||||
|
|
@ -112,8 +111,8 @@ impl<'a, 'gcx, 'tcx> Children {
|
|||
let possible_sibling = *slot;
|
||||
|
||||
let tcx = tcx.global_tcx();
|
||||
let (le, ge) = InferCtxt::enter(tcx, None, None,
|
||||
ProjectionMode::Topmost, |infcx| {
|
||||
let (le, ge) = tcx.infer_ctxt(None, None,
|
||||
ProjectionMode::Topmost).enter(|infcx| {
|
||||
let overlap = traits::overlapping_impls(&infcx,
|
||||
possible_sibling,
|
||||
impl_def_id);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,58 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// For trans only.
|
||||
impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
|
||||
type Lifted = traits::Vtable<'tcx, ()>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
match self.clone() {
|
||||
traits::VtableImpl(traits::VtableImplData {
|
||||
impl_def_id,
|
||||
substs,
|
||||
nested
|
||||
}) => {
|
||||
tcx.lift(&substs).map(|substs| {
|
||||
traits::VtableImpl(traits::VtableImplData {
|
||||
impl_def_id: impl_def_id,
|
||||
substs: substs,
|
||||
nested: nested
|
||||
})
|
||||
})
|
||||
}
|
||||
traits::VtableDefaultImpl(t) => Some(traits::VtableDefaultImpl(t)),
|
||||
traits::VtableClosure(traits::VtableClosureData {
|
||||
closure_def_id,
|
||||
substs,
|
||||
nested
|
||||
}) => {
|
||||
tcx.lift(&substs).map(|substs| {
|
||||
traits::VtableClosure(traits::VtableClosureData {
|
||||
closure_def_id: closure_def_id,
|
||||
substs: substs,
|
||||
nested: nested
|
||||
})
|
||||
})
|
||||
}
|
||||
traits::VtableFnPointer(ty) => {
|
||||
tcx.lift(&ty).map(traits::VtableFnPointer)
|
||||
}
|
||||
traits::VtableParam(n) => Some(traits::VtableParam(n)),
|
||||
traits::VtableBuiltin(d) => Some(traits::VtableBuiltin(d)),
|
||||
traits::VtableObject(traits::VtableObjectData {
|
||||
upcast_trait_ref,
|
||||
vtable_base
|
||||
}) => {
|
||||
tcx.lift(&upcast_trait_ref).map(|trait_ref| {
|
||||
traits::VtableObject(traits::VtableObjectData {
|
||||
upcast_trait_ref: trait_ref,
|
||||
vtable_base: vtable_base
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TypeFoldable implementations.
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use middle::free_region::FreeRegionMap;
|
|||
use middle::region::RegionMaps;
|
||||
use middle::resolve_lifetime;
|
||||
use middle::stability;
|
||||
use ty::subst::{self, Subst, Substs};
|
||||
use ty::subst::{self, Substs};
|
||||
use traits;
|
||||
use ty::{self, TraitRef, Ty, TypeAndMut};
|
||||
use ty::{TyS, TypeVariants};
|
||||
|
|
@ -41,6 +41,7 @@ use arena::TypedArena;
|
|||
use std::borrow::Borrow;
|
||||
use std::cell::{Cell, RefCell, Ref};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{self, Name, NodeId};
|
||||
|
|
@ -82,22 +83,22 @@ impl<'tcx> CtxtArenas<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct CtxtInterners<'tcx> {
|
||||
pub struct CtxtInterners<'tcx> {
|
||||
/// The arenas that types etc are allocated from.
|
||||
arenas: &'tcx CtxtArenas<'tcx>,
|
||||
|
||||
/// Specifically use a speedy hash algorithm for these hash sets,
|
||||
/// they're accessed quite often.
|
||||
type_: RefCell<FnvHashSet<InternedTy<'tcx>>>,
|
||||
type_list: RefCell<FnvHashSet<InternedTyList<'tcx>>>,
|
||||
substs: RefCell<FnvHashSet<InternedSubsts<'tcx>>>,
|
||||
bare_fn: RefCell<FnvHashSet<&'tcx BareFnTy<'tcx>>>,
|
||||
region: RefCell<FnvHashSet<InternedRegion<'tcx>>>,
|
||||
type_: RefCell<FnvHashSet<Interned<'tcx, TyS<'tcx>>>>,
|
||||
type_list: RefCell<FnvHashSet<Interned<'tcx, [Ty<'tcx>]>>>,
|
||||
substs: RefCell<FnvHashSet<Interned<'tcx, Substs<'tcx>>>>,
|
||||
bare_fn: RefCell<FnvHashSet<Interned<'tcx, BareFnTy<'tcx>>>>,
|
||||
region: RefCell<FnvHashSet<Interned<'tcx, Region>>>,
|
||||
stability: RefCell<FnvHashSet<&'tcx attr::Stability>>,
|
||||
layout: RefCell<FnvHashSet<&'tcx Layout>>,
|
||||
}
|
||||
|
||||
impl<'tcx> CtxtInterners<'tcx> {
|
||||
impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
|
||||
fn new(arenas: &'tcx CtxtArenas<'tcx>) -> CtxtInterners<'tcx> {
|
||||
CtxtInterners {
|
||||
arenas: arenas,
|
||||
|
|
@ -111,24 +112,58 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn intern_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
|
||||
/// Intern a type. global_interners is Some only if this is
|
||||
/// a local interner and global_interners is its counterpart.
|
||||
fn intern_ty(&self, st: TypeVariants<'tcx>,
|
||||
global_interners: Option<&CtxtInterners<'gcx>>)
|
||||
-> Ty<'tcx> {
|
||||
let ty = {
|
||||
let mut interner = self.type_.borrow_mut();
|
||||
match interner.get(&st) {
|
||||
Some(&InternedTy { ty }) => return ty,
|
||||
None => ()
|
||||
let global_interner = global_interners.map(|interners| {
|
||||
interners.type_.borrow_mut()
|
||||
});
|
||||
if let Some(&Interned(ty)) = interner.get(&st) {
|
||||
return ty;
|
||||
}
|
||||
if let Some(ref interner) = global_interner {
|
||||
if let Some(&Interned(ty)) = interner.get(&st) {
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
|
||||
let flags = super::flags::FlagComputation::for_sty(&st);
|
||||
|
||||
// Don't be &mut TyS.
|
||||
let ty: Ty = self.arenas.type_.alloc(TyS {
|
||||
let ty_struct = TyS {
|
||||
sty: st,
|
||||
flags: Cell::new(flags.flags),
|
||||
region_depth: flags.depth,
|
||||
});
|
||||
};
|
||||
|
||||
interner.insert(InternedTy { ty: ty });
|
||||
// HACK(eddyb) Depend on flags being accurate to
|
||||
// determine that all contents are in the global tcx.
|
||||
// See comments on Lift for why we can't use that.
|
||||
if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
|
||||
if let Some(interner) = global_interners {
|
||||
let ty_struct: TyS<'gcx> = unsafe {
|
||||
mem::transmute(ty_struct)
|
||||
};
|
||||
let ty: Ty<'gcx> = interner.arenas.type_.alloc(ty_struct);
|
||||
global_interner.unwrap().insert(Interned(ty));
|
||||
return ty;
|
||||
}
|
||||
} else {
|
||||
// Make sure we don't end up with inference
|
||||
// types/regions in the global tcx.
|
||||
if global_interners.is_none() {
|
||||
drop(interner);
|
||||
bug!("Attempted to intern `{:?}` which contains \
|
||||
inference types/regions in the global type context",
|
||||
&ty_struct);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't be &mut TyS.
|
||||
let ty: Ty<'tcx> = self.arenas.type_.alloc(ty_struct);
|
||||
interner.insert(Interned(ty));
|
||||
ty
|
||||
};
|
||||
|
||||
|
|
@ -212,45 +247,11 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
|
|||
fru_field_types: NodeMap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn closure_kind(this: &RefCell<Self>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> ty::ClosureKind {
|
||||
// If this is a local def-id, it should be inserted into the
|
||||
// tables by typeck; else, it will be retreived from
|
||||
// the external crate metadata.
|
||||
if let Some(&kind) = this.borrow().closure_kinds.get(&def_id) {
|
||||
return kind;
|
||||
}
|
||||
|
||||
let kind = tcx.sess.cstore.closure_kind(def_id);
|
||||
this.borrow_mut().closure_kinds.insert(def_id, kind);
|
||||
kind
|
||||
}
|
||||
|
||||
pub fn closure_type(this: &RefCell<Self>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
substs: ClosureSubsts<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
// If this is a local def-id, it should be inserted into the
|
||||
// tables by typeck; else, it will be retreived from
|
||||
// the external crate metadata.
|
||||
if let Some(ty) = this.borrow().closure_tys.get(&def_id) {
|
||||
return ty.subst(tcx, substs.func_substs);
|
||||
}
|
||||
|
||||
let ty = tcx.sess.cstore.closure_ty(tcx.global_tcx(), def_id);
|
||||
this.borrow_mut().closure_tys.insert(def_id, ty.clone());
|
||||
ty.subst(tcx, substs.func_substs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> CommonTypes<'tcx> {
|
||||
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
|
||||
let mk = |sty| interners.intern_ty(sty);
|
||||
let mk = |sty| interners.intern_ty(sty, None);
|
||||
CommonTypes {
|
||||
bool: mk(TyBool),
|
||||
char: mk(TyChar),
|
||||
|
|
@ -558,13 +559,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
interned
|
||||
}
|
||||
|
||||
pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
|
||||
if let Some(st) = self.interners.stability.borrow().get(&stab) {
|
||||
pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
|
||||
if let Some(st) = self.global_interners.stability.borrow().get(&stab) {
|
||||
return st;
|
||||
}
|
||||
|
||||
let interned = self.interners.arenas.stability.alloc(stab);
|
||||
if let Some(prev) = self.interners.stability
|
||||
let interned = self.global_interners.arenas.stability.alloc(stab);
|
||||
if let Some(prev) = self.global_interners.stability
|
||||
.borrow_mut()
|
||||
.replace(interned) {
|
||||
bug!("Tried to overwrite interned Stability: {:?}", prev)
|
||||
|
|
@ -572,13 +573,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
interned
|
||||
}
|
||||
|
||||
pub fn intern_layout(self, layout: Layout) -> &'tcx Layout {
|
||||
if let Some(layout) = self.interners.layout.borrow().get(&layout) {
|
||||
pub fn intern_layout(self, layout: Layout) -> &'gcx Layout {
|
||||
if let Some(layout) = self.global_interners.layout.borrow().get(&layout) {
|
||||
return layout;
|
||||
}
|
||||
|
||||
let interned = self.interners.arenas.layout.alloc(layout);
|
||||
if let Some(prev) = self.interners.layout
|
||||
let interned = self.global_interners.arenas.layout.alloc(layout);
|
||||
if let Some(prev) = self.global_interners.layout
|
||||
.borrow_mut()
|
||||
.replace(interned) {
|
||||
bug!("Tried to overwrite interned Layout: {:?}", prev)
|
||||
|
|
@ -635,7 +636,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
let common_types = CommonTypes::new(&interners);
|
||||
let dep_graph = map.dep_graph.clone();
|
||||
let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
|
||||
tls::enter(GlobalCtxt {
|
||||
tls::enter_global(GlobalCtxt {
|
||||
global_interners: interners,
|
||||
dep_graph: dep_graph.clone(),
|
||||
types: common_types,
|
||||
|
|
@ -690,11 +691,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
|
||||
/// Call the closure with a local `TyCtxt` using the given arenas.
|
||||
pub fn enter_local<F, R>(&self, arenas: &'tcx CtxtArenas<'tcx>, f: F) -> R
|
||||
where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
|
||||
{
|
||||
let interners = CtxtInterners::new(arenas);
|
||||
tls::enter(self, &interners, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait implemented for all X<'a> types which can be safely and
|
||||
/// efficiently converted to X<'tcx> as long as they are part of the
|
||||
/// provided TyCtxt<'tcx>.
|
||||
/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
|
||||
/// by looking them up in their respective interners.
|
||||
///
|
||||
/// However, this is still not the best implementation as it does
|
||||
/// need to compare the components, even for interned values.
|
||||
/// It would be more efficient if TypedArena provided a way to
|
||||
/// determine whether the address is in the allocated range.
|
||||
///
|
||||
/// None is returned if the value or one of the components is not part
|
||||
/// of the provided context.
|
||||
/// For Ty, None can be returned if either the type interner doesn't
|
||||
|
|
@ -709,7 +726,7 @@ pub trait Lift<'tcx> {
|
|||
impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
|
||||
type Lifted = Ty<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
|
||||
if let Some(&InternedTy { ty }) = tcx.interners.type_.borrow().get(&self.sty) {
|
||||
if let Some(&Interned(ty)) = tcx.interners.type_.borrow().get(&self.sty) {
|
||||
if *self as *const _ == ty as *const _ {
|
||||
return Some(ty);
|
||||
}
|
||||
|
|
@ -726,7 +743,7 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
|
|||
impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
|
||||
type Lifted = &'tcx Substs<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
|
||||
if let Some(&InternedSubsts { substs }) = tcx.interners.substs.borrow().get(*self) {
|
||||
if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(*self) {
|
||||
if *self as *const _ == substs as *const _ {
|
||||
return Some(substs);
|
||||
}
|
||||
|
|
@ -743,7 +760,7 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
|
|||
impl<'a, 'tcx> Lift<'tcx> for &'a Region {
|
||||
type Lifted = &'tcx Region;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Region> {
|
||||
if let Some(&InternedRegion { region }) = tcx.interners.region.borrow().get(*self) {
|
||||
if let Some(&Interned(region)) = tcx.interners.region.borrow().get(*self) {
|
||||
if *self as *const _ == region as *const _ {
|
||||
return Some(region);
|
||||
}
|
||||
|
|
@ -760,7 +777,7 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Region {
|
|||
impl<'a, 'tcx> Lift<'tcx> for &'a [Ty<'a>] {
|
||||
type Lifted = &'tcx [Ty<'tcx>];
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx [Ty<'tcx>]> {
|
||||
if let Some(&InternedTyList { list }) = tcx.interners.type_list.borrow().get(*self) {
|
||||
if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(*self) {
|
||||
if *self as *const _ == list as *const _ {
|
||||
return Some(list);
|
||||
}
|
||||
|
|
@ -774,21 +791,41 @@ impl<'a, 'tcx> Lift<'tcx> for &'a [Ty<'a>] {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
|
||||
type Lifted = &'tcx BareFnTy<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
|
||||
-> Option<&'tcx BareFnTy<'tcx>> {
|
||||
if let Some(&Interned(fty)) = tcx.interners.bare_fn.borrow().get(*self) {
|
||||
if *self as *const _ == fty as *const _ {
|
||||
return Some(fty);
|
||||
}
|
||||
}
|
||||
// Also try in the global tcx if we're not that.
|
||||
if !tcx.is_global() {
|
||||
self.lift_to_tcx(tcx.global_tcx())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub mod tls {
|
||||
use super::{GlobalCtxt, TyCtxt};
|
||||
use super::{CtxtInterners, GlobalCtxt, TyCtxt};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use syntax::codemap;
|
||||
|
||||
/// Marker type used for the scoped TLS slot.
|
||||
/// Marker types used for the scoped TLS slot.
|
||||
/// The type context cannot be used directly because the scoped TLS
|
||||
/// in libstd doesn't allow types generic over lifetimes.
|
||||
enum ThreadLocalGlobalCtxt {}
|
||||
enum ThreadLocalInterners {}
|
||||
|
||||
thread_local! {
|
||||
static TLS_TCX: Cell<Option<*const ThreadLocalGlobalCtxt>> = Cell::new(None)
|
||||
static TLS_TCX: Cell<Option<(*const ThreadLocalGlobalCtxt,
|
||||
*const ThreadLocalInterners)>> = Cell::new(None)
|
||||
}
|
||||
|
||||
fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
|
@ -797,42 +834,55 @@ pub mod tls {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn enter<'tcx, F, R>(gcx: GlobalCtxt<'tcx>, f: F) -> R
|
||||
where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> R
|
||||
pub fn enter_global<'gcx, F, R>(gcx: GlobalCtxt<'gcx>, f: F) -> R
|
||||
where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'gcx>) -> R
|
||||
{
|
||||
codemap::SPAN_DEBUG.with(|span_dbg| {
|
||||
let original_span_debug = span_dbg.get();
|
||||
span_dbg.set(span_debug);
|
||||
let tls_ptr = &gcx as *const _ as *const ThreadLocalGlobalCtxt;
|
||||
let result = TLS_TCX.with(|tls| {
|
||||
let prev = tls.get();
|
||||
tls.set(Some(tls_ptr));
|
||||
let ret = f(gcx.global_tcx());
|
||||
tls.set(prev);
|
||||
ret
|
||||
});
|
||||
let result = enter(&gcx, &gcx.global_interners, f);
|
||||
span_dbg.set(original_span_debug);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with<F, R>(f: F) -> R
|
||||
where F: for<'a, 'tcx> FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> R
|
||||
pub fn enter<'a, 'gcx: 'tcx, 'tcx, F, R>(gcx: &'a GlobalCtxt<'gcx>,
|
||||
interners: &'a CtxtInterners<'tcx>,
|
||||
f: F) -> R
|
||||
where F: FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
|
||||
{
|
||||
TLS_TCX.with(|gcx| {
|
||||
let gcx = gcx.get().unwrap();
|
||||
let gcx_ptr = gcx as *const _ as *const ThreadLocalGlobalCtxt;
|
||||
let interners_ptr = interners as *const _ as *const ThreadLocalInterners;
|
||||
TLS_TCX.with(|tls| {
|
||||
let prev = tls.get();
|
||||
tls.set(Some((gcx_ptr, interners_ptr)));
|
||||
let ret = f(TyCtxt {
|
||||
gcx: gcx,
|
||||
interners: interners
|
||||
});
|
||||
tls.set(prev);
|
||||
ret
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with<F, R>(f: F) -> R
|
||||
where F: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
|
||||
{
|
||||
TLS_TCX.with(|tcx| {
|
||||
let (gcx, interners) = tcx.get().unwrap();
|
||||
let gcx = unsafe { &*(gcx as *const GlobalCtxt) };
|
||||
let interners = unsafe { &*(interners as *const CtxtInterners) };
|
||||
f(TyCtxt {
|
||||
gcx: gcx,
|
||||
interners: &gcx.global_interners
|
||||
interners: interners
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_opt<F, R>(f: F) -> R
|
||||
where F: for<'a, 'tcx> FnOnce(Option<TyCtxt<'a, 'tcx, 'tcx>>) -> R
|
||||
where F: for<'a, 'gcx, 'tcx> FnOnce(Option<TyCtxt<'a, 'gcx, 'tcx>>) -> R
|
||||
{
|
||||
if TLS_TCX.with(|gcx| gcx.get().is_some()) {
|
||||
if TLS_TCX.with(|tcx| tcx.get().is_some()) {
|
||||
with(|v| f(Some(v)))
|
||||
} else {
|
||||
f(None)
|
||||
|
|
@ -847,7 +897,7 @@ macro_rules! sty_debug_print {
|
|||
#[allow(non_snake_case)]
|
||||
mod inner {
|
||||
use ty::{self, TyCtxt};
|
||||
use ty::context::InternedTy;
|
||||
use ty::context::Interned;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct DebugStat {
|
||||
|
|
@ -865,7 +915,7 @@ macro_rules! sty_debug_print {
|
|||
$(let mut $variant = total;)*
|
||||
|
||||
|
||||
for &InternedTy { ty: t } in tcx.interners.type_.borrow().iter() {
|
||||
for &Interned(t) in tcx.interners.type_.borrow().iter() {
|
||||
let variant = match t.sty {
|
||||
ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
|
||||
ty::TyFloat(..) | ty::TyStr => continue,
|
||||
|
|
@ -920,68 +970,127 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
|
||||
/// An entry in the type interner.
|
||||
struct InternedTy<'tcx> {
|
||||
ty: Ty<'tcx>
|
||||
}
|
||||
/// An entry in an interner.
|
||||
struct Interned<'tcx, T: 'tcx+?Sized>(&'tcx T);
|
||||
|
||||
// NB: An InternedTy compares and hashes as a sty.
|
||||
impl<'tcx> PartialEq for InternedTy<'tcx> {
|
||||
fn eq(&self, other: &InternedTy<'tcx>) -> bool {
|
||||
self.ty.sty == other.ty.sty
|
||||
// NB: An Interned<Ty> compares and hashes as a sty.
|
||||
impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
|
||||
fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
|
||||
self.0.sty == other.0.sty
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Eq for InternedTy<'tcx> {}
|
||||
impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {}
|
||||
|
||||
impl<'tcx> Hash for InternedTy<'tcx> {
|
||||
impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
|
||||
fn hash<H: Hasher>(&self, s: &mut H) {
|
||||
self.ty.sty.hash(s)
|
||||
self.0.sty.hash(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<TypeVariants<'lcx>> for InternedTy<'tcx> {
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<TypeVariants<'lcx>> for Interned<'tcx, TyS<'tcx>> {
|
||||
fn borrow<'a>(&'a self) -> &'a TypeVariants<'lcx> {
|
||||
&self.ty.sty
|
||||
&self.0.sty
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry in the type list interner.
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct InternedTyList<'tcx> {
|
||||
list: &'tcx [Ty<'tcx>]
|
||||
}
|
||||
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for InternedTyList<'tcx> {
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, [Ty<'tcx>]> {
|
||||
fn borrow<'a>(&'a self) -> &'a [Ty<'lcx>] {
|
||||
self.list
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry in the substs interner.
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct InternedSubsts<'tcx> {
|
||||
substs: &'tcx Substs<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<Substs<'lcx>> for InternedSubsts<'tcx> {
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<Substs<'lcx>> for Interned<'tcx, Substs<'tcx>> {
|
||||
fn borrow<'a>(&'a self) -> &'a Substs<'lcx> {
|
||||
self.substs
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry in the region interner.
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct InternedRegion<'tcx> {
|
||||
region: &'tcx Region
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<BareFnTy<'lcx>> for Interned<'tcx, BareFnTy<'tcx>> {
|
||||
fn borrow<'a>(&'a self) -> &'a BareFnTy<'lcx> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Borrow<Region> for InternedRegion<'tcx> {
|
||||
impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
|
||||
fn borrow<'a>(&'a self) -> &'a Region {
|
||||
self.region
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! items { ($($item:item)+) => ($($item)+) }
|
||||
macro_rules! impl_interners {
|
||||
($lt_tcx:tt, $($name:ident: $method:ident($alloc:ty, $needs_infer:expr)-> $ty:ty),+) => {
|
||||
items!($(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<$lt_tcx> Eq for Interned<$lt_tcx, $ty> {}
|
||||
|
||||
impl<$lt_tcx> Hash for Interned<$lt_tcx, $ty> {
|
||||
fn hash<H: Hasher>(&self, s: &mut H) {
|
||||
self.0.hash(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
|
||||
pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
|
||||
if let Some(i) = self.interners.$name.borrow().get::<$ty>(&v) {
|
||||
return i.0;
|
||||
}
|
||||
if !self.is_global() {
|
||||
if let Some(i) = self.global_interners.$name.borrow().get::<$ty>(&v) {
|
||||
return i.0;
|
||||
}
|
||||
}
|
||||
|
||||
// HACK(eddyb) Depend on flags being accurate to
|
||||
// determine that all contents are in the global tcx.
|
||||
// See comments on Lift for why we can't use that.
|
||||
if !($needs_infer)(&v) {
|
||||
if !self.is_global() {
|
||||
let v = unsafe {
|
||||
mem::transmute(v)
|
||||
};
|
||||
let i = self.global_interners.arenas.$name.alloc(v);
|
||||
self.global_interners.$name.borrow_mut().insert(Interned(i));
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
// Make sure we don't end up with inference
|
||||
// types/regions in the global tcx.
|
||||
if self.is_global() {
|
||||
bug!("Attempted to intern `{:?}` which contains \
|
||||
inference types/regions in the global type context",
|
||||
v);
|
||||
}
|
||||
}
|
||||
|
||||
let i = self.interners.arenas.$name.alloc(v);
|
||||
self.interners.$name.borrow_mut().insert(Interned(i));
|
||||
i
|
||||
}
|
||||
})+);
|
||||
}
|
||||
}
|
||||
|
||||
fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
|
||||
x.has_type_flags(ty::TypeFlags::KEEP_IN_LOCAL_TCX)
|
||||
}
|
||||
|
||||
impl_interners!('tcx,
|
||||
type_list: mk_type_list(Vec<Ty<'tcx>>, keep_local) -> [Ty<'tcx>],
|
||||
substs: mk_substs(Substs<'tcx>, |substs: &Substs| {
|
||||
keep_local(&substs.types) || keep_local(&substs.regions)
|
||||
}) -> Substs<'tcx>,
|
||||
bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| {
|
||||
keep_local(&fty.sig)
|
||||
}) -> BareFnTy<'tcx>,
|
||||
region: mk_region(Region, keep_local) -> Region
|
||||
);
|
||||
|
||||
fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
|
||||
bounds.is_empty() ||
|
||||
bounds[1..].iter().enumerate().all(
|
||||
|
|
@ -989,31 +1098,6 @@ fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn mk_type_list(self, list: Vec<Ty<'tcx>>) -> &'tcx [Ty<'tcx>] {
|
||||
if let Some(interned) = self.interners.type_list.borrow().get(&list[..]) {
|
||||
return interned.list;
|
||||
}
|
||||
|
||||
let list = self.interners.arenas.type_list.alloc(list);
|
||||
self.interners.type_list.borrow_mut().insert(InternedTyList {
|
||||
list: list
|
||||
});
|
||||
list
|
||||
}
|
||||
|
||||
// Type constructors
|
||||
pub fn mk_substs(self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> {
|
||||
if let Some(interned) = self.interners.substs.borrow().get(&substs) {
|
||||
return interned.substs;
|
||||
}
|
||||
|
||||
let substs = self.interners.arenas.substs.alloc(substs);
|
||||
self.interners.substs.borrow_mut().insert(InternedSubsts {
|
||||
substs: substs
|
||||
});
|
||||
substs
|
||||
}
|
||||
|
||||
/// Create an unsafe fn ty based on a safe fn ty.
|
||||
pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
|
||||
assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
|
||||
|
|
@ -1024,32 +1108,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
}))
|
||||
}
|
||||
|
||||
pub fn mk_bare_fn(self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
|
||||
if let Some(bare_fn) = self.interners.bare_fn.borrow().get(&bare_fn) {
|
||||
return *bare_fn;
|
||||
}
|
||||
|
||||
let bare_fn = self.interners.arenas.bare_fn.alloc(bare_fn);
|
||||
self.interners.bare_fn.borrow_mut().insert(bare_fn);
|
||||
bare_fn
|
||||
}
|
||||
|
||||
pub fn mk_region(self, region: Region) -> &'tcx Region {
|
||||
if let Some(interned) = self.interners.region.borrow().get(®ion) {
|
||||
return interned.region;
|
||||
}
|
||||
|
||||
let region = self.interners.arenas.region.alloc(region);
|
||||
self.interners.region.borrow_mut().insert(InternedRegion {
|
||||
region: region
|
||||
});
|
||||
region
|
||||
}
|
||||
|
||||
// Interns a type/name combination, stores the resulting box in cx.interners,
|
||||
// and returns the box as cast to an unsafe ptr (see comments for Ty above).
|
||||
pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
|
||||
self.interners.intern_ty(st)
|
||||
let global_interners = if !self.is_global() {
|
||||
Some(&self.global_interners)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.interners.intern_ty(st, global_interners)
|
||||
}
|
||||
|
||||
pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
|
||||
|
|
|
|||
|
|
@ -90,9 +90,15 @@ impl FlagComputation {
|
|||
self.add_tys(&substs.upvar_tys);
|
||||
}
|
||||
|
||||
&ty::TyInfer(_) => {
|
||||
&ty::TyInfer(infer) => {
|
||||
self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
|
||||
self.add_flags(TypeFlags::HAS_TY_INFER)
|
||||
self.add_flags(TypeFlags::HAS_TY_INFER);
|
||||
match infer {
|
||||
ty::FreshTy(_) |
|
||||
ty::FreshIntTy(_) |
|
||||
ty::FreshFloatTy(_) => {}
|
||||
_ => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
|
||||
}
|
||||
}
|
||||
|
||||
&ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => {
|
||||
|
|
@ -171,7 +177,10 @@ impl FlagComputation {
|
|||
fn add_region(&mut self, r: ty::Region) {
|
||||
match r {
|
||||
ty::ReVar(..) |
|
||||
ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
|
||||
ty::ReSkolemized(..) => {
|
||||
self.add_flags(TypeFlags::HAS_RE_INFER);
|
||||
self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX);
|
||||
}
|
||||
ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
|
||||
ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
|
||||
ty::ReStatic => {}
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ pub struct Struct {
|
|||
pub offset_after_field: Vec<Size>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Struct {
|
||||
impl<'a, 'gcx, 'tcx> Struct {
|
||||
pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {
|
||||
Struct {
|
||||
align: if packed { dl.i8_align } else { dl.aggregate_align },
|
||||
|
|
@ -479,9 +479,9 @@ impl<'a, 'tcx> Struct {
|
|||
/// Extend the Struct with more fields.
|
||||
pub fn extend<I>(&mut self, dl: &TargetDataLayout,
|
||||
fields: I,
|
||||
scapegoat: Ty<'tcx>)
|
||||
-> Result<(), LayoutError<'tcx>>
|
||||
where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
|
||||
scapegoat: Ty<'gcx>)
|
||||
-> Result<(), LayoutError<'gcx>>
|
||||
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
|
||||
self.offset_after_field.reserve(fields.size_hint().0);
|
||||
|
||||
for field in fields {
|
||||
|
|
@ -528,8 +528,8 @@ impl<'a, 'tcx> Struct {
|
|||
|
||||
/// Determine whether a structure would be zero-sized, given its fields.
|
||||
pub fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
|
||||
-> Result<bool, LayoutError<'tcx>>
|
||||
where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
|
||||
-> Result<bool, LayoutError<'gcx>>
|
||||
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
|
||||
for field in fields {
|
||||
let field = field?;
|
||||
if field.is_unsized() || field.size(dl).bytes() > 0 {
|
||||
|
|
@ -542,10 +542,10 @@ impl<'a, 'tcx> Struct {
|
|||
/// Find the path leading to a non-zero leaf field, starting from
|
||||
/// the given type and recursing through aggregates.
|
||||
// FIXME(eddyb) track value ranges and traverse already optimized enums.
|
||||
pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> Result<Option<FieldPath>, LayoutError<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
ty: Ty<'gcx>)
|
||||
-> Result<Option<FieldPath>, LayoutError<'gcx>> {
|
||||
let tcx = infcx.tcx.global_tcx();
|
||||
match (ty.layout(infcx)?, &ty.sty) {
|
||||
(&Scalar { non_zero: true, .. }, _) => Ok(Some(vec![])),
|
||||
(&FatPointer { non_zero: true, .. }, _) => {
|
||||
|
|
@ -600,10 +600,10 @@ impl<'a, 'tcx> Struct {
|
|||
|
||||
/// Find the path leading to a non-zero leaf field, starting from
|
||||
/// the given set of fields and recursing through aggregates.
|
||||
pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
|
||||
pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
fields: I)
|
||||
-> Result<Option<FieldPath>, LayoutError<'tcx>>
|
||||
where I: Iterator<Item=Ty<'tcx>> {
|
||||
-> Result<Option<FieldPath>, LayoutError<'gcx>>
|
||||
where I: Iterator<Item=Ty<'gcx>> {
|
||||
for (i, ty) in fields.enumerate() {
|
||||
if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? {
|
||||
path.push(i as u32);
|
||||
|
|
@ -736,9 +736,9 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
|||
}
|
||||
|
||||
/// Helper function for normalizing associated types in an inference context.
|
||||
fn normalize_associated_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
ty: Ty<'gcx>)
|
||||
-> Ty<'gcx> {
|
||||
if !ty.has_projection_types() {
|
||||
return ty;
|
||||
}
|
||||
|
|
@ -757,11 +757,11 @@ fn normalize_associated_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
|
|||
infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Layout {
|
||||
pub fn compute_uncached(ty: Ty<'tcx>,
|
||||
infcx: &InferCtxt<'a, 'tcx, 'tcx>)
|
||||
-> Result<Layout, LayoutError<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
impl<'a, 'gcx, 'tcx> Layout {
|
||||
pub fn compute_uncached(ty: Ty<'gcx>,
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Result<Layout, LayoutError<'gcx>> {
|
||||
let tcx = infcx.tcx.global_tcx();
|
||||
let dl = &tcx.data_layout;
|
||||
assert!(!ty.has_infer_types());
|
||||
|
||||
|
|
@ -1220,10 +1220,10 @@ pub enum SizeSkeleton<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> SizeSkeleton<'tcx> {
|
||||
pub fn compute(ty: Ty<'tcx>, infcx: &InferCtxt<'a, 'tcx, 'tcx>)
|
||||
-> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
|
||||
pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Result<SizeSkeleton<'gcx>, LayoutError<'gcx>> {
|
||||
let tcx = infcx.tcx.global_tcx();
|
||||
assert!(!ty.has_infer_types());
|
||||
|
||||
// First try computing a static layout.
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ pub struct ImplHeader<'tcx> {
|
|||
pub predicates: Vec<Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ImplHeader<'tcx> {
|
||||
pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'tcx, 'tcx>,
|
||||
impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> {
|
||||
pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'gcx, 'tcx>,
|
||||
impl_def_id: DefId)
|
||||
-> ImplHeader<'tcx>
|
||||
{
|
||||
|
|
@ -524,6 +524,10 @@ bitflags! {
|
|||
// that are local to a particular fn
|
||||
const HAS_LOCAL_NAMES = 1 << 9,
|
||||
|
||||
// Present if the type belongs in a local type context.
|
||||
// Only set for TyInfer other than Fresh.
|
||||
const KEEP_IN_LOCAL_TCX = 1 << 10,
|
||||
|
||||
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
|
||||
TypeFlags::HAS_SELF.bits |
|
||||
TypeFlags::HAS_RE_EARLY_BOUND.bits,
|
||||
|
|
@ -540,7 +544,8 @@ bitflags! {
|
|||
TypeFlags::HAS_TY_ERR.bits |
|
||||
TypeFlags::HAS_PROJECTION.bits |
|
||||
TypeFlags::HAS_TY_CLOSURE.bits |
|
||||
TypeFlags::HAS_LOCAL_NAMES.bits,
|
||||
TypeFlags::HAS_LOCAL_NAMES.bits |
|
||||
TypeFlags::KEEP_IN_LOCAL_TCX.bits,
|
||||
|
||||
// Caches for type_is_sized, type_moves_by_default
|
||||
const SIZEDNESS_CACHED = 1 << 16,
|
||||
|
|
@ -2715,15 +2720,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
|
||||
Tables::closure_kind(&self.tables, self.global_tcx(), def_id)
|
||||
// If this is a local def-id, it should be inserted into the
|
||||
// tables by typeck; else, it will be retreived from
|
||||
// the external crate metadata.
|
||||
if let Some(&kind) = self.tables.borrow().closure_kinds.get(&def_id) {
|
||||
return kind;
|
||||
}
|
||||
|
||||
let kind = self.sess.cstore.closure_kind(def_id);
|
||||
self.tables.borrow_mut().closure_kinds.insert(def_id, kind);
|
||||
kind
|
||||
}
|
||||
|
||||
pub fn closure_type(self,
|
||||
def_id: DefId,
|
||||
substs: ClosureSubsts<'gcx>)
|
||||
-> ty::ClosureTy<'gcx>
|
||||
substs: ClosureSubsts<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
Tables::closure_type(&self.tables, self.global_tcx(), def_id, substs)
|
||||
// If this is a local def-id, it should be inserted into the
|
||||
// tables by typeck; else, it will be retreived from
|
||||
// the external crate metadata.
|
||||
if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) {
|
||||
return ty.subst(self, substs.func_substs);
|
||||
}
|
||||
|
||||
let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
|
||||
self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone());
|
||||
ty.subst(self, substs.func_substs)
|
||||
}
|
||||
|
||||
/// Given the def_id of an impl, return the def_id of the trait it implements.
|
||||
|
|
|
|||
|
|
@ -131,6 +131,41 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
|
||||
type Lifted = ty::Predicate<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref binder) => {
|
||||
tcx.lift(binder).map(ty::Predicate::Trait)
|
||||
}
|
||||
ty::Predicate::Equate(ref binder) => {
|
||||
tcx.lift(binder).map(ty::Predicate::Equate)
|
||||
}
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
tcx.lift(binder).map(ty::Predicate::RegionOutlives)
|
||||
}
|
||||
ty::Predicate::TypeOutlives(ref binder) => {
|
||||
tcx.lift(binder).map(ty::Predicate::TypeOutlives)
|
||||
}
|
||||
ty::Predicate::Projection(ref binder) => {
|
||||
tcx.lift(binder).map(ty::Predicate::Projection)
|
||||
}
|
||||
ty::Predicate::WellFormed(ty) => {
|
||||
tcx.lift(&ty).map(ty::Predicate::WellFormed)
|
||||
}
|
||||
ty::Predicate::Rfc1592(box ref a) => {
|
||||
tcx.lift(a).map(|a| ty::Predicate::Rfc1592(Box::new(a)))
|
||||
}
|
||||
ty::Predicate::ClosureKind(closure_def_id, kind) => {
|
||||
Some(ty::Predicate::ClosureKind(closure_def_id, kind))
|
||||
}
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
Some(ty::Predicate::ObjectSafe(trait_def_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
|
||||
type Lifted = ty::Binder<T::Lifted>;
|
||||
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
|
|
|
|||
|
|
@ -134,9 +134,9 @@ impl<'tcx> ParameterEnvironment<'tcx> {
|
|||
self_type: Ty<'tcx>, span: Span)
|
||||
-> Result<(),CopyImplementationError> {
|
||||
// FIXME: (@jroesch) float this code up
|
||||
let adt = InferCtxt::enter(tcx, None, Some(self.clone()),
|
||||
ProjectionMode::Topmost, |infcx| {
|
||||
match self_type.sty {
|
||||
tcx.infer_ctxt(None, Some(self.clone()),
|
||||
ProjectionMode::Topmost).enter(|infcx| {
|
||||
let adt = match self_type.sty {
|
||||
ty::TyStruct(struct_def, substs) => {
|
||||
for field in struct_def.all_fields() {
|
||||
let field_ty = field.ty(tcx, substs);
|
||||
|
|
@ -145,7 +145,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
|
|||
field.name))
|
||||
}
|
||||
}
|
||||
Ok(struct_def)
|
||||
struct_def
|
||||
}
|
||||
ty::TyEnum(enum_def, substs) => {
|
||||
for variant in &enum_def.variants {
|
||||
|
|
@ -157,17 +157,17 @@ impl<'tcx> ParameterEnvironment<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(enum_def)
|
||||
enum_def
|
||||
}
|
||||
_ => Err(CopyImplementationError::NotAnAdt)
|
||||
_ => return Err(CopyImplementationError::NotAnAdt)
|
||||
};
|
||||
|
||||
if adt.has_dtor() {
|
||||
return Err(CopyImplementationError::HasDestructor);
|
||||
}
|
||||
})?;
|
||||
|
||||
if adt.has_dtor() {
|
||||
return Err(CopyImplementationError::HasDestructor)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +513,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
param_env: &ParameterEnvironment<'tcx>,
|
||||
bound: ty::BuiltinBound, span: Span) -> bool
|
||||
{
|
||||
InferCtxt::enter(tcx, None, Some(param_env.clone()), ProjectionMode::Topmost, |infcx| {
|
||||
tcx.infer_ctxt(None, Some(param_env.clone()), ProjectionMode::Topmost).enter(|infcx| {
|
||||
traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
|
||||
})
|
||||
}
|
||||
|
|
@ -596,19 +596,20 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layout(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'tcx>)
|
||||
-> Result<&'tcx Layout, LayoutError<'tcx>> {
|
||||
pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
|
||||
-> Result<&'tcx Layout, LayoutError<'tcx>> {
|
||||
let tcx = infcx.tcx.global_tcx();
|
||||
let can_cache = !self.has_param_types() && !self.has_self_ty();
|
||||
if can_cache {
|
||||
if let Some(&cached) = infcx.tcx.layout_cache.borrow().get(&self) {
|
||||
if let Some(&cached) = tcx.layout_cache.borrow().get(&self) {
|
||||
return Ok(cached);
|
||||
}
|
||||
}
|
||||
|
||||
let layout = Layout::compute_uncached(self, infcx)?;
|
||||
let layout = infcx.tcx.intern_layout(layout);
|
||||
let layout = tcx.intern_layout(layout);
|
||||
if can_cache {
|
||||
infcx.tcx.layout_cache.borrow_mut().insert(self, layout);
|
||||
tcx.layout_cache.borrow_mut().insert(self, layout);
|
||||
}
|
||||
Ok(layout)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ pub enum Ns {
|
|||
Value
|
||||
}
|
||||
|
||||
fn number_of_supplied_defaults<'a, 'tcx, GG>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
substs: &subst::Substs,
|
||||
space: subst::ParamSpace,
|
||||
get_generics: GG)
|
||||
-> usize
|
||||
where GG: FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx>
|
||||
fn number_of_supplied_defaults<'a, 'gcx, 'tcx, GG>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
substs: &subst::Substs,
|
||||
space: subst::ParamSpace,
|
||||
get_generics: GG)
|
||||
-> usize
|
||||
where GG: FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> ty::Generics<'tcx>
|
||||
{
|
||||
let generics = get_generics(tcx);
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
|
|||
projections: &[ty::ProjectionPredicate],
|
||||
get_generics: GG)
|
||||
-> fmt::Result
|
||||
where GG: for<'a, 'tcx> FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx>
|
||||
where GG: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> ty::Generics<'tcx>
|
||||
{
|
||||
if let (Ns::Value, Some(self_ty)) = (ns, substs.self_ty()) {
|
||||
write!(f, "<{} as ", self_ty)?;
|
||||
|
|
@ -231,10 +231,10 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn in_binder<'a, 'tcx, T, U>(f: &mut fmt::Formatter,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
original: &ty::Binder<T>,
|
||||
lifted: Option<ty::Binder<U>>) -> fmt::Result
|
||||
fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
original: &ty::Binder<T>,
|
||||
lifted: Option<ty::Binder<U>>) -> fmt::Result
|
||||
where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx>
|
||||
{
|
||||
// Replace any anonymous late-bound regions with named
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue