mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #42563 - eddyb:infer, r=nikomatsakis
Disentangle InferCtxt, MemCategorizationContext and ExprUseVisitor. At some point in the past, `InferCtxt` started being used to replace an old "`Typer`" abstraction, which provided access to `TypeckTables` and had optionally type inference to account for. That didn't play so nicely with the `'gcx`/`'tcx` split and I had to introduce `borrowck_fake_infer_ctxt`. The situation wasn't great but it wasn't too painful inside `rustc` itself. Recently I've found that method being used in clippy, which does need EUV (before we make it plausible to run lints on HAIR or MIR), and set out to separate inference from tables, for the sake of lint authors. Also fixes #42435 to make it trivial to compute type layout or use EUV from lints. The remaining uses of `TypeckTables` in `InferCtxt` are for closure kinds and signatures, used in trait selection and projection normalization. The solution there is likely to add them as bounds to `ParamEnv`. r? @nikomatsakis cc @mcarton @llogiq @Manishearth
This commit is contained in:
commit
b7613f8281
@ -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<T> = Option<T>;
|
||||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||
pub type FixupResult<T> = Result<T, FixupError>; // "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<ty::TypeckTables<'tcx>>),
|
||||
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<ty::TypeckTables<'tcx>>>,
|
||||
|
||||
// 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<ty::TypeckTables<'tcx>>);
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
|
||||
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (Option<&'a ty::TypeckTables<'tcx>>,
|
||||
Option<ty::TypeckTables<'tcx>>) {
|
||||
(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<ty::TypeckTables<'tcx>>) {
|
||||
(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<ty::TypeckTables<'tcx>>) {
|
||||
(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<ty::TypeckTables<'tcx>>) {
|
||||
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<RefCell<ty::TypeckTables<'tcx>>>,
|
||||
tables: Option<&'a ty::TypeckTables<'gcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(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<F, R>(&'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<Ty<'tcx>> {
|
||||
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<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
|
||||
/*!
|
||||
* 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<Ty<'tcx>> {
|
||||
let ty = self.node_type(id);
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
}
|
||||
|
||||
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
|
||||
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<ty::UpvarCapture<'tcx>> {
|
||||
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
|
||||
}
|
||||
|
||||
pub fn closure_kind(&self,
|
||||
def_id: DefId)
|
||||
-> Option<ty::ClosureKind>
|
||||
{
|
||||
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;
|
||||
|
@ -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<F>(&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),
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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<T> = Result<T, ()>;
|
||||
@ -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<Ty<'tcx>> {
|
||||
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<T>(&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<Ty<'tcx>>)
|
||||
-> McResult<Ty<'tcx>> {
|
||||
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<Ty<'tcx>> {
|
||||
self.infcx.expr_ty_adjusted(expr)
|
||||
pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
|
||||
self.resolve_type_vars_or_error(id, self.tables.node_id_to_type_opt(id))
|
||||
}
|
||||
|
||||
fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
|
||||
self.infcx.node_ty(id)
|
||||
pub fn expr_ty(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
|
||||
self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_opt(expr))
|
||||
}
|
||||
|
||||
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
|
||||
self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_adjusted_opt(expr))
|
||||
}
|
||||
|
||||
fn pat_ty(&self, pat: &hir::Pat) -> McResult<Ty<'tcx>> {
|
||||
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<cmt<'tcx>>
|
||||
{
|
||||
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<cmt<'tcx>>
|
||||
{
|
||||
// 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<F>(&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_<F>(&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 {
|
||||
|
@ -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 \
|
||||
|
@ -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();
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -376,8 +376,8 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -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<Loan<'tcx>>, 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<Loan<'tcx>>,
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {}
|
||||
|
@ -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(),
|
||||
|
@ -154,7 +154,7 @@ fn test_env<F>(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,
|
||||
|
@ -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, \
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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<RegionMaps>,
|
||||
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 {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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<ty::TypeckTables<'tcx>>>,
|
||||
}
|
||||
|
||||
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<NodeMap<Ty<'tcx>>>,
|
||||
|
||||
fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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<F, R>(&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<mc::cmt<'tcx>> {
|
||||
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.
|
||||
|
@ -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<Ty<'tcx>> {
|
||||
fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
|
||||
// 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,
|
||||
|
@ -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>,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user