Auto merge of #38813 - eddyb:lazy-11, r=nikomatsakis
[11/n] Separate ty::Tables into one per each body. _This is part of a series ([prev](https://github.com/rust-lang/rust/pull/38449) | [next]()) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well. If any motivation is unclear, please ask for additional PR description clarifications or code comments._ <hr> In order to track the results of type-checking and inference for incremental recompilation, they must be stored separately for each function or constant value, instead of lumped together. These side-`Tables` also have to be tracked by various passes, as they visit through bodies (all of which have `Tables`, even if closures share the ones from their parent functions). This is usually done by switching a `tables` field in an override of `visit_nested_body` before recursing through `visit_body`, to the relevant one and then restoring it - however, in many cases the nesting is unnecessary and creating the visitor for each body in the crate and then visiting that body, would be a much cleaner solution. To simplify handling of inlined HIR & its side-tables, their `NodeId` remapping and entries HIR map were fully stripped out, which means that `NodeId`s from inlined HIR must not be used where a local `NodeId` is expected. It might be possible to make the nodes (`Expr`, `Block`, `Pat`, etc.) that only show up within a `Body` have IDs that are scoped to that `Body`, which would also allow `Tables` to use `Vec`s. That last part also fixes #38790 which was accidentally introduced in a previous refactor.
This commit is contained in:
commit
cbf88730e7
76 changed files with 1128 additions and 1415 deletions
|
|
@ -18,6 +18,7 @@ use hir::{self, PatKind};
|
|||
|
||||
struct CFGBuilder<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: &'a ty::Tables<'tcx>,
|
||||
graph: CFGGraph,
|
||||
fn_exit: CFGIndex,
|
||||
loop_scopes: Vec<LoopScope>,
|
||||
|
|
@ -42,10 +43,23 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let fn_exit = graph.add_node(CFGNodeData::Exit);
|
||||
let body_exit;
|
||||
|
||||
// Find the function this expression is from.
|
||||
let mut node_id = body.id;
|
||||
loop {
|
||||
let node = tcx.map.get(node_id);
|
||||
if hir::map::blocks::FnLikeNode::from_node(node).is_some() {
|
||||
break;
|
||||
}
|
||||
let parent = tcx.map.get_parent_node(node_id);
|
||||
assert!(node_id != parent);
|
||||
node_id = parent;
|
||||
}
|
||||
|
||||
let mut cfg_builder = CFGBuilder {
|
||||
tcx: tcx,
|
||||
tables: tcx.item_tables(tcx.map.local_def_id(node_id)),
|
||||
graph: graph,
|
||||
fn_exit: fn_exit,
|
||||
tcx: tcx,
|
||||
loop_scopes: Vec::new()
|
||||
};
|
||||
body_exit = cfg_builder.expr(body, entry);
|
||||
|
|
@ -310,11 +324,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
hir::ExprIndex(ref l, ref r) |
|
||||
hir::ExprBinary(_, ref l, ref r) if self.tcx.tables().is_method_call(expr.id) => {
|
||||
hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => {
|
||||
self.call(expr, pred, &l, Some(&**r).into_iter())
|
||||
}
|
||||
|
||||
hir::ExprUnary(_, ref e) if self.tcx.tables().is_method_call(expr.id) => {
|
||||
hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => {
|
||||
self.call(expr, pred, &e, None::<hir::Expr>.iter())
|
||||
}
|
||||
|
||||
|
|
@ -368,9 +382,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
func_or_rcvr: &hir::Expr,
|
||||
args: I) -> CFGIndex {
|
||||
let method_call = ty::MethodCall::expr(call_expr.id);
|
||||
let fn_ty = match self.tcx.tables().method_map.get(&method_call) {
|
||||
let fn_ty = match self.tables.method_map.get(&method_call) {
|
||||
Some(method) => method.ty,
|
||||
None => self.tcx.tables().expr_ty_adjusted(func_or_rcvr)
|
||||
None => self.tables.expr_ty_adjusted(func_or_rcvr)
|
||||
};
|
||||
|
||||
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
SizedConstraint(D),
|
||||
AssociatedItemDefIds(D),
|
||||
InherentImpls(D),
|
||||
Tables(D),
|
||||
|
||||
// The set of impls for a given trait. Ultimately, it would be
|
||||
// nice to get more fine-grained here (e.g., to include a
|
||||
|
|
@ -162,6 +163,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
ItemSignature,
|
||||
AssociatedItemDefIds,
|
||||
InherentImpls,
|
||||
Tables,
|
||||
TraitImpls,
|
||||
ReprHints,
|
||||
}
|
||||
|
|
@ -230,6 +232,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
SizedConstraint(ref d) => op(d).map(SizedConstraint),
|
||||
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
|
||||
InherentImpls(ref d) => op(d).map(InherentImpls),
|
||||
Tables(ref d) => op(d).map(Tables),
|
||||
TraitImpls(ref d) => op(d).map(TraitImpls),
|
||||
TraitItems(ref d) => op(d).map(TraitItems),
|
||||
ReprHints(ref d) => op(d).map(ReprHints),
|
||||
|
|
|
|||
|
|
@ -45,15 +45,6 @@ pub struct FnLikeNode<'a> { node: map::Node<'a> }
|
|||
/// corresponds to some FnLikeNode.
|
||||
pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
|
||||
|
||||
/// Components shared by fn-like things (fn items, methods, closures).
|
||||
pub struct FnParts<'a> {
|
||||
pub decl: &'a FnDecl,
|
||||
pub body: ast::BodyId,
|
||||
pub kind: FnKind<'a>,
|
||||
pub span: Span,
|
||||
pub id: NodeId,
|
||||
}
|
||||
|
||||
impl MaybeFnLike for ast::Item {
|
||||
fn is_fn_like(&self) -> bool {
|
||||
match self.node { ast::ItemFn(..) => true, _ => false, }
|
||||
|
|
@ -165,16 +156,6 @@ impl<'a> FnLikeNode<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_fn_parts(self) -> FnParts<'a> {
|
||||
FnParts {
|
||||
decl: self.decl(),
|
||||
body: self.body(),
|
||||
kind: self.kind(),
|
||||
span: self.span(),
|
||||
id: self.id(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn body(self) -> ast::BodyId {
|
||||
self.handle(|i: ItemFnParts<'a>| i.body,
|
||||
|_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ pub struct NodeCollector<'ast> {
|
|||
pub(super) map: Vec<MapEntry<'ast>>,
|
||||
/// The parent of this node
|
||||
pub parent_node: NodeId,
|
||||
/// If true, completely ignore nested items. We set this when loading
|
||||
/// HIR from metadata, since in that case we only want the HIR for
|
||||
/// one specific item (and not the ones nested inside of it).
|
||||
pub ignore_nested_items: bool
|
||||
}
|
||||
|
||||
impl<'ast> NodeCollector<'ast> {
|
||||
|
|
@ -35,30 +31,12 @@ impl<'ast> NodeCollector<'ast> {
|
|||
krate: krate,
|
||||
map: vec![],
|
||||
parent_node: CRATE_NODE_ID,
|
||||
ignore_nested_items: false
|
||||
};
|
||||
collector.insert_entry(CRATE_NODE_ID, RootCrate);
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
pub(super) fn extend(krate: &'ast Crate,
|
||||
parent: &'ast InlinedItem,
|
||||
parent_node: NodeId,
|
||||
map: Vec<MapEntry<'ast>>)
|
||||
-> NodeCollector<'ast> {
|
||||
let mut collector = NodeCollector {
|
||||
krate: krate,
|
||||
map: map,
|
||||
parent_node: parent_node,
|
||||
ignore_nested_items: true
|
||||
};
|
||||
|
||||
collector.insert_entry(parent_node, RootInlinedParent(parent));
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
|
||||
debug!("ast_map: {:?} => {:?}", id, entry);
|
||||
let len = self.map.len();
|
||||
|
|
@ -92,27 +70,19 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
|||
|
||||
fn visit_nested_item(&mut self, item: ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item);
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_item(self.krate.item(item.id))
|
||||
}
|
||||
self.visit_item(self.krate.item(item.id));
|
||||
}
|
||||
|
||||
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_trait_item(self.krate.trait_item(item_id))
|
||||
}
|
||||
self.visit_trait_item(self.krate.trait_item(item_id));
|
||||
}
|
||||
|
||||
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_impl_item(self.krate.impl_item(item_id))
|
||||
}
|
||||
self.visit_impl_item(self.krate.impl_item(item_id));
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, id: BodyId) {
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_body(self.krate.body(id))
|
||||
}
|
||||
self.visit_body(self.krate.body(id));
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'ast Item) {
|
||||
|
|
|
|||
|
|
@ -25,28 +25,18 @@ use syntax::codemap::Spanned;
|
|||
use syntax_pos::Span;
|
||||
|
||||
use hir::*;
|
||||
use hir::intravisit::Visitor;
|
||||
use hir::print::Nested;
|
||||
use util::nodemap::DefIdMap;
|
||||
|
||||
use arena::TypedArena;
|
||||
use std::cell::RefCell;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
|
||||
pub mod blocks;
|
||||
mod collector;
|
||||
mod def_collector;
|
||||
pub mod definitions;
|
||||
|
||||
/// The data we save and restore about an inlined item or method. This is not
|
||||
/// part of the AST that we parse from a file, but it becomes part of the tree
|
||||
/// that we trans.
|
||||
#[derive(Debug)]
|
||||
struct InlinedItem {
|
||||
def_id: DefId,
|
||||
body: Body,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Node<'ast> {
|
||||
NodeItem(&'ast Item),
|
||||
|
|
@ -99,7 +89,6 @@ enum MapEntry<'ast> {
|
|||
|
||||
/// Roots for node trees.
|
||||
RootCrate,
|
||||
RootInlinedParent(&'ast InlinedItem)
|
||||
}
|
||||
|
||||
impl<'ast> Clone for MapEntry<'ast> {
|
||||
|
|
@ -152,8 +141,7 @@ impl<'ast> MapEntry<'ast> {
|
|||
EntryVisibility(id, _) => id,
|
||||
|
||||
NotPresent |
|
||||
RootCrate |
|
||||
RootInlinedParent(_) => return None,
|
||||
RootCrate => return None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +213,7 @@ impl<'ast> MapEntry<'ast> {
|
|||
pub struct Forest {
|
||||
krate: Crate,
|
||||
pub dep_graph: DepGraph,
|
||||
inlined_items: TypedArena<InlinedItem>
|
||||
inlined_bodies: TypedArena<Body>
|
||||
}
|
||||
|
||||
impl Forest {
|
||||
|
|
@ -233,7 +221,7 @@ impl Forest {
|
|||
Forest {
|
||||
krate: krate,
|
||||
dep_graph: dep_graph.clone(),
|
||||
inlined_items: TypedArena::new()
|
||||
inlined_bodies: TypedArena::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,20 +251,15 @@ pub struct Map<'ast> {
|
|||
///
|
||||
/// Also, indexing is pretty quick when you've got a vector and
|
||||
/// plain old integers.
|
||||
map: RefCell<Vec<MapEntry<'ast>>>,
|
||||
map: Vec<MapEntry<'ast>>,
|
||||
|
||||
definitions: Definitions,
|
||||
|
||||
/// All NodeIds that are numerically greater or equal to this value come
|
||||
/// from inlined items.
|
||||
local_node_id_watermark: NodeId,
|
||||
/// Bodies inlined from other crates are cached here.
|
||||
inlined_bodies: RefCell<DefIdMap<&'ast Body>>,
|
||||
}
|
||||
|
||||
impl<'ast> Map<'ast> {
|
||||
pub fn is_inlined_node_id(&self, id: NodeId) -> bool {
|
||||
id >= self.local_node_id_watermark
|
||||
}
|
||||
|
||||
/// Registers a read in the dependency graph of the AST node with
|
||||
/// the given `id`. This needs to be called each time a public
|
||||
/// function returns the HIR for a node -- in other words, when it
|
||||
|
|
@ -289,111 +272,71 @@ impl<'ast> Map<'ast> {
|
|||
}
|
||||
|
||||
fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
|
||||
let map = self.map.borrow();
|
||||
let mut id = id0;
|
||||
if !self.is_inlined_node_id(id) {
|
||||
let mut last_expr = None;
|
||||
loop {
|
||||
let entry = map[id.as_usize()];
|
||||
match entry {
|
||||
EntryItem(..) |
|
||||
EntryTraitItem(..) |
|
||||
EntryImplItem(..) => {
|
||||
if let Some(last_id) = last_expr {
|
||||
// The body may have a separate dep node
|
||||
if entry.is_body_owner(last_id) {
|
||||
let def_id = self.local_def_id(id);
|
||||
return DepNode::HirBody(def_id);
|
||||
}
|
||||
}
|
||||
return DepNode::Hir(self.local_def_id(id));
|
||||
}
|
||||
|
||||
EntryVariant(p, v) => {
|
||||
id = p;
|
||||
|
||||
if last_expr.is_some() {
|
||||
if v.node.disr_expr.map(|e| e.node_id) == last_expr {
|
||||
// The enum parent holds both Hir and HirBody nodes.
|
||||
let def_id = self.local_def_id(id);
|
||||
return DepNode::HirBody(def_id);
|
||||
}
|
||||
let mut last_expr = None;
|
||||
loop {
|
||||
let entry = self.map[id.as_usize()];
|
||||
match entry {
|
||||
EntryItem(..) |
|
||||
EntryTraitItem(..) |
|
||||
EntryImplItem(..) => {
|
||||
if let Some(last_id) = last_expr {
|
||||
// The body may have a separate dep node
|
||||
if entry.is_body_owner(last_id) {
|
||||
let def_id = self.local_def_id(id);
|
||||
return DepNode::HirBody(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
EntryForeignItem(p, _) |
|
||||
EntryField(p, _) |
|
||||
EntryStmt(p, _) |
|
||||
EntryTy(p, _) |
|
||||
EntryTraitRef(p, _) |
|
||||
EntryLocal(p, _) |
|
||||
EntryPat(p, _) |
|
||||
EntryBlock(p, _) |
|
||||
EntryStructCtor(p, _) |
|
||||
EntryLifetime(p, _) |
|
||||
EntryTyParam(p, _) |
|
||||
EntryVisibility(p, _) =>
|
||||
id = p,
|
||||
|
||||
EntryExpr(p, _) => {
|
||||
last_expr = Some(id);
|
||||
id = p;
|
||||
}
|
||||
|
||||
RootCrate => {
|
||||
return DepNode::Hir(DefId::local(CRATE_DEF_INDEX));
|
||||
}
|
||||
|
||||
RootInlinedParent(_) =>
|
||||
bug!("node {} has inlined ancestor but is not inlined", id0),
|
||||
|
||||
NotPresent =>
|
||||
// Some nodes, notably macro definitions, are not
|
||||
// present in the map for whatever reason, but
|
||||
// they *do* have def-ids. So if we encounter an
|
||||
// empty hole, check for that case.
|
||||
return self.opt_local_def_id(id)
|
||||
.map(|def_id| DepNode::Hir(def_id))
|
||||
.unwrap_or_else(|| {
|
||||
bug!("Walking parents from `{}` \
|
||||
led to `NotPresent` at `{}`",
|
||||
id0, id)
|
||||
}),
|
||||
return DepNode::Hir(self.local_def_id(id));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// reading from an inlined def-id is really a read out of
|
||||
// the metadata from which we loaded the item.
|
||||
loop {
|
||||
match map[id.as_usize()] {
|
||||
EntryItem(p, _) |
|
||||
EntryForeignItem(p, _) |
|
||||
EntryTraitItem(p, _) |
|
||||
EntryImplItem(p, _) |
|
||||
EntryVariant(p, _) |
|
||||
EntryField(p, _) |
|
||||
EntryExpr(p, _) |
|
||||
EntryStmt(p, _) |
|
||||
EntryTy(p, _) |
|
||||
EntryTraitRef(p, _) |
|
||||
EntryLocal(p, _) |
|
||||
EntryPat(p, _) |
|
||||
EntryBlock(p, _) |
|
||||
EntryStructCtor(p, _) |
|
||||
EntryLifetime(p, _) |
|
||||
EntryTyParam(p, _) |
|
||||
EntryVisibility(p, _) =>
|
||||
id = p,
|
||||
|
||||
RootInlinedParent(parent) =>
|
||||
return DepNode::MetaData(parent.def_id),
|
||||
EntryVariant(p, v) => {
|
||||
id = p;
|
||||
|
||||
RootCrate =>
|
||||
bug!("node {} has crate ancestor but is inlined", id0),
|
||||
|
||||
NotPresent =>
|
||||
bug!("node {} is inlined but not present in map", id0),
|
||||
if last_expr.is_some() {
|
||||
if v.node.disr_expr.map(|e| e.node_id) == last_expr {
|
||||
// The enum parent holds both Hir and HirBody nodes.
|
||||
let def_id = self.local_def_id(id);
|
||||
return DepNode::HirBody(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntryForeignItem(p, _) |
|
||||
EntryField(p, _) |
|
||||
EntryStmt(p, _) |
|
||||
EntryTy(p, _) |
|
||||
EntryTraitRef(p, _) |
|
||||
EntryLocal(p, _) |
|
||||
EntryPat(p, _) |
|
||||
EntryBlock(p, _) |
|
||||
EntryStructCtor(p, _) |
|
||||
EntryLifetime(p, _) |
|
||||
EntryTyParam(p, _) |
|
||||
EntryVisibility(p, _) =>
|
||||
id = p,
|
||||
|
||||
EntryExpr(p, _) => {
|
||||
last_expr = Some(id);
|
||||
id = p;
|
||||
}
|
||||
|
||||
RootCrate => {
|
||||
return DepNode::Hir(DefId::local(CRATE_DEF_INDEX));
|
||||
}
|
||||
|
||||
NotPresent =>
|
||||
// Some nodes, notably macro definitions, are not
|
||||
// present in the map for whatever reason, but
|
||||
// they *do* have def-ids. So if we encounter an
|
||||
// empty hole, check for that case.
|
||||
return self.opt_local_def_id(id)
|
||||
.map(|def_id| DepNode::Hir(def_id))
|
||||
.unwrap_or_else(|| {
|
||||
bug!("Walking parents from `{}` \
|
||||
led to `NotPresent` at `{}`",
|
||||
id0, id)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -442,11 +385,11 @@ impl<'ast> Map<'ast> {
|
|||
}
|
||||
|
||||
fn entry_count(&self) -> usize {
|
||||
self.map.borrow().len()
|
||||
self.map.len()
|
||||
}
|
||||
|
||||
fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
|
||||
self.map.borrow().get(id.as_usize()).cloned()
|
||||
self.map.get(id.as_usize()).cloned()
|
||||
}
|
||||
|
||||
pub fn krate(&self) -> &'ast Crate {
|
||||
|
|
@ -483,7 +426,7 @@ impl<'ast> Map<'ast> {
|
|||
/// for embedded constant expressions (e.g. `N` in `[T; N]`).
|
||||
pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
|
||||
let parent = self.get_parent_node(node_id);
|
||||
if self.map.borrow()[parent.as_usize()].is_body_owner(node_id) {
|
||||
if self.map[parent.as_usize()].is_body_owner(node_id) {
|
||||
parent
|
||||
} else {
|
||||
node_id
|
||||
|
|
@ -644,11 +587,7 @@ impl<'ast> Map<'ast> {
|
|||
}
|
||||
|
||||
pub fn get_parent_did(&self, id: NodeId) -> DefId {
|
||||
let parent = self.get_parent(id);
|
||||
match self.find_entry(parent) {
|
||||
Some(RootInlinedParent(ii)) => ii.def_id,
|
||||
_ => self.local_def_id(parent)
|
||||
}
|
||||
self.local_def_id(self.get_parent(id))
|
||||
}
|
||||
|
||||
pub fn get_foreign_abi(&self, id: NodeId) -> Abi {
|
||||
|
|
@ -660,8 +599,6 @@ impl<'ast> Map<'ast> {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
/// Wrong but OK, because the only inlined foreign items are intrinsics.
|
||||
Some(RootInlinedParent(_)) => Some(Abi::RustIntrinsic),
|
||||
_ => None
|
||||
};
|
||||
match abi {
|
||||
|
|
@ -737,11 +674,17 @@ impl<'ast> Map<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_inlined_body(&self, id: NodeId) -> &'ast Body {
|
||||
match self.find_entry(id) {
|
||||
Some(RootInlinedParent(inlined_item)) => &inlined_item.body,
|
||||
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
|
||||
}
|
||||
pub fn get_inlined_body(&self, def_id: DefId) -> Option<&'ast Body> {
|
||||
self.inlined_bodies.borrow().get(&def_id).map(|&body| {
|
||||
self.dep_graph.read(DepNode::MetaData(def_id));
|
||||
body
|
||||
})
|
||||
}
|
||||
|
||||
pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'ast Body {
|
||||
let body = self.forest.inlined_bodies.alloc(body);
|
||||
self.inlined_bodies.borrow_mut().insert(def_id, body);
|
||||
body
|
||||
}
|
||||
|
||||
/// Returns the name associated with the given NodeId's AST.
|
||||
|
|
@ -824,7 +767,6 @@ impl<'ast> Map<'ast> {
|
|||
Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
|
||||
|
||||
Some(RootCrate) => self.forest.krate.span,
|
||||
Some(RootInlinedParent(parent)) => parent.body.value.span,
|
||||
Some(NotPresent) | None => {
|
||||
bug!("hir::map::Map::span: id not in map: {:?}", id)
|
||||
}
|
||||
|
|
@ -973,41 +915,15 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
|
|||
entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
|
||||
}
|
||||
|
||||
let local_node_id_watermark = NodeId::new(map.len());
|
||||
|
||||
Map {
|
||||
forest: forest,
|
||||
dep_graph: forest.dep_graph.clone(),
|
||||
map: RefCell::new(map),
|
||||
map: map,
|
||||
definitions: definitions,
|
||||
local_node_id_watermark: local_node_id_watermark,
|
||||
inlined_bodies: RefCell::new(DefIdMap()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for bodies loaded from external crate that are being inlined into this
|
||||
/// crate.
|
||||
pub fn map_decoded_body<'ast>(map: &Map<'ast>,
|
||||
def_id: DefId,
|
||||
body: Body,
|
||||
parent_id: NodeId)
|
||||
-> &'ast Body {
|
||||
let _ignore = map.forest.dep_graph.in_ignore();
|
||||
|
||||
let ii = map.forest.inlined_items.alloc(InlinedItem {
|
||||
def_id: def_id,
|
||||
body: body
|
||||
});
|
||||
|
||||
let mut collector = NodeCollector::extend(map.krate(),
|
||||
ii,
|
||||
parent_id,
|
||||
mem::replace(&mut *map.map.borrow_mut(), vec![]));
|
||||
collector.visit_body(&ii.body);
|
||||
*map.map.borrow_mut() = collector.map;
|
||||
|
||||
&ii.body
|
||||
}
|
||||
|
||||
/// Identical to the `PpAnn` implementation for `hir::Crate`,
|
||||
/// except it avoids creating a dependency on the whole crate.
|
||||
impl<'ast> print::PpAnn for Map<'ast> {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ use middle::region::CodeExtent;
|
|||
use middle::lang_items;
|
||||
use mir::tcx::LvalueTy;
|
||||
use ty::subst::{Kind, Subst, Substs};
|
||||
use ty::adjustment;
|
||||
use ty::{TyVid, IntVid, FloatVid};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
|
||||
|
|
@ -37,10 +36,11 @@ use traits::{self, ObligationCause, PredicateObligations, Reveal};
|
|||
use rustc_data_structures::unify::{self, UnificationTable};
|
||||
use std::cell::{Cell, RefCell, Ref, RefMut};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use syntax::ast;
|
||||
use errors::DiagnosticBuilder;
|
||||
use syntax_pos::{self, Span, DUMMY_SP};
|
||||
use util::nodemap::{FxHashMap, FxHashSet, NodeMap};
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use arena::DroplessArena;
|
||||
|
||||
use self::combine::CombineFields;
|
||||
|
|
@ -76,28 +76,63 @@ pub type Bound<T> = Option<T>;
|
|||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
|
||||
|
||||
/// A version of &ty::Tables which can be global or local.
|
||||
/// Only the local version supports borrow_mut.
|
||||
/// A version of &ty::Tables 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> {
|
||||
Global(&'a RefCell<ty::Tables<'gcx>>),
|
||||
Local(&'a RefCell<ty::Tables<'tcx>>)
|
||||
Interned(&'a ty::Tables<'gcx>),
|
||||
InProgress(&'a RefCell<ty::Tables<'tcx>>),
|
||||
Missing
|
||||
}
|
||||
|
||||
pub enum InferTablesRef<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
Interned(&'a ty::Tables<'gcx>),
|
||||
InProgress(Ref<'a, ty::Tables<'tcx>>)
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Deref for InferTablesRef<'a, 'gcx, 'tcx> {
|
||||
type Target = ty::Tables<'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) -> Ref<'a, ty::Tables<'tcx>> {
|
||||
pub fn borrow(self) -> InferTablesRef<'a, 'gcx, 'tcx> {
|
||||
match self {
|
||||
InferTables::Global(tables) => tables.borrow(),
|
||||
InferTables::Local(tables) => tables.borrow()
|
||||
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::Tables<'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::Tables<'tcx>> {
|
||||
match self {
|
||||
InferTables::Global(_) => {
|
||||
InferTables::Interned(_) => {
|
||||
bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking");
|
||||
}
|
||||
InferTables::Local(tables) => tables.borrow_mut()
|
||||
InferTables::InProgress(tables) => tables.borrow_mut(),
|
||||
InferTables::Missing => {
|
||||
bug!("InferTables: infcx.tables.borrow_mut() with no tables")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -370,27 +405,84 @@ impl fmt::Display for FixupError {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait InferEnv<'a, 'tcx> {
|
||||
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (Option<&'a ty::Tables<'tcx>>,
|
||||
Option<ty::Tables<'tcx>>,
|
||||
Option<ty::ParameterEnvironment<'tcx>>);
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
|
||||
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (Option<&'a ty::Tables<'tcx>>,
|
||||
Option<ty::Tables<'tcx>>,
|
||||
Option<ty::ParameterEnvironment<'tcx>>) {
|
||||
(None, None, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParameterEnvironment<'tcx> {
|
||||
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (Option<&'a ty::Tables<'tcx>>,
|
||||
Option<ty::Tables<'tcx>>,
|
||||
Option<ty::ParameterEnvironment<'tcx>>) {
|
||||
(None, None, Some(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::Tables<'tcx>, ty::ParameterEnvironment<'tcx>) {
|
||||
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (Option<&'a ty::Tables<'tcx>>,
|
||||
Option<ty::Tables<'tcx>>,
|
||||
Option<ty::ParameterEnvironment<'tcx>>) {
|
||||
(Some(self.0), None, Some(self.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::Tables<'tcx>, ty::ParameterEnvironment<'tcx>) {
|
||||
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (Option<&'a ty::Tables<'tcx>>,
|
||||
Option<ty::Tables<'tcx>>,
|
||||
Option<ty::ParameterEnvironment<'tcx>>) {
|
||||
(None, Some(self.0), Some(self.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
|
||||
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (Option<&'a ty::Tables<'tcx>>,
|
||||
Option<ty::Tables<'tcx>>,
|
||||
Option<ty::ParameterEnvironment<'tcx>>) {
|
||||
let item_id = tcx.map.body_owner(self);
|
||||
(Some(tcx.item_tables(tcx.map.local_def_id(item_id))),
|
||||
None,
|
||||
Some(ty::ParameterEnvironment::for_item(tcx, item_id)))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
tables: Option<RefCell<ty::Tables<'tcx>>>,
|
||||
fresh_tables: Option<RefCell<ty::Tables<'tcx>>>,
|
||||
tables: Option<&'a ty::Tables<'gcx>>,
|
||||
param_env: Option<ty::ParameterEnvironment<'gcx>>,
|
||||
projection_mode: Reveal,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
pub fn infer_ctxt(self,
|
||||
tables: Option<ty::Tables<'tcx>>,
|
||||
param_env: Option<ty::ParameterEnvironment<'gcx>>,
|
||||
projection_mode: Reveal)
|
||||
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self,
|
||||
env: E,
|
||||
projection_mode: Reveal)
|
||||
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
let (tables, fresh_tables, param_env) = env.to_parts(self);
|
||||
InferCtxtBuilder {
|
||||
global_tcx: self,
|
||||
arena: DroplessArena::new(),
|
||||
tables: tables.map(RefCell::new),
|
||||
fresh_tables: fresh_tables.map(RefCell::new),
|
||||
tables: tables,
|
||||
param_env: param_env,
|
||||
projection_mode: projection_mode,
|
||||
}
|
||||
|
|
@ -399,16 +491,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
|||
/// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck
|
||||
/// for MemCategorizationContext/ExprUseVisitor.
|
||||
/// If any inference functionality is used, ICEs will occur.
|
||||
pub fn borrowck_fake_infer_ctxt(self, param_env: ty::ParameterEnvironment<'gcx>)
|
||||
pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
|
||||
-> InferCtxt<'a, 'gcx, 'gcx> {
|
||||
let (tables, _, param_env) = body.to_parts(self);
|
||||
InferCtxt {
|
||||
tcx: self,
|
||||
tables: InferTables::Global(&self.tables),
|
||||
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),
|
||||
parameter_environment: param_env,
|
||||
parameter_environment: param_env.unwrap(),
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
projection_cache: RefCell::new(traits::ProjectionCache::new()),
|
||||
|
|
@ -428,15 +521,14 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
|||
let InferCtxtBuilder {
|
||||
global_tcx,
|
||||
ref arena,
|
||||
ref tables,
|
||||
ref fresh_tables,
|
||||
tables,
|
||||
ref mut param_env,
|
||||
projection_mode,
|
||||
} = *self;
|
||||
let tables = if let Some(ref tables) = *tables {
|
||||
InferTables::Local(tables)
|
||||
} else {
|
||||
InferTables::Global(&global_tcx.tables)
|
||||
};
|
||||
let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
|
||||
fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
|
||||
});
|
||||
let param_env = param_env.take().unwrap_or_else(|| {
|
||||
global_tcx.empty_parameter_environment()
|
||||
});
|
||||
|
|
@ -555,7 +647,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
return value;
|
||||
}
|
||||
|
||||
self.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||
self.infer_ctxt((), Reveal::All).enter(|infcx| {
|
||||
value.trans_normalize(&infcx)
|
||||
})
|
||||
}
|
||||
|
|
@ -573,7 +665,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
return value;
|
||||
}
|
||||
|
||||
self.infer_ctxt(None, Some(env.clone()), Reveal::All).enter(|infcx| {
|
||||
self.infer_ctxt(env.clone(), Reveal::All).enter(|infcx| {
|
||||
value.trans_normalize(&infcx)
|
||||
})
|
||||
}
|
||||
|
|
@ -1490,8 +1582,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// Even if the type may have no inference variables, during
|
||||
// type-checking closure types are in local tables only.
|
||||
let local_closures = match self.tables {
|
||||
InferTables::Local(_) => ty.has_closure_types(),
|
||||
InferTables::Global(_) => false
|
||||
InferTables::InProgress(_) => ty.has_closure_types(),
|
||||
_ => false
|
||||
};
|
||||
if !local_closures {
|
||||
return ty.moves_by_default(self.tcx.global_tcx(), self.param_env(), span);
|
||||
|
|
@ -1526,15 +1618,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
.map(|method| method.def_id)
|
||||
}
|
||||
|
||||
pub fn adjustments(&self) -> Ref<NodeMap<adjustment::Adjustment<'tcx>>> {
|
||||
fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
|
||||
-> &'a NodeMap<adjustment::Adjustment<'tcx>> {
|
||||
&tables.adjustments
|
||||
}
|
||||
|
||||
Ref::map(self.tables.borrow(), project_adjustments)
|
||||
}
|
||||
|
||||
pub fn is_method_call(&self, id: ast::NodeId) -> bool {
|
||||
self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
|
||||
}
|
||||
|
|
@ -1555,15 +1638,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
def_id: DefId)
|
||||
-> Option<ty::ClosureKind>
|
||||
{
|
||||
if def_id.is_local() {
|
||||
self.tables.borrow().closure_kinds.get(&def_id).cloned()
|
||||
} else {
|
||||
// During typeck, ALL closures are local. But afterwards,
|
||||
// during trans, we see closure ids from other traits.
|
||||
// That may require loading the closure data out of the
|
||||
// cstore.
|
||||
Some(self.tcx.closure_kind(def_id))
|
||||
if let InferTables::InProgress(tables) = self.tables {
|
||||
if let Some(id) = self.tcx.map.as_local_node_id(def_id) {
|
||||
return tables.borrow().closure_kinds.get(&id).cloned();
|
||||
}
|
||||
}
|
||||
|
||||
// During typeck, ALL closures are local. But afterwards,
|
||||
// during trans, we see closure ids from other traits.
|
||||
// That may require loading the closure data out of the
|
||||
// cstore.
|
||||
Some(self.tcx.closure_kind(def_id))
|
||||
}
|
||||
|
||||
pub fn closure_type(&self,
|
||||
|
|
@ -1571,14 +1656,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
substs: ty::ClosureSubsts<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
if let InferTables::Local(tables) = self.tables {
|
||||
if let Some(ty) = tables.borrow().closure_tys.get(&def_id) {
|
||||
return ty.subst(self.tcx, substs.substs);
|
||||
if let InferTables::InProgress(tables) = self.tables {
|
||||
if let Some(id) = self.tcx.map.as_local_node_id(def_id) {
|
||||
if let Some(ty) = tables.borrow().closure_tys.get(&id) {
|
||||
return ty.subst(self.tcx, substs.substs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let closure_ty = self.tcx.closure_type(def_id, substs);
|
||||
closure_ty
|
||||
self.tcx.closure_type(def_id, substs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use self::TargetLint::*;
|
|||
|
||||
use dep_graph::DepNode;
|
||||
use middle::privacy::AccessLevels;
|
||||
use ty::TyCtxt;
|
||||
use ty::{self, TyCtxt};
|
||||
use session::{config, early_error, Session};
|
||||
use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
|
||||
use lint::{EarlyLintPassObject, LateLintPassObject};
|
||||
|
|
@ -336,6 +336,9 @@ pub struct LateContext<'a, 'tcx: 'a> {
|
|||
/// Type context we're checking in.
|
||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
/// Side-tables for the body we are in.
|
||||
pub tables: &'a ty::Tables<'tcx>,
|
||||
|
||||
/// The crate being checked.
|
||||
pub krate: &'a hir::Crate,
|
||||
|
||||
|
|
@ -703,22 +706,6 @@ impl<'a> EarlyContext<'a> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> LateContext<'a, 'tcx> {
|
||||
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
krate: &'a hir::Crate,
|
||||
access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
|
||||
// We want to own the lint store, so move it out of the session.
|
||||
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
|
||||
LintStore::new());
|
||||
|
||||
LateContext {
|
||||
tcx: tcx,
|
||||
krate: krate,
|
||||
access_levels: access_levels,
|
||||
lints: lint_store,
|
||||
level_stack: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ids<'b, F: 'b>(&'b mut self, f: F)
|
||||
where F: FnOnce(&mut IdVisitor<'b, 'a, 'tcx>)
|
||||
{
|
||||
|
|
@ -795,6 +782,14 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
|
|||
hir_visit::NestedVisitorMap::All(&self.tcx.map)
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||
let old_tables = self.tables;
|
||||
self.tables = self.tcx.body_tables(body);
|
||||
let body = self.tcx.map.body(body);
|
||||
self.visit_body(body);
|
||||
self.tables = old_tables;
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, it: &'tcx hir::Item) {
|
||||
self.with_lint_attrs(&it.attrs, |cx| {
|
||||
run_lints!(cx, check_item, late_passes, it);
|
||||
|
|
@ -837,10 +832,15 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
|
|||
|
||||
fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
|
||||
body_id: hir::BodyId, span: Span, id: ast::NodeId) {
|
||||
// Wrap in tables here, not just in visit_nested_body,
|
||||
// in order for `check_fn` to be able to use them.
|
||||
let old_tables = self.tables;
|
||||
self.tables = self.tcx.body_tables(body_id);
|
||||
let body = self.tcx.map.body(body_id);
|
||||
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
|
||||
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
|
||||
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
|
||||
self.tables = old_tables;
|
||||
}
|
||||
|
||||
fn visit_variant_data(&mut self,
|
||||
|
|
@ -1238,7 +1238,17 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);
|
||||
|
||||
let krate = tcx.map.krate();
|
||||
let mut cx = LateContext::new(tcx, krate, access_levels);
|
||||
|
||||
// We want to own the lint store, so move it out of the session.
|
||||
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), LintStore::new());
|
||||
let mut cx = LateContext {
|
||||
tcx: tcx,
|
||||
tables: &ty::Tables::empty(),
|
||||
krate: krate,
|
||||
access_levels: access_levels,
|
||||
lints: lint_store,
|
||||
level_stack: vec![],
|
||||
};
|
||||
|
||||
// Visit the whole crate.
|
||||
cx.with_lint_attrs(&krate.attrs, |cx| {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ use hir::def_id::DefId;
|
|||
use rustc_const_math::*;
|
||||
use self::ConstVal::*;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||
pub enum ConstVal {
|
||||
Float(ConstFloat),
|
||||
|
|
@ -22,16 +24,12 @@ pub enum ConstVal {
|
|||
Str(InternedString),
|
||||
ByteStr(Rc<Vec<u8>>),
|
||||
Bool(bool),
|
||||
Struct(ast::NodeId),
|
||||
Tuple(ast::NodeId),
|
||||
Function(DefId),
|
||||
Array(ast::NodeId, u64),
|
||||
Repeat(ast::NodeId, u64),
|
||||
Struct(BTreeMap<ast::Name, ConstVal>),
|
||||
Tuple(Vec<ConstVal>),
|
||||
Array(Vec<ConstVal>),
|
||||
Repeat(Box<ConstVal>, u64),
|
||||
Char(char),
|
||||
/// A value that only occurs in case `eval_const_expr` reported an error. You should never
|
||||
/// handle this case. Its sole purpose is to allow more errors to be reported instead of
|
||||
/// causing a fatal error.
|
||||
Dummy,
|
||||
}
|
||||
|
||||
impl ConstVal {
|
||||
|
|
@ -48,7 +46,6 @@ impl ConstVal {
|
|||
Array(..) => "array",
|
||||
Repeat(..) => "repeat",
|
||||
Char(..) => "char",
|
||||
Dummy => "dummy value",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ fn should_explore<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
struct MarkSymbolVisitor<'a, 'tcx: 'a> {
|
||||
worklist: Vec<ast::NodeId>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: &'a ty::Tables<'tcx>,
|
||||
live_symbols: Box<FxHashSet<ast::NodeId>>,
|
||||
struct_has_extern_repr: bool,
|
||||
ignore_non_const_paths: bool,
|
||||
|
|
@ -57,19 +58,6 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
||||
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
worklist: Vec<ast::NodeId>) -> MarkSymbolVisitor<'a, 'tcx> {
|
||||
MarkSymbolVisitor {
|
||||
worklist: worklist,
|
||||
tcx: tcx,
|
||||
live_symbols: box FxHashSet(),
|
||||
struct_has_extern_repr: false,
|
||||
ignore_non_const_paths: false,
|
||||
inherited_pub_visibility: false,
|
||||
ignore_variant_stack: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn check_def_id(&mut self, def_id: DefId) {
|
||||
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
|
||||
if should_explore(self.tcx, node_id) {
|
||||
|
|
@ -109,12 +97,12 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
|
||||
fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
|
||||
let method_call = ty::MethodCall::expr(id);
|
||||
let method = self.tcx.tables().method_map[&method_call];
|
||||
let method = self.tables.method_map[&method_call];
|
||||
self.check_def_id(method.def_id);
|
||||
}
|
||||
|
||||
fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
|
||||
match self.tcx.tables().expr_ty_adjusted(lhs).sty {
|
||||
match self.tables.expr_ty_adjusted(lhs).sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
self.insert_def_id(def.struct_variant().field_named(name).did);
|
||||
}
|
||||
|
|
@ -123,7 +111,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) {
|
||||
match self.tcx.tables().expr_ty_adjusted(lhs).sty {
|
||||
match self.tables.expr_ty_adjusted(lhs).sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
self.insert_def_id(def.struct_variant().fields[idx].did);
|
||||
}
|
||||
|
|
@ -134,7 +122,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
|
||||
fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, def: Def,
|
||||
pats: &[codemap::Spanned<hir::FieldPat>]) {
|
||||
let variant = match self.tcx.tables().node_id_to_type(lhs.id).sty {
|
||||
let variant = match self.tables.node_id_to_type(lhs.id).sty {
|
||||
ty::TyAdt(adt, _) => adt.variant_of_def(def),
|
||||
_ => span_bug!(lhs.span, "non-ADT in struct pattern")
|
||||
};
|
||||
|
|
@ -209,7 +197,15 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::OnlyBodies(&self.tcx.map)
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||
let old_tables = self.tables;
|
||||
self.tables = self.tcx.body_tables(body);
|
||||
let body = self.tcx.map.body(body);
|
||||
self.visit_body(body);
|
||||
self.tables = old_tables;
|
||||
}
|
||||
|
||||
fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
|
||||
|
|
@ -227,7 +223,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
|
|||
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
||||
match expr.node {
|
||||
hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => {
|
||||
let def = self.tcx.tables().qpath_def(qpath, expr.id);
|
||||
let def = self.tables.qpath_def(qpath, expr.id);
|
||||
self.handle_definition(def);
|
||||
}
|
||||
hir::ExprMethodCall(..) => {
|
||||
|
|
@ -267,7 +263,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
|
|||
self.handle_field_pattern_match(pat, path.def, fields);
|
||||
}
|
||||
PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
|
||||
let def = self.tcx.tables().qpath_def(qpath, pat.id);
|
||||
let def = self.tables.qpath_def(qpath, pat.id);
|
||||
self.handle_definition(def);
|
||||
}
|
||||
_ => ()
|
||||
|
|
@ -393,7 +389,16 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
krate: &hir::Crate)
|
||||
-> Box<FxHashSet<ast::NodeId>> {
|
||||
let worklist = create_and_seed_worklist(tcx, access_levels, krate);
|
||||
let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
|
||||
let mut symbol_visitor = MarkSymbolVisitor {
|
||||
worklist: worklist,
|
||||
tcx: tcx,
|
||||
tables: &ty::Tables::empty(),
|
||||
live_symbols: box FxHashSet(),
|
||||
struct_has_extern_repr: false,
|
||||
ignore_non_const_paths: false,
|
||||
inherited_pub_visibility: false,
|
||||
ignore_variant_stack: vec![],
|
||||
};
|
||||
symbol_visitor.mark_live_symbols();
|
||||
symbol_visitor.live_symbols
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ fn type_is_unsafe_function(ty: Ty) -> bool {
|
|||
|
||||
struct EffectCheckVisitor<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: &'a ty::Tables<'tcx>,
|
||||
|
||||
/// Whether we're in an unsafe context.
|
||||
unsafe_context: UnsafeContext,
|
||||
|
|
@ -94,7 +95,15 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::OnlyBodies(&self.tcx.map)
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||
let old_tables = self.tables;
|
||||
self.tables = self.tcx.body_tables(body);
|
||||
let body = self.tcx.map.body(body);
|
||||
self.visit_body(body);
|
||||
self.tables = old_tables;
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
|
||||
|
|
@ -163,7 +172,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
|
|||
match expr.node {
|
||||
hir::ExprMethodCall(..) => {
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let base_type = self.tcx.tables().method_map[&method_call].ty;
|
||||
let base_type = self.tables.method_map[&method_call].ty;
|
||||
debug!("effect: method call case, base type is {:?}",
|
||||
base_type);
|
||||
if type_is_unsafe_function(base_type) {
|
||||
|
|
@ -172,7 +181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::ExprCall(ref base, _) => {
|
||||
let base_type = self.tcx.tables().expr_ty_adjusted(base);
|
||||
let base_type = self.tables.expr_ty_adjusted(base);
|
||||
debug!("effect: call case, base type is {:?}",
|
||||
base_type);
|
||||
if type_is_unsafe_function(base_type) {
|
||||
|
|
@ -180,7 +189,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::ExprUnary(hir::UnDeref, ref base) => {
|
||||
let base_type = self.tcx.tables().expr_ty_adjusted(base);
|
||||
let base_type = self.tables.expr_ty_adjusted(base);
|
||||
debug!("effect: unary case, base type is {:?}",
|
||||
base_type);
|
||||
if let ty::TyRawPtr(_) = base_type.sty {
|
||||
|
|
@ -204,7 +213,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::ExprField(ref base_expr, field) => {
|
||||
if let ty::TyAdt(adt, ..) = self.tcx.tables().expr_ty_adjusted(base_expr).sty {
|
||||
if let ty::TyAdt(adt, ..) = self.tables.expr_ty_adjusted(base_expr).sty {
|
||||
if adt.is_union() {
|
||||
self.require_unsafe(field.span, "access to union field");
|
||||
}
|
||||
|
|
@ -218,7 +227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
|
|||
|
||||
fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
|
||||
if let PatKind::Struct(_, ref fields, _) = pat.node {
|
||||
if let ty::TyAdt(adt, ..) = self.tcx.tables().pat_ty(pat).sty {
|
||||
if let ty::TyAdt(adt, ..) = self.tables.pat_ty(pat).sty {
|
||||
if adt.is_union() {
|
||||
for field in fields {
|
||||
self.require_unsafe(field.span, "matching on union field");
|
||||
|
|
@ -236,6 +245,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
|||
|
||||
let mut visitor = EffectCheckVisitor {
|
||||
tcx: tcx,
|
||||
tables: &ty::Tables::empty(),
|
||||
unsafe_context: UnsafeContext::new(SafeContext),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
fn walk_adjustment(&mut self, expr: &hir::Expr) {
|
||||
let infcx = self.mc.infcx;
|
||||
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
||||
let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone());
|
||||
let adj = infcx.tables.borrow().adjustments.get(&expr.id).map(|x| x.clone());
|
||||
if let Some(adjustment) = adj {
|
||||
match adjustment.kind {
|
||||
adjustment::Adjust::NeverToAny |
|
||||
|
|
@ -989,7 +989,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
PatKind::Struct(ref qpath, ..) => qpath,
|
||||
_ => return
|
||||
};
|
||||
let def = tcx.tables().qpath_def(qpath, pat.id);
|
||||
let def = infcx.tables.borrow().qpath_def(qpath, pat.id);
|
||||
match def {
|
||||
Def::Variant(variant_did) |
|
||||
Def::VariantCtor(variant_did, ..) => {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use ty::layout::{LayoutError, Pointer, SizeSkeleton};
|
|||
use syntax::abi::Abi::RustIntrinsic;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
|
||||
use hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use hir;
|
||||
|
||||
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
|
|
@ -33,18 +33,6 @@ struct ItemVisitor<'a, 'tcx: 'a> {
|
|||
tcx: TyCtxt<'a, 'tcx, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
|
||||
fn visit_const(&mut self, item_id: ast::NodeId, body: hir::BodyId) {
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
|
||||
self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
visitor.visit_nested_body(body);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
|
||||
}
|
||||
|
|
@ -118,64 +106,36 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::OnlyBodies(&self.tcx.map)
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
// const, static and N in [T; N].
|
||||
fn visit_body(&mut self, body: &'tcx hir::Body) {
|
||||
self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
|
||||
let body = self.tcx.map.body(body_id);
|
||||
self.tcx.infer_ctxt(body_id, Reveal::All).enter(|infcx| {
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
visitor.visit_body(body);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
|
||||
if let hir::TraitItemKind::Const(_, Some(body)) = item.node {
|
||||
self.visit_const(item.id, body);
|
||||
} else {
|
||||
intravisit::walk_trait_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
|
||||
if let hir::ImplItemKind::Const(_, body) = item.node {
|
||||
self.visit_const(item.id, body);
|
||||
} else {
|
||||
intravisit::walk_impl_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
|
||||
b: hir::BodyId, s: Span, id: ast::NodeId) {
|
||||
if let FnKind::Closure(..) = fk {
|
||||
span_bug!(s, "intrinsicck: closure outside of function")
|
||||
}
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
||||
self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
|
||||
let mut visitor = ExprVisitor {
|
||||
infcx: &infcx
|
||||
};
|
||||
visitor.visit_fn(fk, fd, b, s, id);
|
||||
});
|
||||
self.visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
|
||||
NestedVisitorMap::OnlyBodies(&self.infcx.tcx.map)
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
|
||||
let def = if let hir::ExprPath(ref qpath) = expr.node {
|
||||
self.infcx.tcx.tables().qpath_def(qpath, expr.id)
|
||||
self.infcx.tables.borrow().qpath_def(qpath, expr.id)
|
||||
} else {
|
||||
Def::Err
|
||||
};
|
||||
match def {
|
||||
Def::Fn(did) if self.def_id_is_transmute(did) => {
|
||||
let typ = self.infcx.tcx.tables().node_id_to_type(expr.id);
|
||||
let typ = self.infcx.tables.borrow().node_id_to_type(expr.id);
|
||||
let typ = self.infcx.tcx.lift_to_global(&typ).unwrap();
|
||||
match typ.sty {
|
||||
ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
|
||||
let from = bare_fn_ty.sig.skip_binder().inputs()[0];
|
||||
|
|
|
|||
|
|
@ -351,22 +351,6 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx hir::Local) {
|
||||
check_local(self, l);
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr) {
|
||||
check_expr(self, ex);
|
||||
}
|
||||
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
|
||||
check_arm(self, a);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
|
||||
fk: FnKind<'tcx>,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
|
|
@ -394,24 +378,13 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
|
|||
// and so forth:
|
||||
intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
|
||||
|
||||
// Special nodes and variables:
|
||||
// - exit_ln represents the end of the fn, either by return or panic
|
||||
// - implicit_ret_var is a pseudo-variable that represents
|
||||
// an implicit return
|
||||
let specials = Specials {
|
||||
exit_ln: fn_maps.add_live_node(ExitNode),
|
||||
fallthrough_ln: fn_maps.add_live_node(ExitNode),
|
||||
no_ret_var: fn_maps.add_variable(ImplicitRet),
|
||||
clean_exit_var: fn_maps.add_variable(CleanExit)
|
||||
};
|
||||
|
||||
// compute liveness
|
||||
let mut lsets = Liveness::new(&mut fn_maps, specials);
|
||||
let mut lsets = Liveness::new(&mut fn_maps, body_id);
|
||||
let entry_ln = lsets.compute(&body.value);
|
||||
|
||||
// check for various error conditions
|
||||
lsets.visit_body(body);
|
||||
lsets.check_ret(id, sp, fk, entry_ln, body);
|
||||
lsets.check_ret(id, sp, entry_ln, body);
|
||||
lsets.warn_about_unused_args(body, entry_ln);
|
||||
}
|
||||
|
||||
|
|
@ -539,6 +512,7 @@ const ACC_USE: u32 = 4;
|
|||
|
||||
struct Liveness<'a, 'tcx: 'a> {
|
||||
ir: &'a mut IrMaps<'a, 'tcx>,
|
||||
tables: &'a ty::Tables<'tcx>,
|
||||
s: Specials,
|
||||
successors: Vec<LiveNode>,
|
||||
users: Vec<Users>,
|
||||
|
|
@ -553,11 +527,26 @@ struct Liveness<'a, 'tcx: 'a> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
fn new(ir: &'a mut IrMaps<'a, 'tcx>, specials: Specials) -> Liveness<'a, 'tcx> {
|
||||
fn new(ir: &'a mut IrMaps<'a, 'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> {
|
||||
// Special nodes and variables:
|
||||
// - exit_ln represents the end of the fn, either by return or panic
|
||||
// - implicit_ret_var is a pseudo-variable that represents
|
||||
// an implicit return
|
||||
let specials = Specials {
|
||||
exit_ln: ir.add_live_node(ExitNode),
|
||||
fallthrough_ln: ir.add_live_node(ExitNode),
|
||||
no_ret_var: ir.add_variable(ImplicitRet),
|
||||
clean_exit_var: ir.add_variable(CleanExit)
|
||||
};
|
||||
|
||||
let tables = ir.tcx.body_tables(body);
|
||||
|
||||
let num_live_nodes = ir.num_live_nodes;
|
||||
let num_vars = ir.num_vars;
|
||||
|
||||
Liveness {
|
||||
ir: ir,
|
||||
tables: tables,
|
||||
s: specials,
|
||||
successors: vec![invalid_node(); num_live_nodes],
|
||||
users: vec![invalid_users(); num_live_nodes * num_vars],
|
||||
|
|
@ -1065,7 +1054,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
|
||||
hir::ExprAssignOp(_, ref l, ref r) => {
|
||||
// an overloaded assign op is like a method call
|
||||
if self.ir.tcx.tables().is_method_call(expr.id) {
|
||||
if self.tables.is_method_call(expr.id) {
|
||||
let succ = self.propagate_through_expr(&l, succ);
|
||||
self.propagate_through_expr(&r, succ)
|
||||
} else {
|
||||
|
|
@ -1092,8 +1081,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
|
||||
hir::ExprCall(ref f, ref args) => {
|
||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
||||
let diverges = !self.ir.tcx.tables().is_method_call(expr.id) &&
|
||||
self.ir.tcx.tables().expr_ty_adjusted(&f).fn_ret().0.is_never();
|
||||
let diverges = !self.tables.is_method_call(expr.id) &&
|
||||
self.tables.expr_ty_adjusted(&f).fn_ret().0.is_never();
|
||||
let succ = if diverges {
|
||||
self.s.exit_ln
|
||||
} else {
|
||||
|
|
@ -1105,7 +1094,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
|
||||
hir::ExprMethodCall(.., ref args) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
let method_ty = self.ir.tcx.tables().method_map[&method_call].ty;
|
||||
let method_ty = self.tables.method_map[&method_call].ty;
|
||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
||||
let succ = if method_ty.fn_ret().0.is_never() {
|
||||
self.s.exit_ln
|
||||
|
|
@ -1355,6 +1344,22 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
// _______________________________________________________________________
|
||||
// Checking for error conditions
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx hir::Local) {
|
||||
check_local(self, l);
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr) {
|
||||
check_expr(self, ex);
|
||||
}
|
||||
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
|
||||
check_arm(self, a);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) {
|
||||
match local.init {
|
||||
Some(_) => {
|
||||
|
|
@ -1389,7 +1394,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
|||
}
|
||||
|
||||
hir::ExprAssignOp(_, ref l, _) => {
|
||||
if !this.ir.tcx.tables().is_method_call(expr.id) {
|
||||
if !this.tables.is_method_call(expr.id) {
|
||||
this.check_lvalue(&l);
|
||||
}
|
||||
|
||||
|
|
@ -1432,15 +1437,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
fn check_ret(&self,
|
||||
id: NodeId,
|
||||
sp: Span,
|
||||
fk: FnKind,
|
||||
entry_ln: LiveNode,
|
||||
body: &hir::Body)
|
||||
{
|
||||
let fn_ty = if let FnKind::Closure(_) = fk {
|
||||
self.ir.tcx.tables().node_id_to_type(id)
|
||||
} else {
|
||||
self.ir.tcx.item_type(self.ir.tcx.map.local_def_id(id))
|
||||
};
|
||||
let fn_ty = self.ir.tcx.item_type(self.ir.tcx.map.local_def_id(id));
|
||||
let fn_ret = match fn_ty.sty {
|
||||
ty::TyClosure(closure_def_id, substs) =>
|
||||
self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
|
||||
|
|
@ -1457,8 +1457,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
|
||||
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
|
||||
let t_ret_subst = fn_ret.subst(self.ir.tcx, ¶m_env.free_substs);
|
||||
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
|
||||
Reveal::All).enter(|infcx| {
|
||||
let is_nil = self.ir.tcx.infer_ctxt(param_env, Reveal::All).enter(|infcx| {
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
|
||||
match self.infcx.adjustments().get(&expr.id) {
|
||||
match self.infcx.tables.borrow().adjustments.get(&expr.id) {
|
||||
None => {
|
||||
// No adjustments.
|
||||
self.cat_expr_unadjusted(expr)
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
struct ReachableContext<'a, 'tcx: 'a> {
|
||||
// The type context.
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: &'a ty::Tables<'tcx>,
|
||||
// The set of items which must be exported in the linkage sense.
|
||||
reachable_symbols: NodeSet,
|
||||
// A worklist of item IDs. Each item ID in this worklist will be inlined
|
||||
|
|
@ -90,17 +91,25 @@ struct ReachableContext<'a, 'tcx: 'a> {
|
|||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::OnlyBodies(&self.tcx.map)
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||
let old_tables = self.tables;
|
||||
self.tables = self.tcx.body_tables(body);
|
||||
let body = self.tcx.map.body(body);
|
||||
self.visit_body(body);
|
||||
self.tables = old_tables;
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
||||
let def = match expr.node {
|
||||
hir::ExprPath(ref qpath) => {
|
||||
Some(self.tcx.tables().qpath_def(qpath, expr.id))
|
||||
Some(self.tables.qpath_def(qpath, expr.id))
|
||||
}
|
||||
hir::ExprMethodCall(..) => {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
|
||||
let def_id = self.tables.method_map[&method_call].def_id;
|
||||
Some(Def::Method(def_id))
|
||||
}
|
||||
_ => None
|
||||
|
|
@ -135,20 +144,6 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
||||
// Creates a new reachability computation context.
|
||||
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
|
||||
let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
|
||||
*ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
|
||||
*ty == config::CrateTypeProcMacro
|
||||
});
|
||||
ReachableContext {
|
||||
tcx: tcx,
|
||||
reachable_symbols: NodeSet(),
|
||||
worklist: Vec::new(),
|
||||
any_library: any_library,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the given def ID represents a local item that is
|
||||
// eligible for inlining and false otherwise.
|
||||
fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
|
||||
|
|
@ -369,7 +364,17 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
-> NodeSet {
|
||||
let _task = tcx.dep_graph.in_task(DepNode::Reachability);
|
||||
|
||||
let mut reachable_context = ReachableContext::new(tcx);
|
||||
let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
|
||||
*ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
|
||||
*ty == config::CrateTypeProcMacro
|
||||
});
|
||||
let mut reachable_context = ReachableContext {
|
||||
tcx: tcx,
|
||||
tables: &ty::Tables::empty(),
|
||||
reachable_symbols: NodeSet(),
|
||||
worklist: Vec::new(),
|
||||
any_library: any_library,
|
||||
};
|
||||
|
||||
// Step 1: Seed the worklist with all nodes which were found to be public as
|
||||
// a result of the privacy pass along with all local lang items and impl items.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use std::fmt::{self, Debug, Formatter, Write};
|
|||
use std::{iter, u32};
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::vec::IntoIter;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::ast::Name;
|
||||
use syntax_pos::Span;
|
||||
|
||||
mod cache;
|
||||
|
|
@ -1271,17 +1271,12 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
|
|||
}
|
||||
Bool(b) => write!(fmt, "{:?}", b),
|
||||
Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
|
||||
Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
|
||||
write!(fmt, "{}", node_to_string(node_id)),
|
||||
Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
|
||||
bug!("ConstVal `{:?}` should not be in MIR", const_val),
|
||||
Char(c) => write!(fmt, "{:?}", c),
|
||||
Dummy => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn node_to_string(node_id: ast::NodeId) -> String {
|
||||
ty::tls::with(|tcx| tcx.map.node_to_user_string(node_id))
|
||||
}
|
||||
|
||||
fn item_path_str(def_id: DefId) -> String {
|
||||
ty::tls::with(|tcx| tcx.item_path_str(def_id))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
|
||||
|
||||
tcx.infer_ctxt(None, Some(elaborated_env), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(elaborated_env, Reveal::NotSpecializable).enter(|infcx| {
|
||||
let predicates = match fully_normalize(&infcx, cause,
|
||||
&infcx.parameter_environment.caller_bounds) {
|
||||
Ok(predicates) => predicates,
|
||||
|
|
@ -576,7 +576,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
debug!("normalize_and_test_predicates(predicates={:?})",
|
||||
predicates);
|
||||
|
||||
tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||
tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
let cause = ObligationCause::dummy();
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let ancestors = trait_def.ancestors(impl_data.impl_def_id);
|
||||
match ancestors.defs(tcx, name, ty::AssociatedKind::Method).next() {
|
||||
Some(node_item) => {
|
||||
let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||
let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
|
||||
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
|
||||
let substs = translate_substs(&infcx, impl_data.impl_def_id,
|
||||
substs, node_item.node);
|
||||
|
|
@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
.subst(tcx, &penv.free_substs);
|
||||
|
||||
// Create a infcx, taking the predicates of impl1 as assumptions:
|
||||
let result = tcx.infer_ctxt(None, Some(penv), Reveal::ExactMatch).enter(|infcx| {
|
||||
let result = tcx.infer_ctxt(penv, Reveal::ExactMatch).enter(|infcx| {
|
||||
// Normalize the trait reference. The WF rules ought to ensure
|
||||
// that this always succeeds.
|
||||
let impl1_trait_ref =
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> Children {
|
|||
let possible_sibling = *slot;
|
||||
|
||||
let tcx = tcx.global_tcx();
|
||||
let (le, ge) = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
|
||||
let (le, ge) = tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
|
||||
let overlap = traits::overlapping_impls(&infcx,
|
||||
possible_sibling,
|
||||
impl_def_id);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ pub struct GlobalArenas<'tcx> {
|
|||
trait_def: TypedArena<ty::TraitDef>,
|
||||
adt_def: TypedArena<ty::AdtDef>,
|
||||
mir: TypedArena<RefCell<Mir<'tcx>>>,
|
||||
tables: TypedArena<ty::Tables<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> GlobalArenas<'tcx> {
|
||||
|
|
@ -75,6 +76,7 @@ impl<'tcx> GlobalArenas<'tcx> {
|
|||
trait_def: TypedArena::new(),
|
||||
adt_def: TypedArena::new(),
|
||||
mir: TypedArena::new(),
|
||||
tables: TypedArena::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,6 +191,7 @@ pub struct CommonTypes<'tcx> {
|
|||
pub err: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct Tables<'tcx> {
|
||||
/// Resolved definitions for `<T>::X` associated paths.
|
||||
pub type_relative_path_defs: NodeMap<Def>,
|
||||
|
|
@ -211,13 +214,11 @@ pub struct Tables<'tcx> {
|
|||
/// Borrows
|
||||
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
||||
|
||||
/// Records the type of each closure. The def ID is the ID of the
|
||||
/// expression defining the closure.
|
||||
pub closure_tys: DefIdMap<ty::ClosureTy<'tcx>>,
|
||||
/// Records the type of each closure.
|
||||
pub closure_tys: NodeMap<ty::ClosureTy<'tcx>>,
|
||||
|
||||
/// Records the type of each closure. The def ID is the ID of the
|
||||
/// expression defining the closure.
|
||||
pub closure_kinds: DefIdMap<ty::ClosureKind>,
|
||||
/// Records the type of each closure.
|
||||
pub closure_kinds: NodeMap<ty::ClosureKind>,
|
||||
|
||||
/// For each fn, records the "liberated" types of its arguments
|
||||
/// and return type. Liberated means that all bound regions
|
||||
|
|
@ -233,7 +234,7 @@ pub struct Tables<'tcx> {
|
|||
pub fru_field_types: NodeMap<Vec<Ty<'tcx>>>
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Tables<'tcx> {
|
||||
impl<'tcx> Tables<'tcx> {
|
||||
pub fn empty() -> Tables<'tcx> {
|
||||
Tables {
|
||||
type_relative_path_defs: NodeMap(),
|
||||
|
|
@ -242,8 +243,8 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
|
|||
adjustments: NodeMap(),
|
||||
method_map: FxHashMap(),
|
||||
upvar_capture_map: FxHashMap(),
|
||||
closure_tys: DefIdMap(),
|
||||
closure_kinds: DefIdMap(),
|
||||
closure_tys: NodeMap(),
|
||||
closure_kinds: NodeMap(),
|
||||
liberated_fn_sigs: NodeMap(),
|
||||
fru_field_types: NodeMap()
|
||||
}
|
||||
|
|
@ -401,7 +402,7 @@ pub struct GlobalCtxt<'tcx> {
|
|||
free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
|
||||
// FIXME: jroesch make this a refcell
|
||||
|
||||
pub tables: RefCell<Tables<'tcx>>,
|
||||
pub tables: RefCell<DepTrackingMap<maps::Tables<'tcx>>>,
|
||||
|
||||
/// Maps from a trait item to the trait item "descriptor"
|
||||
pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'tcx>>>,
|
||||
|
|
@ -524,6 +525,14 @@ pub struct GlobalCtxt<'tcx> {
|
|||
/// Caches CoerceUnsized kinds for impls on custom types.
|
||||
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
|
||||
|
||||
/// Records the type of each closure. The def ID is the ID of the
|
||||
/// expression defining the closure.
|
||||
pub closure_tys: RefCell<DepTrackingMap<maps::ClosureTypes<'tcx>>>,
|
||||
|
||||
/// Records the type of each closure. The def ID is the ID of the
|
||||
/// expression defining the closure.
|
||||
pub closure_kinds: RefCell<DepTrackingMap<maps::ClosureKinds<'tcx>>>,
|
||||
|
||||
/// Maps a cast expression to its kind. This is keyed on the
|
||||
/// *from* expression of the cast, not the cast itself.
|
||||
pub cast_kinds: RefCell<NodeMap<ty::cast::CastKind>>,
|
||||
|
|
@ -645,6 +654,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
self.global_arenas.mir.alloc(RefCell::new(mir))
|
||||
}
|
||||
|
||||
pub fn alloc_tables(self, tables: ty::Tables<'gcx>) -> &'gcx ty::Tables<'gcx> {
|
||||
self.global_arenas.tables.alloc(tables)
|
||||
}
|
||||
|
||||
pub fn alloc_trait_def(self, def: ty::TraitDef) -> &'gcx ty::TraitDef {
|
||||
self.global_arenas.trait_def.alloc(def)
|
||||
}
|
||||
|
|
@ -743,7 +756,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
variance_computed: Cell::new(false),
|
||||
sess: s,
|
||||
trait_map: resolutions.trait_map,
|
||||
tables: RefCell::new(Tables::empty()),
|
||||
tables: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
|
|
@ -777,6 +790,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
rvalue_promotable_to_static: RefCell::new(NodeMap()),
|
||||
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
|
||||
closure_tys: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
closure_kinds: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
cast_kinds: RefCell::new(NodeMap()),
|
||||
fragment_infos: RefCell::new(DefIdMap()),
|
||||
crate_name: Symbol::intern(crate_name),
|
||||
|
|
|
|||
|
|
@ -46,3 +46,6 @@ dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
|
|||
dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec<DefId> }
|
||||
dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
|
||||
dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> }
|
||||
dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
|
||||
dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
|
||||
dep_map_ty! { Tables: Tables(DefId) -> &'tcx ty::Tables<'tcx> }
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ pub struct MethodCallee<'tcx> {
|
|||
/// needed to add to the side tables. Thus to disambiguate
|
||||
/// we also keep track of whether there's an adjustment in
|
||||
/// our key.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct MethodCall {
|
||||
pub expr_id: NodeId,
|
||||
pub autoderef: u32
|
||||
|
|
@ -501,7 +501,7 @@ impl<T> Slice<T> {
|
|||
/// Upvars do not get their own node-id. Instead, we use the pair of
|
||||
/// the original var id (that is, the root variable that is referenced
|
||||
/// by the upvar) and the id of the closure expression.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct UpvarId {
|
||||
pub var_id: NodeId,
|
||||
pub closure_expr_id: NodeId,
|
||||
|
|
@ -1917,8 +1917,30 @@ impl BorrowKind {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn tables(self) -> Ref<'a, Tables<'gcx>> {
|
||||
self.tables.borrow()
|
||||
pub fn body_tables(self, body: hir::BodyId) -> &'gcx Tables<'gcx> {
|
||||
self.item_tables(self.map.body_owner_def_id(body))
|
||||
}
|
||||
|
||||
pub fn item_tables(self, def_id: DefId) -> &'gcx Tables<'gcx> {
|
||||
self.tables.memoize(def_id, || {
|
||||
if def_id.is_local() {
|
||||
// Closures' tables come from their outermost function,
|
||||
// as they are part of the same "inference environment".
|
||||
let outer_def_id = self.closure_base_def_id(def_id);
|
||||
if outer_def_id != def_id {
|
||||
return self.item_tables(outer_def_id);
|
||||
}
|
||||
|
||||
bug!("No def'n found for {:?} in tcx.tables", def_id);
|
||||
}
|
||||
|
||||
// Cross-crate side-tables only exist alongside serialized HIR.
|
||||
self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
|
||||
self.tables.borrow()[&def_id]
|
||||
}).unwrap_or_else(|| {
|
||||
bug!("tcx.item_tables({:?}): missing from metadata", def_id)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expr_span(self, id: NodeId) -> Span {
|
||||
|
|
@ -2454,12 +2476,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
// If this is a local def-id, it should be inserted into the
|
||||
// tables by typeck; else, it will be retreived from
|
||||
// the external crate metadata.
|
||||
if let Some(&kind) = self.tables.borrow().closure_kinds.get(&def_id) {
|
||||
if let Some(&kind) = self.closure_kinds.borrow().get(&def_id) {
|
||||
return kind;
|
||||
}
|
||||
|
||||
let kind = self.sess.cstore.closure_kind(def_id);
|
||||
self.tables.borrow_mut().closure_kinds.insert(def_id, kind);
|
||||
self.closure_kinds.borrow_mut().insert(def_id, kind);
|
||||
kind
|
||||
}
|
||||
|
||||
|
|
@ -2471,12 +2493,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
// If this is a local def-id, it should be inserted into the
|
||||
// tables by typeck; else, it will be retreived from
|
||||
// the external crate metadata.
|
||||
if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) {
|
||||
if let Some(ty) = self.closure_tys.borrow().get(&def_id) {
|
||||
return ty.subst(self, substs.substs);
|
||||
}
|
||||
|
||||
let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
|
||||
self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone());
|
||||
self.closure_tys.borrow_mut().insert(def_id, ty.clone());
|
||||
ty.subst(self, substs.substs)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
|
|||
self_type: Ty<'tcx>, span: Span)
|
||||
-> Result<(), CopyImplementationError> {
|
||||
// FIXME: (@jroesch) float this code up
|
||||
tcx.infer_ctxt(None, Some(self.clone()), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(self.clone(), Reveal::NotSpecializable).enter(|infcx| {
|
||||
let (adt, substs) = match self_type.sty {
|
||||
ty::TyAdt(adt, substs) => (adt, substs),
|
||||
_ => return Err(CopyImplementationError::NotAnAdt)
|
||||
|
|
@ -536,7 +536,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
}
|
||||
}
|
||||
let result =
|
||||
tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch)
|
||||
tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch)
|
||||
.enter(|infcx| {
|
||||
traits::type_known_to_meet_bound(&infcx, self, def_id, span)
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue