Skip to content

Commit b7613f8

Browse files
committed
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
2 parents 995f741 + fc5c31c commit b7613f8

File tree

32 files changed

+440
-625
lines changed

32 files changed

+440
-625
lines changed

src/librustc/infer/mod.rs

Lines changed: 30 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,8 @@ pub use self::freshen::TypeFreshener;
1919
pub use self::region_inference::{GenericKind, VerifyBound};
2020

2121
use hir::def_id::DefId;
22-
use hir;
2322
use middle::free_region::{FreeRegionMap, RegionRelations};
2423
use middle::region::RegionMaps;
25-
use middle::mem_categorization as mc;
26-
use middle::mem_categorization::McResult;
2724
use middle::lang_items;
2825
use mir::tcx::LvalueTy;
2926
use ty::subst::{Kind, Subst, Substs};
@@ -34,9 +31,8 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
3431
use ty::relate::RelateResult;
3532
use traits::{self, ObligationCause, PredicateObligations, Reveal};
3633
use rustc_data_structures::unify::{self, UnificationTable};
37-
use std::cell::{Cell, RefCell, Ref, RefMut};
34+
use std::cell::{Cell, RefCell, Ref};
3835
use std::fmt;
39-
use std::ops::Deref;
4036
use syntax::ast;
4137
use errors::DiagnosticBuilder;
4238
use syntax_pos::{self, Span, DUMMY_SP};
@@ -76,71 +72,14 @@ pub type Bound<T> = Option<T>;
7672
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
7773
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
7874

79-
/// A version of &ty::TypeckTables which can be `Missing` (not needed),
80-
/// `InProgress` (during typeck) or `Interned` (result of typeck).
81-
/// Only the `InProgress` version supports `borrow_mut`.
82-
#[derive(Copy, Clone)]
83-
pub enum InferTables<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
84-
Interned(&'a ty::TypeckTables<'gcx>),
85-
InProgress(&'a RefCell<ty::TypeckTables<'tcx>>),
86-
Missing
87-
}
88-
89-
pub enum InferTablesRef<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
90-
Interned(&'a ty::TypeckTables<'gcx>),
91-
InProgress(Ref<'a, ty::TypeckTables<'tcx>>)
92-
}
93-
94-
impl<'a, 'gcx, 'tcx> Deref for InferTablesRef<'a, 'gcx, 'tcx> {
95-
type Target = ty::TypeckTables<'tcx>;
96-
fn deref(&self) -> &Self::Target {
97-
match *self {
98-
InferTablesRef::Interned(tables) => tables,
99-
InferTablesRef::InProgress(ref tables) => tables
100-
}
101-
}
102-
}
103-
104-
impl<'a, 'gcx, 'tcx> InferTables<'a, 'gcx, 'tcx> {
105-
pub fn borrow(self) -> InferTablesRef<'a, 'gcx, 'tcx> {
106-
match self {
107-
InferTables::Interned(tables) => InferTablesRef::Interned(tables),
108-
InferTables::InProgress(tables) => InferTablesRef::InProgress(tables.borrow()),
109-
InferTables::Missing => {
110-
bug!("InferTables: infcx.tables.borrow() with no tables")
111-
}
112-
}
113-
}
114-
115-
pub fn expect_interned(self) -> &'a ty::TypeckTables<'gcx> {
116-
match self {
117-
InferTables::Interned(tables) => tables,
118-
InferTables::InProgress(_) => {
119-
bug!("InferTables: infcx.tables.expect_interned() during type-checking");
120-
}
121-
InferTables::Missing => {
122-
bug!("InferTables: infcx.tables.expect_interned() with no tables")
123-
}
124-
}
125-
}
126-
127-
pub fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> {
128-
match self {
129-
InferTables::Interned(_) => {
130-
bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking");
131-
}
132-
InferTables::InProgress(tables) => tables.borrow_mut(),
133-
InferTables::Missing => {
134-
bug!("InferTables: infcx.tables.borrow_mut() with no tables")
135-
}
136-
}
137-
}
138-
}
139-
14075
pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
14176
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
14277

143-
pub tables: InferTables<'a, 'gcx, 'tcx>,
78+
/// During type-checking/inference of a body, `in_progress_tables`
79+
/// contains a reference to the tables being built up, which are
80+
/// used for reading closure kinds/signatures as they are inferred,
81+
/// and for error reporting logic to read arbitrary node types.
82+
pub in_progress_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>,
14483

14584
// Cache for projections. This cache is snapshotted along with the
14685
// infcx.
@@ -396,106 +335,45 @@ impl fmt::Display for FixupError {
396335
}
397336
}
398337

399-
pub trait InferEnv<'a, 'tcx> {
400-
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
401-
-> (Option<&'a ty::TypeckTables<'tcx>>,
402-
Option<ty::TypeckTables<'tcx>>);
403-
}
404-
405-
impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
406-
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
407-
-> (Option<&'a ty::TypeckTables<'tcx>>,
408-
Option<ty::TypeckTables<'tcx>>) {
409-
(None, None)
410-
}
411-
}
412-
413-
impl<'a, 'tcx> InferEnv<'a, 'tcx> for &'a ty::TypeckTables<'tcx> {
414-
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
415-
-> (Option<&'a ty::TypeckTables<'tcx>>,
416-
Option<ty::TypeckTables<'tcx>>) {
417-
(Some(self), None)
418-
}
419-
}
420-
421-
impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::TypeckTables<'tcx> {
422-
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
423-
-> (Option<&'a ty::TypeckTables<'tcx>>,
424-
Option<ty::TypeckTables<'tcx>>) {
425-
(None, Some(self))
426-
}
427-
}
428-
429-
impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
430-
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
431-
-> (Option<&'a ty::TypeckTables<'tcx>>,
432-
Option<ty::TypeckTables<'tcx>>) {
433-
let def_id = tcx.hir.body_owner_def_id(self);
434-
(Some(tcx.typeck_tables_of(def_id)), None)
435-
}
436-
}
437-
438-
/// Helper type of a temporary returned by tcx.infer_ctxt(...).
338+
/// Helper type of a temporary returned by tcx.infer_ctxt().
439339
/// Necessary because we can't write the following bound:
440340
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>).
441341
pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
442342
global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
443343
arena: DroplessArena,
444344
fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
445-
tables: Option<&'a ty::TypeckTables<'gcx>>,
446345
}
447346

448347
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
449-
pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
450-
let (tables, fresh_tables) = env.to_parts(self);
348+
pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
451349
InferCtxtBuilder {
452350
global_tcx: self,
453351
arena: DroplessArena::new(),
454-
fresh_tables: fresh_tables.map(RefCell::new),
455-
tables: tables,
456-
}
457-
}
458-
459-
/// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck
460-
/// for MemCategorizationContext/ExprUseVisitor.
461-
/// If any inference functionality is used, ICEs will occur.
462-
pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
463-
-> InferCtxt<'a, 'gcx, 'gcx> {
464-
let (tables, _) = body.to_parts(self);
465-
InferCtxt {
466-
tcx: self,
467-
tables: InferTables::Interned(tables.unwrap()),
468-
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
469-
int_unification_table: RefCell::new(UnificationTable::new()),
470-
float_unification_table: RefCell::new(UnificationTable::new()),
471-
region_vars: RegionVarBindings::new(self),
472-
selection_cache: traits::SelectionCache::new(),
473-
evaluation_cache: traits::EvaluationCache::new(),
474-
projection_cache: RefCell::new(traits::ProjectionCache::new()),
475-
reported_trait_errors: RefCell::new(FxHashSet()),
476-
tainted_by_errors_flag: Cell::new(false),
477-
err_count_on_creation: self.sess.err_count(),
478-
in_snapshot: Cell::new(false),
352+
fresh_tables: None,
479353
}
480354
}
481355
}
482356

483357
impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
358+
/// Used only by `rustc_typeck` during body type-checking/inference,
359+
/// will initialize `in_progress_tables` with fresh `TypeckTables`.
360+
pub fn with_fresh_in_progress_tables(mut self) -> Self {
361+
self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty()));
362+
self
363+
}
364+
484365
pub fn enter<F, R>(&'tcx mut self, f: F) -> R
485366
where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R
486367
{
487368
let InferCtxtBuilder {
488369
global_tcx,
489370
ref arena,
490371
ref fresh_tables,
491-
tables,
492372
} = *self;
493-
let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
494-
fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
495-
});
373+
let in_progress_tables = fresh_tables.as_ref();
496374
global_tcx.enter_local(arena, |tcx| f(InferCtxt {
497-
tcx: tcx,
498-
tables: tables,
375+
tcx,
376+
in_progress_tables,
499377
projection_cache: RefCell::new(traits::ProjectionCache::new()),
500378
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
501379
int_unification_table: RefCell::new(UnificationTable::new()),
@@ -618,7 +496,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
618496
return value;
619497
}
620498

621-
self.infer_ctxt(()).enter(|infcx| {
499+
self.infer_ctxt().enter(|infcx| {
622500
value.trans_normalize(&infcx, param_env)
623501
})
624502
}
@@ -640,7 +518,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
640518
return value;
641519
}
642520

643-
self.infer_ctxt(()).enter(|infcx| {
521+
self.infer_ctxt().enter(|infcx| {
644522
value.trans_normalize(&infcx, env.reveal_all())
645523
})
646524
}
@@ -844,10 +722,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
844722
was_in_snapshot: in_snapshot,
845723
// Borrow tables "in progress" (i.e. during typeck)
846724
// to ban writes from within a snapshot to them.
847-
_in_progress_tables: match self.tables {
848-
InferTables::InProgress(ref tables) => tables.try_borrow().ok(),
849-
_ => None
850-
}
725+
_in_progress_tables: self.in_progress_tables.map(|tables| {
726+
tables.borrow()
727+
})
851728
}
852729
}
853730

@@ -1190,28 +1067,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11901067
self.tainted_by_errors_flag.set(true)
11911068
}
11921069

1193-
pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> {
1194-
match self.tables.borrow().node_types.get(&id) {
1195-
Some(&t) => t,
1196-
// FIXME
1197-
None if self.is_tainted_by_errors() =>
1198-
self.tcx.types.err,
1199-
None => {
1200-
bug!("no type for node {}: {} in fcx",
1201-
id, self.tcx.hir.node_to_string(id));
1202-
}
1203-
}
1204-
}
1205-
1206-
pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
1207-
match self.tables.borrow().node_types.get(&ex.id) {
1208-
Some(&t) => t,
1209-
None => {
1210-
bug!("no type for expr in fcx");
1211-
}
1212-
}
1213-
}
1214-
12151070
pub fn resolve_regions_and_report_errors(&self,
12161071
region_context: DefId,
12171072
region_map: &RegionMaps,
@@ -1310,21 +1165,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
13101165
value.fold_with(&mut r)
13111166
}
13121167

1313-
/// Resolves all type variables in `t` and then, if any were left
1314-
/// unresolved, substitutes an error type. This is used after the
1315-
/// main checking when doing a second pass before writeback. The
1316-
/// justification is that writeback will produce an error for
1317-
/// these unconstrained type variables.
1318-
fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
1319-
let ty = self.resolve_type_vars_if_possible(t);
1320-
if ty.references_error() || ty.is_ty_var() {
1321-
debug!("resolve_type_vars_or_error: error from {:?}", ty);
1322-
Err(())
1323-
} else {
1324-
Ok(ty)
1325-
}
1326-
}
1327-
13281168
pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
13291169
/*!
13301170
* Attempts to resolve all type/region variables in
@@ -1484,30 +1324,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
14841324
self.region_vars.verify_generic_bound(origin, kind, a, bound);
14851325
}
14861326

1487-
pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
1488-
let ty = self.node_type(id);
1489-
self.resolve_type_vars_or_error(&ty)
1490-
}
1491-
1492-
pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
1493-
let ty = self.tables.borrow().expr_ty_adjusted(expr);
1494-
self.resolve_type_vars_or_error(&ty)
1495-
}
1496-
14971327
pub fn type_moves_by_default(&self,
14981328
param_env: ty::ParamEnv<'tcx>,
14991329
ty: Ty<'tcx>,
15001330
span: Span)
15011331
-> bool {
15021332
let ty = self.resolve_type_vars_if_possible(&ty);
1503-
if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
1504-
// Even if the type may have no inference variables, during
1505-
// type-checking closure types are in local tables only.
1506-
let local_closures = match self.tables {
1507-
InferTables::InProgress(_) => ty.has_closure_types(),
1508-
_ => false
1509-
};
1510-
if !local_closures {
1333+
// Even if the type may have no inference variables, during
1334+
// type-checking closure types are in local tables only.
1335+
if !self.in_progress_tables.is_some() || !ty.has_closure_types() {
1336+
if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
15111337
return ty.moves_by_default(self.tcx.global_tcx(), param_env, span);
15121338
}
15131339
}
@@ -1521,15 +1347,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
15211347
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
15221348
}
15231349

1524-
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
1525-
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
1526-
}
1527-
15281350
pub fn closure_kind(&self,
15291351
def_id: DefId)
15301352
-> Option<ty::ClosureKind>
15311353
{
1532-
if let InferTables::InProgress(tables) = self.tables {
1354+
if let Some(tables) = self.in_progress_tables {
15331355
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
15341356
return tables.borrow()
15351357
.closure_kinds
@@ -1547,7 +1369,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
15471369
}
15481370

15491371
pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
1550-
if let InferTables::InProgress(tables) = self.tables {
1372+
if let Some(tables) = self.in_progress_tables {
15511373
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
15521374
if let Some(&ty) = tables.borrow().closure_tys.get(&id) {
15531375
return ty;

0 commit comments

Comments
 (0)