diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f5869b8a20fa..4bc0005d568a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -19,11 +19,8 @@ pub use self::freshen::TypeFreshener; pub use self::region_inference::{GenericKind, VerifyBound}; use hir::def_id::DefId; -use hir; use middle::free_region::{FreeRegionMap, RegionRelations}; use middle::region::RegionMaps; -use middle::mem_categorization as mc; -use middle::mem_categorization::McResult; use middle::lang_items; use mir::tcx::LvalueTy; use ty::subst::{Kind, Subst, Substs}; @@ -34,9 +31,8 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations, Reveal}; use rustc_data_structures::unify::{self, UnificationTable}; -use std::cell::{Cell, RefCell, Ref, RefMut}; +use std::cell::{Cell, RefCell, Ref}; use std::fmt; -use std::ops::Deref; use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::{self, Span, DUMMY_SP}; @@ -76,71 +72,14 @@ pub type Bound = Option; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type FixupResult = Result; // "fixup result" -/// A version of &ty::TypeckTables which can be `Missing` (not needed), -/// `InProgress` (during typeck) or `Interned` (result of typeck). -/// Only the `InProgress` version supports `borrow_mut`. -#[derive(Copy, Clone)] -pub enum InferTables<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - Interned(&'a ty::TypeckTables<'gcx>), - InProgress(&'a RefCell>), - Missing -} - -pub enum InferTablesRef<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - Interned(&'a ty::TypeckTables<'gcx>), - InProgress(Ref<'a, ty::TypeckTables<'tcx>>) -} - -impl<'a, 'gcx, 'tcx> Deref for InferTablesRef<'a, 'gcx, 'tcx> { - type Target = ty::TypeckTables<'tcx>; - fn deref(&self) -> &Self::Target { - match *self { - InferTablesRef::Interned(tables) => tables, - InferTablesRef::InProgress(ref tables) => tables - } - } -} - -impl<'a, 'gcx, 'tcx> InferTables<'a, 'gcx, 'tcx> { - pub fn borrow(self) -> InferTablesRef<'a, 'gcx, 'tcx> { - match self { - InferTables::Interned(tables) => InferTablesRef::Interned(tables), - InferTables::InProgress(tables) => InferTablesRef::InProgress(tables.borrow()), - InferTables::Missing => { - bug!("InferTables: infcx.tables.borrow() with no tables") - } - } - } - - pub fn expect_interned(self) -> &'a ty::TypeckTables<'gcx> { - match self { - InferTables::Interned(tables) => tables, - InferTables::InProgress(_) => { - bug!("InferTables: infcx.tables.expect_interned() during type-checking"); - } - InferTables::Missing => { - bug!("InferTables: infcx.tables.expect_interned() with no tables") - } - } - } - - pub fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> { - match self { - InferTables::Interned(_) => { - bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking"); - } - InferTables::InProgress(tables) => tables.borrow_mut(), - InferTables::Missing => { - bug!("InferTables: infcx.tables.borrow_mut() with no tables") - } - } - } -} - pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, - pub tables: InferTables<'a, 'gcx, 'tcx>, + /// During type-checking/inference of a body, `in_progress_tables` + /// contains a reference to the tables being built up, which are + /// used for reading closure kinds/signatures as they are inferred, + /// and for error reporting logic to read arbitrary node types. + pub in_progress_tables: Option<&'a RefCell>>, // Cache for projections. This cache is snapshotted along with the // infcx. @@ -396,91 +335,33 @@ impl fmt::Display for FixupError { } } -pub trait InferEnv<'a, 'tcx> { - fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>); -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for () { - fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - (None, None) - } -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for &'a ty::TypeckTables<'tcx> { - fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - (Some(self), None) - } -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::TypeckTables<'tcx> { - fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - (None, Some(self)) - } -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId { - fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - let def_id = tcx.hir.body_owner_def_id(self); - (Some(tcx.typeck_tables_of(def_id)), None) - } -} - -/// Helper type of a temporary returned by tcx.infer_ctxt(...). +/// 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>, arena: DroplessArena, fresh_tables: Option>>, - tables: Option<&'a ty::TypeckTables<'gcx>>, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { - pub fn infer_ctxt>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> { - let (tables, fresh_tables) = env.to_parts(self); + pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> { InferCtxtBuilder { global_tcx: self, arena: DroplessArena::new(), - fresh_tables: fresh_tables.map(RefCell::new), - tables: tables, - } - } - - /// 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, body: hir::BodyId) - -> InferCtxt<'a, 'gcx, 'gcx> { - let (tables, _) = body.to_parts(self); - InferCtxt { - tcx: self, - tables: InferTables::Interned(tables.unwrap()), - 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), - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - projection_cache: RefCell::new(traits::ProjectionCache::new()), - reported_trait_errors: RefCell::new(FxHashSet()), - tainted_by_errors_flag: Cell::new(false), - err_count_on_creation: self.sess.err_count(), - in_snapshot: Cell::new(false), + fresh_tables: None, } } } impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { + /// Used only by `rustc_typeck` during body type-checking/inference, + /// will initialize `in_progress_tables` with fresh `TypeckTables`. + pub fn with_fresh_in_progress_tables(mut self) -> Self { + self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty())); + self + } + pub fn enter(&'tcx mut self, f: F) -> R where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R { @@ -488,14 +369,11 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { global_tcx, ref arena, ref fresh_tables, - tables, } = *self; - let tables = tables.map(InferTables::Interned).unwrap_or_else(|| { - fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress) - }); + let in_progress_tables = fresh_tables.as_ref(); global_tcx.enter_local(arena, |tcx| f(InferCtxt { - tcx: tcx, - tables: tables, + tcx, + in_progress_tables, projection_cache: RefCell::new(traits::ProjectionCache::new()), type_variables: RefCell::new(type_variable::TypeVariableTable::new()), int_unification_table: RefCell::new(UnificationTable::new()), @@ -618,7 +496,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt(()).enter(|infcx| { + self.infer_ctxt().enter(|infcx| { value.trans_normalize(&infcx, param_env) }) } @@ -640,7 +518,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt(()).enter(|infcx| { + self.infer_ctxt().enter(|infcx| { value.trans_normalize(&infcx, env.reveal_all()) }) } @@ -844,10 +722,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e. during typeck) // to ban writes from within a snapshot to them. - _in_progress_tables: match self.tables { - InferTables::InProgress(ref tables) => tables.try_borrow().ok(), - _ => None - } + _in_progress_tables: self.in_progress_tables.map(|tables| { + tables.borrow() + }) } } @@ -1190,28 +1067,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tainted_by_errors_flag.set(true) } - pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { - match self.tables.borrow().node_types.get(&id) { - Some(&t) => t, - // FIXME - None if self.is_tainted_by_errors() => - self.tcx.types.err, - None => { - bug!("no type for node {}: {} in fcx", - id, self.tcx.hir.node_to_string(id)); - } - } - } - - pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { - match self.tables.borrow().node_types.get(&ex.id) { - Some(&t) => t, - None => { - bug!("no type for expr in fcx"); - } - } - } - pub fn resolve_regions_and_report_errors(&self, region_context: DefId, region_map: &RegionMaps, @@ -1310,21 +1165,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { value.fold_with(&mut r) } - /// Resolves all type variables in `t` and then, if any were left - /// unresolved, substitutes an error type. This is used after the - /// main checking when doing a second pass before writeback. The - /// justification is that writeback will produce an error for - /// these unconstrained type variables. - fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { - let ty = self.resolve_type_vars_if_possible(t); - if ty.references_error() || ty.is_ty_var() { - debug!("resolve_type_vars_or_error: error from {:?}", ty); - Err(()) - } else { - Ok(ty) - } - } - pub fn fully_resolve>(&self, value: &T) -> FixupResult { /*! * Attempts to resolve all type/region variables in @@ -1484,30 +1324,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bound); } - pub fn node_ty(&self, id: ast::NodeId) -> McResult> { - let ty = self.node_type(id); - self.resolve_type_vars_or_error(&ty) - } - - pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - let ty = self.tables.borrow().expr_ty_adjusted(expr); - self.resolve_type_vars_or_error(&ty) - } - pub fn type_moves_by_default(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, span: Span) -> bool { let ty = self.resolve_type_vars_if_possible(&ty); - if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) { - // 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::InProgress(_) => ty.has_closure_types(), - _ => false - }; - if !local_closures { + // Even if the type may have no inference variables, during + // type-checking closure types are in local tables only. + if !self.in_progress_tables.is_some() || !ty.has_closure_types() { + if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) { return ty.moves_by_default(self.tcx.global_tcx(), param_env, span); } } @@ -1521,15 +1347,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span) } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { - self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() - } - pub fn closure_kind(&self, def_id: DefId) -> Option { - if let InferTables::InProgress(tables) = self.tables { + if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { return tables.borrow() .closure_kinds @@ -1547,7 +1369,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> { - if let InferTables::InProgress(tables) = self.tables { + if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { if let Some(&ty) = tables.borrow().closure_tys.get(&id) { return ty; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 2022565d533b..40734469718b 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -27,6 +27,7 @@ use self::TargetLint::*; use dep_graph::DepNode; use middle::privacy::AccessLevels; +use traits::Reveal; use ty::{self, TyCtxt}; use session::{config, early_error, Session}; use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource}; @@ -411,8 +412,8 @@ pub struct LateContext<'a, 'tcx: 'a> { /// Side-tables for the body we are in. pub tables: &'a ty::TypeckTables<'tcx>, - /// The crate being checked. - pub krate: &'a hir::Crate, + /// Parameter environment for the item we are in. + pub param_env: ty::ParamEnv<'tcx>, /// Items accessible from the crate being checked. pub access_levels: &'a AccessLevels, @@ -869,6 +870,17 @@ impl<'a> LintContext<'a> for EarlyContext<'a> { } } +impl<'a, 'tcx> LateContext<'a, 'tcx> { + fn with_param_env(&mut self, id: ast::NodeId, f: F) + where F: FnOnce(&mut Self), + { + let old_param_env = self.param_env; + self.param_env = self.tcx.param_env(self.tcx.hir.local_def_id(id)); + f(self); + self.param_env = old_param_env; + } +} + impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { /// Because lints are scoped lexically, we want to walk nested /// items in the context of the outer item, so enable @@ -902,17 +914,21 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { - run_lints!(cx, check_item, late_passes, it); - hir_visit::walk_item(cx, it); - run_lints!(cx, check_item_post, late_passes, it); + cx.with_param_env(it.id, |cx| { + run_lints!(cx, check_item, late_passes, it); + hir_visit::walk_item(cx, it); + run_lints!(cx, check_item_post, late_passes, it); + }); }) } fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { self.with_lint_attrs(&it.attrs, |cx| { - run_lints!(cx, check_foreign_item, late_passes, it); - hir_visit::walk_foreign_item(cx, it); - run_lints!(cx, check_foreign_item_post, late_passes, it); + cx.with_param_env(it.id, |cx| { + run_lints!(cx, check_foreign_item, late_passes, it); + hir_visit::walk_foreign_item(cx, it); + run_lints!(cx, check_foreign_item_post, late_passes, it); + }); }) } @@ -1026,17 +1042,21 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { - run_lints!(cx, check_trait_item, late_passes, trait_item); - hir_visit::walk_trait_item(cx, trait_item); - run_lints!(cx, check_trait_item_post, late_passes, trait_item); + cx.with_param_env(trait_item.id, |cx| { + run_lints!(cx, check_trait_item, late_passes, trait_item); + hir_visit::walk_trait_item(cx, trait_item); + run_lints!(cx, check_trait_item_post, late_passes, trait_item); + }); }); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { - run_lints!(cx, check_impl_item, late_passes, impl_item); - hir_visit::walk_impl_item(cx, impl_item); - run_lints!(cx, check_impl_item_post, late_passes, impl_item); + cx.with_param_env(impl_item.id, |cx| { + run_lints!(cx, check_impl_item, late_passes, impl_item); + hir_visit::walk_impl_item(cx, impl_item); + run_lints!(cx, check_impl_item_post, late_passes, impl_item); + }); }); } @@ -1330,7 +1350,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut cx = LateContext { tcx: tcx, tables: &ty::TypeckTables::empty(), - krate: krate, + param_env: ty::ParamEnv::empty(Reveal::UserFacing), access_levels: access_levels, lint_sess: LintSession::new(&tcx.sess.lint_store), }; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0b2652c74881..58e77f40d981 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -235,17 +235,14 @@ impl OverloadedCallType { /////////////////////////////////////////////////////////////////////////// // The ExprUseVisitor type // -// This is the code that actually walks the tree. Like -// mem_categorization, it requires a TYPER, which is a type that -// supplies types from the tree. After type checking is complete, you -// can just use the tcx as the typer. +// This is the code that actually walks the tree. pub struct ExprUseVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>, delegate: &'a mut Delegate<'tcx>, param_env: ty::ParamEnv<'tcx>, } -// If the TYPER results in an error, it's because the type check +// If the MC results in an error, it's because the type check // failed (or will fail, when the error is uncovered and reported // during writeback). In this case, we just ignore this part of the // code. @@ -264,29 +261,32 @@ macro_rules! return_if_err { ) } -impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, region_maps: &'a RegionMaps, - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self - { - ExprUseVisitor::with_options(delegate, - infcx, - param_env, - region_maps, - mc::MemCategorizationOptions::default()) - } - - pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - region_maps: &'a RegionMaps, - options: mc::MemCategorizationOptions) + tables: &'a ty::TypeckTables<'tcx>) -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options), + mc: mc::MemCategorizationContext::new(tcx, region_maps, tables), + delegate, + param_env, + } + } +} + +impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { + pub fn with_infer(delegate: &'a mut (Delegate<'tcx>+'a), + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + region_maps: &'a RegionMaps, + tables: &'a ty::TypeckTables<'tcx>) + -> Self + { + ExprUseVisitor { + mc: mc::MemCategorizationContext::with_infer(infcx, region_maps, tables), delegate, param_env, } @@ -296,7 +296,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("consume_body(body={:?})", body); for arg in &body.arguments { - let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); + let arg_ty = return_if_err!(self.mc.node_ty(arg.pat.id)); let fn_body_scope_r = self.tcx().node_scope_region(body.value.id); let arg_cmt = self.mc.cat_rvalue( @@ -312,7 +312,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { - self.mc.infcx.tcx + self.mc.tcx } fn delegate_consume(&mut self, @@ -322,7 +322,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("delegate_consume(consume_id={}, cmt={:?})", consume_id, cmt); - let mode = copy_or_move(self.mc.infcx, self.param_env, &cmt, DirectRefMove); + let mode = copy_or_move(&self.mc, self.param_env, &cmt, DirectRefMove); self.delegate.consume(consume_id, consume_span, cmt, mode); } @@ -441,7 +441,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { hir::ExprAddrOf(m, ref base) => { // &base // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: - let expr_ty = return_if_err!(self.mc.infcx.node_ty(expr.id)); + let expr_ty = return_if_err!(self.mc.expr_ty(expr)); if let ty::TyRef(r, _) = expr_ty.sty { let bk = ty::BorrowKind::from_mutbl(m); self.borrow_expr(&base, r, bk, AddrOf); @@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprAssignOp(_, ref lhs, ref rhs) => { - if self.mc.infcx.tables.borrow().is_method_call(expr) { + if self.mc.tables.is_method_call(expr) { self.consume_expr(lhs); } else { self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead); @@ -528,7 +528,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) { - let callee_ty = return_if_err!(self.mc.infcx.expr_ty_adjusted(callee)); + let callee_ty = return_if_err!(self.mc.expr_ty_adjusted(callee)); debug!("walk_callee: callee={:?} callee_ty={:?}", callee, callee_ty); match callee_ty.sty { @@ -537,7 +537,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let def_id = self.mc.infcx.tables.borrow().type_dependent_defs[&call.id].def_id(); + let def_id = self.mc.tables.type_dependent_defs[&call.id].def_id(); match OverloadedCallType::from_method_id(self.tcx(), def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); @@ -678,8 +678,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // consumed or borrowed as part of the automatic adjustment // process. fn walk_adjustment(&mut self, expr: &hir::Expr) { - //NOTE(@jroesch): mixed RefCell borrow causes crash - let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec(); + let adjustments = self.mc.tables.expr_adjustments(expr); let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr)); for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); @@ -796,12 +795,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { mode: &mut TrackMatchMode) { debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr, pat); - return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| { + return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { match pat.node { PatKind::Binding(hir::BindByRef(..), ..) => mode.lub(BorrowingMatch), PatKind::Binding(hir::BindByValue(..), ..) => { - match copy_or_move(self.mc.infcx, self.param_env, &cmt_pat, PatBindingMove) { + match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) { Copy => mode.lub(CopyingMatch), Move(..) => mode.lub(MovingMatch), } @@ -818,14 +817,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat); let tcx = self.tcx(); - let infcx = self.mc.infcx; let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; - return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| { + return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(bmode, def_id, ..) = pat.node { debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); // pat_ty: the type of the binding being produced. - let pat_ty = return_if_err!(infcx.node_ty(pat.id)); + let pat_ty = return_if_err!(mc.node_ty(pat.id)); // Each match binding is effectively an assignment to the // binding being produced. @@ -843,7 +841,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } hir::BindByValue(..) => { - let mode = copy_or_move(infcx, param_env, &cmt_pat, PatBindingMove); + let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); debug!("walk_pat binding consuming pat"); delegate.consume_pat(pat, cmt_pat, mode); } @@ -855,14 +853,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // the interior nodes (enum variants and structs), as opposed // to the above loop's visit of than the bindings that form // the leaves of the pattern tree structure. - return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { + return_if_err!(mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { let qpath = match pat.node { PatKind::Path(ref qpath) | PatKind::TupleStruct(ref qpath, ..) | PatKind::Struct(ref qpath, ..) => qpath, _ => return }; - let def = infcx.tables.borrow().qpath_def(qpath, pat.id); + let def = mc.tables.qpath_def(qpath, pat.id); match def { Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { @@ -896,13 +894,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let id_var = self.tcx().hir.as_local_node_id(def_id).unwrap(); let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id }; - let upvar_capture = self.mc.infcx.upvar_capture(upvar_id).unwrap(); + let upvar_capture = self.mc.tables.upvar_capture(upvar_id); let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id, fn_decl_span, freevar.def)); match upvar_capture { ty::UpvarCapture::ByValue => { - let mode = copy_or_move(self.mc.infcx, + let mode = copy_or_move(&self.mc, self.param_env, &cmt_var, CaptureMove); @@ -929,18 +927,18 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Create the cmt for the variable being borrowed, from the // caller's perspective let var_id = self.tcx().hir.as_local_node_id(upvar_def.def_id()).unwrap(); - let var_ty = self.mc.infcx.node_ty(var_id)?; + let var_ty = self.mc.node_ty(var_id)?; self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def) } } -fn copy_or_move<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, +fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, cmt: &mc::cmt<'tcx>, move_reason: MoveReason) -> ConsumeMode { - if infcx.type_moves_by_default(param_env, cmt.ty, cmt.span) { + if mc.type_moves_by_default(param_env, cmt.ty, cmt.span) { Move(move_reason) } else { Copy diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c114aa1d7a88..259079cf1604 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -76,6 +76,7 @@ use infer::InferCtxt; use hir::def::{Def, CtorKind}; use ty::adjustment; use ty::{self, Ty, TyCtxt}; +use ty::fold::TypeFoldable; use hir::{MutImmutable, MutMutable, PatKind}; use hir::pat_util::EnumerateAndAdjustIterator; @@ -281,20 +282,10 @@ impl ast_node for hir::Pat { #[derive(Clone)] pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, pub region_maps: &'a RegionMaps, - options: MemCategorizationOptions, -} - -#[derive(Copy, Clone, Default)] -pub struct MemCategorizationOptions { - // If true, then when analyzing a closure upvar, if the closure - // has a missing kind, we treat it like a Fn closure. When false, - // we ICE if the closure has a missing kind. Should be false - // except during closure kind inference. It is used by the - // mem-categorization code to be able to have stricter assertions - // (which are always true except during upvar inference). - pub during_closure_kind_inference: bool, + pub tables: &'a ty::TypeckTables<'tcx>, + infcx: Option<&'a InferCtxt<'a, 'gcx, 'tcx>>, } pub type McResult = Result; @@ -395,51 +386,90 @@ impl MutabilityCategory { } } -impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { - /// Context should be the `DefId` we use to fetch region-maps. - pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - region_maps: &'a RegionMaps) - -> MemCategorizationContext<'a, 'gcx, 'tcx> { - MemCategorizationContext::with_options(infcx, - region_maps, - MemCategorizationOptions::default()) +impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + region_maps: &'a RegionMaps, + tables: &'a ty::TypeckTables<'tcx>) + -> MemCategorizationContext<'a, 'tcx, 'tcx> { + MemCategorizationContext { tcx, region_maps, tables, infcx: None } } +} - pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - region_maps: &'a RegionMaps, - options: MemCategorizationOptions) - -> MemCategorizationContext<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { + pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + region_maps: &'a RegionMaps, + tables: &'a ty::TypeckTables<'tcx>) + -> MemCategorizationContext<'a, 'gcx, 'tcx> { MemCategorizationContext { - infcx: infcx, - region_maps: region_maps, - options: options, + tcx: infcx.tcx, + region_maps, + tables, + infcx: Some(infcx), } } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { - self.infcx.tcx + pub fn type_moves_by_default(&self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span) + -> bool { + self.infcx.map(|infcx| infcx.type_moves_by_default(param_env, ty, span)) + .or_else(|| { + self.tcx.lift_to_global(&(param_env, ty)).map(|(param_env, ty)| { + ty.moves_by_default(self.tcx.global_tcx(), param_env, span) + }) + }) + .unwrap_or(true) } - fn expr_ty(&self, expr: &hir::Expr) -> McResult> { - match self.infcx.node_ty(expr.id) { - Ok(t) => Ok(t), - Err(()) => { - debug!("expr_ty({:?}) yielded Err", expr); - Err(()) + fn resolve_type_vars_if_possible(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + self.infcx.map(|infcx| infcx.resolve_type_vars_if_possible(value)) + .unwrap_or_else(|| value.clone()) + } + + fn is_tainted_by_errors(&self) -> bool { + self.infcx.map_or(false, |infcx| infcx.is_tainted_by_errors()) + } + + fn resolve_type_vars_or_error(&self, + id: ast::NodeId, + ty: Option>) + -> McResult> { + match ty { + Some(ty) => { + let ty = self.resolve_type_vars_if_possible(&ty); + if ty.references_error() || ty.is_ty_var() { + debug!("resolve_type_vars_or_error: error from {:?}", ty); + Err(()) + } else { + Ok(ty) + } + } + // FIXME + None if self.is_tainted_by_errors() => Err(()), + None => { + bug!("no type for node {}: {} in mem_categorization", + id, self.tcx.hir.node_to_string(id)); } } } - fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - self.infcx.expr_ty_adjusted(expr) + pub fn node_ty(&self, id: ast::NodeId) -> McResult> { + self.resolve_type_vars_or_error(id, self.tables.node_id_to_type_opt(id)) } - fn node_ty(&self, id: ast::NodeId) -> McResult> { - self.infcx.node_ty(id) + pub fn expr_ty(&self, expr: &hir::Expr) -> McResult> { + self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_opt(expr)) + } + + pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { + self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_adjusted_opt(expr)) } fn pat_ty(&self, pat: &hir::Pat) -> McResult> { - let base_ty = self.infcx.node_ty(pat.id)?; + let base_ty = self.node_ty(pat.id)?; // FIXME (Issue #18207): This code detects whether we are // looking at a `ref x`, and if so, figures out what the type // *being borrowed* is. But ideally we would put in a more @@ -479,7 +509,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr)) + helper(self, expr, self.tables.expr_adjustments(expr)) } pub fn cat_expr_adjusted(&self, expr: &hir::Expr, @@ -496,12 +526,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { where F: FnOnce() -> McResult> { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); - let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target); + let target = self.resolve_type_vars_if_possible(&adjustment.target); match adjustment.kind { adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. let base = if let Some(deref) = overloaded { - let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut { + let ref_ty = self.tcx.mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl, }); @@ -531,7 +561,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expr_ty = self.expr_ty(expr)?; match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { - if self.infcx.tables.borrow().is_method_call(expr) { + if self.tables.is_method_call(expr) { self.cat_overloaded_lvalue(expr, e_base, false) } else { let base_cmt = self.cat_expr(&e_base)?; @@ -554,7 +584,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref base, _) => { - if self.infcx.tables.borrow().is_method_call(expr) { + if self.tables.is_method_call(expr) { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. // The call to index() returns a `&T` value, which @@ -568,7 +598,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprPath(ref qpath) => { - let def = self.infcx.tables.borrow().qpath_def(qpath, expr.id); + let def = self.tables.qpath_def(qpath, expr.id); self.cat_def(expr.id, expr.span, expr_ty, def) } @@ -619,49 +649,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Upvar(def_id, _, fn_node_id) => { - let var_id = self.tcx().hir.as_local_node_id(def_id).unwrap(); - let ty = self.node_ty(fn_node_id)?; - match ty.sty { - ty::TyClosure(closure_id, _) => { - match self.infcx.closure_kind(closure_id) { - Some(kind) => { - self.cat_upvar(id, span, var_id, fn_node_id, kind) - } - None => { - if !self.options.during_closure_kind_inference { - span_bug!( - span, - "No closure kind for {:?}", - closure_id); - } - - // during closure kind inference, we - // don't know the closure kind yet, but - // it's ok because we detect that we are - // accessing an upvar and handle that - // case specially anyhow. Use Fn - // arbitrarily. - self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn) - } - } - } - _ => { - span_bug!( - span, - "Upvar of non-closure {} - {:?}", - fn_node_id, - ty); - } - } + let var_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); + self.cat_upvar(id, span, var_id, fn_node_id) } Def::Local(def_id) => { - let vid = self.tcx().hir.as_local_node_id(def_id).unwrap(); + let vid = self.tcx.hir.as_local_node_id(def_id).unwrap(); Ok(Rc::new(cmt_ { id: id, span: span, cat: Categorization::Local(vid), - mutbl: MutabilityCategory::from_local(self.tcx(), vid), + mutbl: MutabilityCategory::from_local(self.tcx, vid), ty: expr_ty, note: NoteNone })) @@ -677,8 +675,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { id: ast::NodeId, span: Span, var_id: ast::NodeId, - fn_node_id: ast::NodeId, - kind: ty::ClosureKind) + fn_node_id: ast::NodeId) -> McResult> { // An upvar can have up to 3 components. We translate first to a @@ -704,12 +701,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk // FnOnce | copied | upvar -> &'up bk + let kind = match self.tables.closure_kinds.get(&fn_node_id) { + Some(&(kind, _)) => kind, + None => span_bug!(span, "missing closure kind") + }; + let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: fn_node_id }; let var_ty = self.node_ty(var_id)?; // Mutability of original variable itself - let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id); + let var_mutbl = MutabilityCategory::from_local(self.tcx, var_id); // Construct the upvar. This represents access to the field // from the environment (perhaps we should eventually desugar @@ -743,7 +745,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // for that. let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: fn_node_id }; - let upvar_capture = self.infcx.upvar_capture(upvar_id).unwrap(); + let upvar_capture = self.tables.upvar_capture(upvar_id); let cmt_result = match upvar_capture { ty::UpvarCapture::ByValue => { cmt_result @@ -776,11 +778,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { -> cmt_<'tcx> { // Region of environment pointer - let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion { + let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { // The environment of a closure is guaranteed to // outlive any bindings introduced in the body of the // closure itself. - scope: self.tcx().hir.local_def_id(upvar_id.closure_expr_id), + scope: self.tcx.hir.local_def_id(upvar_id.closure_expr_id), bound_region: ty::BrEnv })); @@ -797,7 +799,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // one. let cmt_result = cmt_ { mutbl: McImmutable, - ty: self.tcx().types.err, + ty: self.tcx.types.err, ..cmt_result }; @@ -829,7 +831,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region<'tcx> { let scope = self.region_maps.temporary_scope(id); - self.tcx().mk_region(match scope { + self.tcx.mk_region(match scope { Some(scope) => ty::ReScope(scope), None => ty::ReStatic }) @@ -840,20 +842,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { span: Span, expr_ty: Ty<'tcx>) -> cmt<'tcx> { - let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned() + let promotable = self.tcx.rvalue_promotable_to_static.borrow().get(&id).cloned() .unwrap_or(false); // When the corresponding feature isn't toggled, only promote `[T; 0]`. let promotable = match expr_ty.sty { ty::TyArray(_, 0) => true, - _ => promotable && self.tcx().sess.features.borrow().rvalue_static_promotion, + _ => promotable && self.tcx.sess.features.borrow().rvalue_static_promotion, }; // Compute maximum lifetime of this rvalue. This is 'static if // we can promote to a constant, otherwise equal to enclosing temp // lifetime. let re = if promotable { - self.tcx().types.re_static + self.tcx.types.re_static } else { self.temporary_scope(id) }; @@ -934,7 +936,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference") } }; - let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { + let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { ty: lvalue_ty, mutbl, }); @@ -1049,14 +1051,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } pub fn cat_pattern(&self, cmt: cmt<'tcx>, pat: &hir::Pat, mut op: F) -> McResult<()> - where F: FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat), + where F: FnMut(cmt<'tcx>, &hir::Pat), { self.cat_pattern_(cmt, pat, &mut op) } // FIXME(#19596) This is a workaround, but there should be a better way to do this fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()> - where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat) + where F : FnMut(cmt<'tcx>, &hir::Pat) { // Here, `cmt` is the categorization for the value being // matched and pat is the pattern it is being matched against. @@ -1105,7 +1107,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { debug!("cat_pattern: {:?} cmt={:?}", pat, cmt); - op(self, cmt.clone(), pat); + op(cmt.clone(), pat); // Note: This goes up here (rather than within the PatKind::TupleStruct arm // alone) because PatKind::Struct can also refer to variants. @@ -1121,8 +1123,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { // univariant enums do not need downcasts - let enum_did = self.tcx().parent_def_id(variant_did).unwrap(); - if !self.tcx().adt_def(enum_did).is_univariant() { + let enum_did = self.tcx.parent_def_id(variant_did).unwrap(); + if !self.tcx.adt_def(enum_did).is_univariant() { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) } else { cmt @@ -1136,11 +1138,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match pat.node { PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { - let def = self.infcx.tables.borrow().qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.id); let expected_len = match def { Def::VariantCtor(def_id, CtorKind::Fn) => { - let enum_def = self.tcx().parent_def_id(def_id).unwrap(); - self.tcx().adt_def(enum_def).variant_with_id(def_id).fields.len() + let enum_def = self.tcx.parent_def_id(def_id).unwrap(); + self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len() } Def::StructCtor(_, CtorKind::Fn) => { match self.pat_ty(&pat)?.sty { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c8e99c0354ab..64438f586d7f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -29,7 +29,7 @@ use hir::{self, intravisit, Local, Pat, Body}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::map::NodeExpr; use hir::def_id::DefId; -use infer::{self, InferCtxt, InferTables, InferTablesRef}; +use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; @@ -72,9 +72,12 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn node_matches_type(&mut self, node_id: &'gcx NodeId) -> bool { - match self.infcx.tables.borrow().node_types.get(node_id) { - Some(&ty) => { + fn node_matches_type(&mut self, node_id: NodeId) -> bool { + let ty_opt = self.infcx.in_progress_tables.and_then(|tables| { + tables.borrow().node_id_to_type_opt(node_id) + }); + match ty_opt { + Some(ty) => { let ty = self.infcx.resolve_type_vars_if_possible(&ty); ty.walk().any(|inner_ty| { inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) { @@ -88,7 +91,7 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { } }) } - _ => false, + None => false, } } } @@ -99,7 +102,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { } fn visit_local(&mut self, local: &'gcx Local) { - if self.found_local_pattern.is_none() && self.node_matches_type(&local.id) { + if self.found_local_pattern.is_none() && self.node_matches_type(local.id) { self.found_local_pattern = Some(&*local.pat); } intravisit::walk_local(self, local); @@ -107,7 +110,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn visit_body(&mut self, body: &'gcx Body) { for argument in &body.arguments { - if self.found_arg_pattern.is_none() && self.node_matches_type(&argument.id) { + if self.found_arg_pattern.is_none() && self.node_matches_type(argument.id) { self.found_arg_pattern = Some(&*argument.pat); } } @@ -652,18 +655,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation.cause.span, format!("the requirement to implement `{}` derives from here", kind)); - let infer_tables = match self.tables { - InferTables::Interned(tables) => - Some(InferTablesRef::Interned(tables)), - InferTables::InProgress(tables) => - Some(InferTablesRef::InProgress(tables.borrow())), - InferTables::Missing => None, - }; - // Additional context information explaining why the closure only implements // a particular trait. - if let Some(tables) = infer_tables { - match tables.closure_kinds.get(&node_id) { + if let Some(tables) = self.in_progress_tables { + match tables.borrow().closure_kinds.get(&node_id) { Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => { err.span_note(span, &format!( "closure is `FnOnce` because it moves the \ diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c51974e6e670..3ce7ee847cca 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -484,7 +484,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let predicates = match fully_normalize( &infcx, cause, @@ -598,7 +598,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_and_test_predicates(predicates={:?})", predicates); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::All); let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = FulfillmentContext::new(); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 689f06a35973..18734e2dbc3f 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -125,7 +125,7 @@ pub fn find_associated_item<'a, 'tcx>( let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); match ancestors.defs(tcx, item.name, item.kind).next() { Some(node_item) => { - let substs = tcx.infer_ctxt(()).enter(|infcx| { + let substs = tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::All); let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id, @@ -188,7 +188,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); // Create a infcx, taking the predicates of impl1 as assumptions: - let result = tcx.infer_ctxt(()).enter(|infcx| { + let result = tcx.infer_ctxt().enter(|infcx| { // Normalize the trait reference. The WF rules ought to ensure // that this always succeeds. let impl1_trait_ref = diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 702c5035a18b..f80caeec460f 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Children { let possible_sibling = *slot; let tcx = tcx.global_tcx(); - let (le, ge) = tcx.infer_ctxt(()).enter(|infcx| { + let (le, ge) = tcx.infer_ctxt().enter(|infcx| { let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 7ad2ef90f0d4..734ba2a2d390 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - self.infer_ctxt(()).enter(|infcx| { + self.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let param_env = ty::ParamEnv::empty(Reveal::All); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2bbb71610ad0..2d81606329e5 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -376,8 +376,8 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { - Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone()) + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { + self.upvar_capture_map[&upvar_id] } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index ec4ca54d6f5e..a7029ac5fa9f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -175,7 +175,7 @@ impl<'tcx> ty::ParamEnv<'tcx> { self_type: Ty<'tcx>, span: Span) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let (adt, substs) = match self_type.sty { ty::TyAdt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt), @@ -977,7 +977,7 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); - tcx.infer_ctxt(()) + tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound(&infcx, param_env, ty, @@ -991,7 +991,7 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); - tcx.infer_ctxt(()) + tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound(&infcx, param_env, ty, @@ -1005,7 +1005,7 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); - tcx.infer_ctxt(()) + tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound(&infcx, param_env, ty, diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 122a37ee32ae..ae2be28c198b 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -192,7 +192,6 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, debug!("check_loans(body id={})", body.value.id); let def_id = bccx.tcx.hir.body_owner_def_id(body.id()); - let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body.id()); let param_env = bccx.tcx.param_env(def_id); let mut clcx = CheckLoanCtxt { bccx: bccx, @@ -201,7 +200,8 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, all_loans: all_loans, param_env, }; - euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx, param_env).consume_body(body); + euv::ExprUseVisitor::new(&mut clcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables) + .consume_body(body); } #[derive(PartialEq)] diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 85a09969ac81..7dcb6ce76a40 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -18,7 +18,6 @@ use borrowck::*; use borrowck::move_data::MoveData; -use rustc::infer::InferCtxt; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; @@ -40,11 +39,9 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: hir::BodyId) -> (Vec>, move_data::MoveData<'tcx>) { let def_id = bccx.tcx.hir.body_owner_def_id(body); - let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body); let param_env = bccx.tcx.param_env(def_id); let mut glcx = GatherLoanCtxt { bccx: bccx, - infcx: &infcx, all_loans: Vec::new(), item_ub: region::CodeExtent::Misc(body.node_id), move_data: MoveData::new(), @@ -52,7 +49,8 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, }; let body = glcx.bccx.tcx.hir.body(body); - euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx, param_env).consume_body(body); + euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables) + .consume_body(body); glcx.report_potential_errors(); let GatherLoanCtxt { all_loans, move_data, .. } = glcx; @@ -61,7 +59,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, struct GatherLoanCtxt<'a, 'tcx: 'a> { bccx: &'a BorrowckCtxt<'a, 'tcx>, - infcx: &'a InferCtxt<'a, 'tcx, 'tcx>, move_data: move_data::MoveData<'tcx>, move_error_collector: move_error::MoveErrorCollector<'tcx>, all_loans: Vec>, @@ -158,7 +155,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { } fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) { - let ty = self.infcx.tables.borrow().node_id_to_type(id); + let ty = self.bccx.tables.node_id_to_type(id); gather_moves::gather_decl(self.bccx, &self.move_data, id, ty); } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 7c3076fda4fe..fcdabf89e3cd 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -493,19 +493,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, /// /// FIXME: this should be done by borrowck. fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { - cx.tcx.infer_ctxt(cx.tables).enter(|infcx| { - let mut checker = MutationChecker { - cx: cx, - }; - ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx, cx.param_env).walk_expr(guard); - }); + let mut checker = MutationChecker { + cx: cx, + }; + ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_maps, cx.tables) + .walk_expr(guard); } -struct MutationChecker<'a, 'gcx: 'a> { - cx: &'a MatchVisitor<'a, 'gcx>, +struct MutationChecker<'a, 'tcx: 'a> { + cx: &'a MatchVisitor<'a, 'tcx>, } -impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { +impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {} fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {} fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {} diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 3d07ffc2bc77..ec7510546a04 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -483,7 +483,7 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 2b74d0a812b4..62e20a90f8a0 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -154,7 +154,7 @@ fn test_env(source_string: &str, index, "test_crate", |tcx| { - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut region_maps = RegionMaps::new(); body(Env { infcx: &infcx, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3a4729e64548..9800012917c5 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -32,7 +32,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::cfg; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty}; use rustc::traits::{self, Reveal}; use rustc::hir::map as hir_map; use util::nodemap::NodeSet; @@ -893,7 +893,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { for adjustment in cx.tables.expr_adjustments(expr) { if let Adjust::Deref(Some(deref)) = adjustment.kind { let (def_id, substs) = deref.method_call(cx.tcx, source); - if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + if method_call_refers_to_method(cx, method, def_id, substs, id) { return true; } } @@ -904,7 +904,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { if cx.tables.is_method_call(expr) { let def_id = cx.tables.type_dependent_defs[&id].def_id(); let substs = cx.tables.node_substs(id); - if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + if method_call_refers_to_method(cx, method, def_id, substs, id) { return true; } } @@ -920,8 +920,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { match def { Def::Method(def_id) => { let substs = cx.tables.node_substs(callee.id); - method_call_refers_to_method( - cx.tcx, method, def_id, substs, id) + method_call_refers_to_method(cx, method, def_id, substs, id) } _ => false, } @@ -932,12 +931,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Check if the method call to the method with the ID `callee_id` // and instantiated with `callee_substs` refers to method `method`. - fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn method_call_refers_to_method<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, method: &ty::AssociatedItem, callee_id: DefId, callee_substs: &Substs<'tcx>, expr_id: ast::NodeId) -> bool { + let tcx = cx.tcx; let callee_item = tcx.associated_item(callee_id); match callee_item.container { @@ -951,13 +951,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs); let trait_ref = ty::Binder(trait_ref); let span = tcx.hir.span(expr_id); - let param_env = tcx.param_env(method.def_id); let obligation = traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), - param_env, + cx.param_env, trait_ref.to_poly_trait_predicate()); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); match selcx.select(&obligation) { // The method comes from a `T: Trait` bound. @@ -1224,11 +1223,9 @@ impl LintPass for UnionsWithDropFields { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { if let hir::ItemUnion(ref vdata, _) = item.node { - let item_def_id = ctx.tcx.hir.local_def_id(item.id); - let param_env = ctx.tcx.param_env(item_def_id); for field in vdata.fields() { let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id)); - if field_ty.needs_drop(ctx.tcx, param_env) { + if field_ty.needs_drop(ctx.tcx, ctx.param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, "union contains a field with possibly non-trivial drop code, \ diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 3019165bfbf9..32bde42b5261 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -725,7 +725,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { // sizes only make sense for non-generic types let item_def_id = cx.tcx.hir.local_def_id(it.id); let t = cx.tcx.type_of(item_def_id); - let param_env = cx.tcx.param_env(item_def_id).reveal_all(); + let param_env = cx.param_env.reveal_all(); let ty = cx.tcx.erase_regions(&t); let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| { bug!("failed to get layout for `{}`: {}", t, e) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 08a5cb37e578..56c0e18d6f91 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -83,7 +83,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t }; let src = MirSource::from_node(tcx, id); - tcx.infer_ctxt(body_id).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let cx = Cx::new(&infcx, src); let mut mir = if cx.tables().tainted_by_errors { build::construct_error(cx, body_id) @@ -171,7 +171,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let span = tcx.hir.span(ctor_id); if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let (mut mir, src) = shim::build_adt_ctor(&infcx, ctor_id, fields, span); @@ -365,13 +365,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { freevars.iter().map(|fv| { let var_id = tcx.hir.as_local_node_id(fv.def.def_id()).unwrap(); - let by_ref = hir.tables().upvar_capture(ty::UpvarId { + let capture = hir.tables().upvar_capture(ty::UpvarId { var_id: var_id, closure_expr_id: fn_id - }).map_or(false, |capture| match capture { + }); + let by_ref = match capture { ty::UpvarCapture::ByValue => false, ty::UpvarCapture::ByRef(..) => true - }); + }; let mut decl = UpvarDecl { debug_name: keywords::Invalid.name(), by_ref: by_ref diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8cfeecdafb51..474feefabbb8 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -758,13 +758,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr_id, }; - let upvar_capture = match cx.tables().upvar_capture(upvar_id) { - Some(c) => c, - None => { - span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id); - } - }; - match upvar_capture { + match cx.tables().upvar_capture(upvar_id) { ty::UpvarCapture::ByValue => field_kind, ty::UpvarCapture::ByRef(borrow) => { ExprKind::Deref { @@ -878,7 +872,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr.id, }; - let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap(); + let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id); let var_ty = cx.tables().node_id_to_type(id_var); let captured_var = Expr { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 5b7b52a72b0a..2bb6b39966a8 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -37,6 +37,7 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, pub param_env: ty::ParamEnv<'tcx>, pub region_maps: Rc, + pub tables: &'a ty::TypeckTables<'gcx>, /// This is `Constness::Const` if we are compiling a `static`, /// `const`, or the body of a `const fn`. @@ -67,6 +68,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let param_env = tcx.param_env(src_def_id); let region_maps = tcx.region_maps(src_def_id); + let tables = tcx.typeck_tables_of(src_def_id); let attrs = tcx.hir.attrs(src_id); @@ -82,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Constants and const fn's always need overflow checks. check_overflow |= constness == hir::Constness::Const; - Cx { tcx, infcx, param_env, region_maps, constness, src, check_overflow } + Cx { tcx, infcx, param_env, region_maps, tables, constness, src, check_overflow } } } @@ -184,7 +186,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn tables(&self) -> &'a ty::TypeckTables<'gcx> { - self.infcx.tables.expect_interned() + self.tables } pub fn check_overflow(&self) -> bool { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 793cffdec89e..d60e761bc0b9 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -998,7 +998,7 @@ impl MirPass for QualifyAndPromoteConstants { // Statics must be Sync. if mode == Mode::Static { let ty = mir.return_ty; - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index da8e3b5a42ba..e23f0705b6a0 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -759,7 +759,7 @@ impl MirPass for TypeckMir { return; } let param_env = tcx.param_env(def_id); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut checker = TypeChecker::new(&infcx, item_id, param_env); { let mut verifier = TypeVerifier::new(&mut checker, mir); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 65a9334bbae1..e539cc1ae8bf 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -51,7 +51,6 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use std::collections::hash_map::Entry; use std::cmp::Ordering; -use std::mem; struct CheckCrateVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -138,13 +137,14 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(&body.value); } - let outer_penv = self.tcx.infer_ctxt(body_id).enter(|infcx| { - let param_env = self.tcx.param_env(item_def_id); - let outer_penv = mem::replace(&mut self.param_env, param_env); - let region_maps = &self.tcx.region_maps(item_def_id); - euv::ExprUseVisitor::new(self, region_maps, &infcx, param_env).consume_body(body); - outer_penv - }); + let outer_penv = self.param_env; + self.param_env = self.tcx.param_env(item_def_id); + + let tcx = self.tcx; + let param_env = self.param_env; + let region_maps = self.tcx.region_maps(item_def_id); + euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_maps, self.tables) + .consume_body(body); self.visit_body(body); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 8b76431fd2e6..29742469f84d 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -219,7 +219,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env, normalize_cause.clone()); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let inh = Inherited::new(infcx, impl_m.def_id); let infcx = &inh.infcx; @@ -726,7 +726,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_trait_ref: ty::TraitRef<'tcx>) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let inh = Inherited::new(infcx, impl_c.def_id); let infcx = &inh.infcx; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index bff9289de505..93057f91997d 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -79,7 +79,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( // check that the impl type can be made to match the trait type. - tcx.infer_ctxt(()).enter(|ref infcx| { + tcx.infer_ctxt().enter(|ref infcx| { let impl_param_env = tcx.param_env(self_type_did); let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 04469dcaf2bd..844065cb3348 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -108,7 +108,7 @@ use lint; use util::common::{ErrorReported, indenter}; use util::nodemap::{DefIdMap, FxHashMap, NodeMap}; -use std::cell::{Cell, RefCell}; +use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::hash_map::Entry; use std::cmp; use std::mem::replace; @@ -147,6 +147,33 @@ mod compare_method; mod intrinsic; mod op; +/// A wrapper for InferCtxt's `in_progress_tables` field. +#[derive(Copy, Clone)] +struct MaybeInProgressTables<'a, 'tcx: 'a> { + maybe_tables: Option<&'a RefCell>>, +} + +impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { + fn borrow(self) -> Ref<'a, ty::TypeckTables<'tcx>> { + match self.maybe_tables { + Some(tables) => tables.borrow(), + None => { + bug!("MaybeInProgressTables: inh/fcx.tables.borrow() with no tables") + } + } + } + + fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> { + match self.maybe_tables { + Some(tables) => tables.borrow_mut(), + None => { + bug!("MaybeInProgressTables: inh/fcx.tables.borrow_mut() with no tables") + } + } + } +} + + /// closures defined within the function. For example: /// /// fn foo() { @@ -159,6 +186,8 @@ mod op; pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: InferCtxt<'a, 'gcx, 'tcx>, + tables: MaybeInProgressTables<'a, 'tcx>, + locals: RefCell>>, fulfillment_cx: RefCell>, @@ -535,9 +564,8 @@ pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId) -> InheritedBuilder<'a, 'gcx, 'tcx> { - let tables = ty::TypeckTables::empty(); InheritedBuilder { - infcx: tcx.infer_ctxt(tables), + infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(), def_id, } } @@ -562,6 +590,9 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { }); Inherited { + tables: MaybeInProgressTables { + maybe_tables: infcx.in_progress_tables, + }, infcx: infcx, fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), locals: RefCell::new(NodeMap()), @@ -3302,14 +3333,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_has_type(base_expr, struct_ty); match struct_ty.sty { ty::TyAdt(adt, substs) if adt.is_struct() => { - self.tables.borrow_mut().fru_field_types.insert( - expr.id, - adt.struct_variant().fields.iter().map(|f| { - self.normalize_associated_types_in( - expr.span, &f.ty(self.tcx, substs) - ) - }).collect() - ); + let fru_field_types = adt.struct_variant().fields.iter().map(|f| { + self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) + }).collect(); + self.tables.borrow_mut().fru_field_types.insert(expr.id, fru_field_types); } _ => { span_err!(self.tcx.sess, base_expr.span, E0436, @@ -4186,7 +4213,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::StmtSemi(ref e, _) => e, _ => return, }; - let last_expr_ty = self.expr_ty(last_expr); + let last_expr_ty = self.node_ty(last_expr.id); if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { return; } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b66e311f04c6..952321c946bf 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -824,18 +824,24 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } + /// Create a temporary `MemCategorizationContext` and pass it to the closure. + fn with_mc(&self, f: F) -> R + where F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'gcx, 'tcx>) -> R + { + f(mc::MemCategorizationContext::with_infer(&self.infcx, + &self.region_maps, + &self.tables.borrow())) + } + /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// dereferenced, the lifetime of the pointer includes the deref expr. fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult> { debug!("constrain_adjustments(expr={:?})", expr); - let mut cmt = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - mc.cat_expr_unadjusted(expr)? - }; + let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; - //NOTE(@jroesch): mixed RefCell borrow causes crash - let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec(); + let tables = self.tables.borrow(); + let adjustments = tables.expr_adjustments(&expr); if adjustments.is_empty() { return Ok(cmt); } @@ -886,10 +892,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { expr.id, expr_region); } - { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?; - } + cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?; if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat { self.mk_subregion_due_to_dereference(expr.span, @@ -981,10 +984,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { mutability: hir::Mutability, base: &hir::Expr) { debug!("link_addr_of(expr={:?}, base={:?})", expr, base); - let cmt = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - ignore_err!(mc.cat_expr(base)) - }; + let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base))); debug!("link_addr_of: cmt={:?}", cmt); @@ -1000,9 +1000,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { None => { return; } Some(ref expr) => &**expr, }; - let mc = &mc::MemCategorizationContext::new(self, &self.region_maps); - let discr_cmt = ignore_err!(mc.cat_expr(init_expr)); - self.link_pattern(mc, discr_cmt, &local.pat); + let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); + self.link_pattern(discr_cmt, &local.pat); } /// Computes the guarantors for any ref bindings in a match and @@ -1010,12 +1009,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// linked to the lifetime of its guarantor (if any). fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { debug!("regionck::for_match()"); - let mc = &mc::MemCategorizationContext::new(self, &self.region_maps); - let discr_cmt = ignore_err!(mc.cat_expr(discr)); + let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { for root_pat in &arm.pats { - self.link_pattern(mc, discr_cmt.clone(), &root_pat); + self.link_pattern(discr_cmt.clone(), &root_pat); } } } @@ -1025,30 +1023,28 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// linked to the lifetime of its guarantor (if any). fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) { debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - let mc = &mc::MemCategorizationContext::new(self, &self.region_maps); for arg in args { let arg_ty = self.node_ty(arg.id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); - let arg_cmt = mc.cat_rvalue( - arg.id, arg.pat.span, re_scope, arg_ty); + let arg_cmt = self.with_mc(|mc| { + mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty) + }); debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, arg_cmt, arg); - self.link_pattern(mc, arg_cmt, &arg.pat); + self.link_pattern(arg_cmt, &arg.pat); } } /// Link lifetimes of any ref bindings in `root_pat` to the pointers found /// in the discriminant, if needed. - fn link_pattern<'t>(&self, - mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, - discr_cmt: mc::cmt<'tcx>, - root_pat: &hir::Pat) { + fn link_pattern(&self, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); - let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| { + let _ = self.with_mc(|mc| { + mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| { match sub_pat.node { // `ref x` pattern PatKind::Binding(hir::BindByRef(mutbl), ..) => { @@ -1057,7 +1053,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } _ => {} } - }); + }) + }); } /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being @@ -1215,8 +1212,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // Detect by-ref upvar `x`: let cause = match note { mc::NoteUpvarRef(ref upvar_id) => { - let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map; - match upvar_capture_map.get(upvar_id) { + match self.tables.borrow().upvar_capture_map.get(upvar_id) { Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => { // The mutability of the upvar may have been modified // by the above adjustment, so update our local variable. diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 25f5418bea9c..59ca896b347f 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -53,31 +53,22 @@ use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::util::nodemap::NodeMap; -/////////////////////////////////////////////////////////////////////////// -// PUBLIC ENTRY POINTS +use std::collections::hash_map::Entry; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { - let mut seed = SeedBorrowKind::new(self); - seed.visit_body(body); - - let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); - adjust.visit_body(body); + InferBorrowKindVisitor { fcx: self }.visit_body(body); // it's our job to process these. assert!(self.deferred_call_resolutions.borrow().is_empty()); } } -/////////////////////////////////////////////////////////////////////////// -// SEED BORROW KIND - -struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct InferBorrowKindVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { NestedVisitorMap::None } @@ -87,7 +78,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { hir::ExprClosure(cc, _, body_id, _) => { let body = self.fcx.tcx.hir.body(body_id); self.visit_body(body); - self.check_closure(expr, cc); + self.fcx.analyze_closure(expr.id, expr.span, body, cc); } _ => { } @@ -97,26 +88,33 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { - fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> { - SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() } - } +impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { + fn analyze_closure(&self, + id: ast::NodeId, + span: Span, + body: &hir::Body, + capture_clause: hir::CaptureClause) { + /*! + * Analysis starting point. + */ - fn check_closure(&mut self, - expr: &hir::Expr, - capture_clause: hir::CaptureClause) - { - if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) { - self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None)); - debug!("check_closure: adding closure {:?} as Fn", expr.id); - } + debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); - self.fcx.tcx.with_freevars(expr.id, |freevars| { + let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(id) { + Entry::Occupied(_) => false, + Entry::Vacant(entry) => { + debug!("check_closure: adding closure {:?} as Fn", id); + entry.insert((ty::ClosureKind::Fn, None)); + true + } + }; + + self.tcx.with_freevars(id, |freevars| { for freevar in freevars { let def_id = freevar.def.def_id(); - let var_node_id = self.fcx.tcx.hir.as_local_node_id(def_id).unwrap(); + let var_node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let upvar_id = ty::UpvarId { var_id: var_node_id, - closure_expr_id: expr.id }; + closure_expr_id: id }; debug!("seed upvar_id {:?}", upvar_id); let capture_kind = match capture_clause { @@ -124,58 +122,41 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { ty::UpvarCapture::ByValue } hir::CaptureByRef => { - let origin = UpvarRegion(upvar_id, expr.span); - let freevar_region = self.fcx.next_region_var(origin); + let origin = UpvarRegion(upvar_id, span); + let freevar_region = self.next_region_var(origin); let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: freevar_region }; ty::UpvarCapture::ByRef(upvar_borrow) } }; - self.fcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); + self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); } }); - } -} - -/////////////////////////////////////////////////////////////////////////// -// ADJUST BORROW KIND - -struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, -} - -impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { - fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>) - -> AdjustBorrowKind<'a, 'gcx, 'tcx> { - AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } - } - - fn analyze_closure(&mut self, - id: ast::NodeId, - span: Span, - body: &hir::Body) { - /*! - * Analysis starting point. - */ - - debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); { - let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id()); - let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id); - let param_env = self.fcx.param_env; - let mut euv = - euv::ExprUseVisitor::with_options(self, - self.fcx, - param_env, - region_maps, - mc::MemCategorizationOptions { - during_closure_kind_inference: true - }); - euv.consume_body(body); + let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id()); + let region_maps = &self.tcx.region_maps(body_owner_def_id); + let mut delegate = InferBorrowKind { + fcx: self, + adjust_closure_kinds: NodeMap(), + adjust_upvar_captures: ty::UpvarCaptureMap::default(), + }; + euv::ExprUseVisitor::with_infer(&mut delegate, + &self.infcx, + self.param_env, + region_maps, + &self.tables.borrow()) + .consume_body(body); + + // Write the adjusted values back into the main tables. + if infer_kind { + if let Some(kind) = delegate.adjust_closure_kinds.remove(&id) { + self.tables.borrow_mut().closure_kinds.insert(id, kind); + } + } + self.tables.borrow_mut().upvar_capture_map.extend( + delegate.adjust_upvar_captures); } // Now that we've analyzed the closure, we know how each @@ -191,7 +172,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // inference algorithm will reject it). // Extract the type variables UV0...UVn. - let (def_id, closure_substs) = match self.fcx.node_ty(id).sty { + let (def_id, closure_substs) = match self.node_ty(id).sty { ty::TyClosure(def_id, substs) => (def_id, substs), ref t => { span_bug!( @@ -206,44 +187,41 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", id, closure_substs, final_upvar_tys); for (upvar_ty, final_upvar_ty) in - closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys) + closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys) { - self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); + self.demand_eqtype(span, final_upvar_ty, upvar_ty); } - // If we are also inferred the closure kind here, update the - // main table and process any deferred resolutions. - if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) { - self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context)); - let closure_def_id = self.fcx.tcx.hir.local_def_id(id); - debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); - + // If we are also inferred the closure kind here, + // process any deferred resolutions. + if infer_kind { + let closure_def_id = self.tcx.hir.local_def_id(id); let deferred_call_resolutions = - self.fcx.remove_deferred_call_resolutions(closure_def_id); + self.remove_deferred_call_resolutions(closure_def_id); for deferred_call_resolution in deferred_call_resolutions { - deferred_call_resolution.resolve(self.fcx); + deferred_call_resolution.resolve(self); } } } // Returns a list of `ClosureUpvar`s for each upvar. - fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec> { + fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the // local crate or were inlined into it along with some function. // This may change if abstract return types of some sort are // implemented. - let tcx = self.fcx.tcx; + let tcx = self.tcx; tcx.with_freevars(closure_id, |freevars| { freevars.iter().map(|freevar| { let def_id = freevar.def.def_id(); let var_id = tcx.hir.as_local_node_id(def_id).unwrap(); - let freevar_ty = self.fcx.node_ty(var_id); + let freevar_ty = self.node_ty(var_id); let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: closure_id }; - let capture = self.fcx.upvar_capture(upvar_id).unwrap(); + let capture = self.tables.borrow().upvar_capture(upvar_id); debug!("var_id={:?} freevar_ty={:?} capture={:?}", var_id, freevar_ty, capture); @@ -260,7 +238,15 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { }).collect() }) } +} +struct InferBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + adjust_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, + adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, +} + +impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) @@ -297,9 +283,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { guarantor.span, tcx.hir.name(upvar_id.var_id)); - let upvar_capture_map = - &mut self.fcx.tables.borrow_mut().upvar_capture_map; - upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue); + self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); } mc::NoteClosureEnv(upvar_id) => { // we get just a closureenv ref if this is a @@ -410,11 +394,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // upvar, then we need to modify the // borrow_kind of the upvar to make sure it // is inferred to mutable if necessary - { - let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; - let ub = upvar_capture_map.get_mut(&upvar_id).unwrap(); - self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind); - } + self.adjust_upvar_borrow_kind(upvar_id, borrow_kind); // also need to be in an FnMut closure since this is not an ImmBorrow self.adjust_closure_kind(upvar_id.closure_expr_id, @@ -448,22 +428,25 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { /// some particular use. fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, - upvar_capture: &mut ty::UpvarCapture, kind: ty::BorrowKind) { + let upvar_capture = self.adjust_upvar_captures.get(&upvar_id).cloned() + .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id)); debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", upvar_id, upvar_capture, kind); - match *upvar_capture { + match upvar_capture { ty::UpvarCapture::ByValue => { // Upvar is already by-value, the strongest criteria. } - ty::UpvarCapture::ByRef(ref mut upvar_borrow) => { + ty::UpvarCapture::ByRef(mut upvar_borrow) => { match (upvar_borrow.kind, kind) { // Take RHS: (ty::ImmBorrow, ty::UniqueImmBorrow) | (ty::ImmBorrow, ty::MutBorrow) | (ty::UniqueImmBorrow, ty::MutBorrow) => { upvar_borrow.kind = kind; + self.adjust_upvar_captures.insert(upvar_id, + ty::UpvarCapture::ByRef(upvar_borrow)); } // Take LHS: (ty::ImmBorrow, ty::ImmBorrow) | @@ -484,7 +467,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})", closure_id, new_kind, upvar_span, var_name); - if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) { + let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned() + .or_else(|| self.fcx.tables.borrow().closure_kinds.get(&closure_id).cloned()); + if let Some((existing_kind, _)) = closure_kind { debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", closure_id, existing_kind, new_kind); @@ -500,7 +485,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind - self.temp_closure_kinds.insert( + self.adjust_closure_kinds.insert( closure_id, (new_kind, Some((upvar_span, var_name))) ); @@ -510,27 +495,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { - NestedVisitorMap::None - } - - fn visit_fn(&mut self, - fn_kind: intravisit::FnKind<'gcx>, - decl: &'gcx hir::FnDecl, - body: hir::BodyId, - span: Span, - id: ast::NodeId) - { - intravisit::walk_fn(self, fn_kind, decl, body, span, id); - - let body = self.fcx.tcx.hir.body(body); - self.visit_body(body); - self.analyze_closure(id, span, body); - } -} - -impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { fn consume(&mut self, _consume_id: ast::NodeId, _consume_span: Span, diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 377b7b069d33..ccbc02990418 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -208,7 +208,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source, target); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::misc(span, impl_node_id); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index afeb85a7a065..078ae34bc524 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt(()).enter(|infcx| { + self.tcx.infer_ctxt().enter(|infcx| { if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 06cb9f948c9b..26ea3ab3a335 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -155,7 +155,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { - tcx.infer_ctxt(()).enter(|ref infcx| { + tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut fulfill_cx = FulfillmentContext::new(); match infcx.at(&cause, param_env).eq(expected, actual) {