Auto merge of #38449 - eddyb:lazy-10, r=nikomatsakis

[10/n] Split constants and functions' arguments into disjoint bodies.

_This is part of a series ([prev](https://github.com/rust-lang/rust/pull/38053) | [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>

Finishes the signature-body split started in #37918, namely:
* `trait` items are separated just like `impl` items were, for uniformity, closing #37712
* `static`s, `const`s (including associated ones), `enum` discriminants and array lengths get bodies
  * even the count in "repeat expressions", i.e. `n` in `[x; n]`, which fixes #24414
* arguments' patterns are moved to the bodies, with the types staying in `FnDecl`
  * `&self` now desugars to `self: &Self` instead of `self: &_` (similarly for other `self` forms)
  * `astconv`'s and metadata's (for rustdoc) informative uses are explicitly ignored for the purposes of the dep graph. this could be fixed in the future by hashing the exact information being extracted about the arguments as opposed to generating a dependency on *the whole body*
This commit is contained in:
bors 2016-12-28 20:19:39 +00:00
commit 4ecc85beb3
124 changed files with 2284 additions and 2761 deletions

View file

@ -327,10 +327,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
self.opt_expr(base, field_cfg)
}
hir::ExprRepeat(ref elem, ref count) => {
self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
}
hir::ExprAssign(ref l, ref r) |
hir::ExprAssignOp(_, ref l, ref r) => {
self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
@ -347,7 +343,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
hir::ExprType(ref e, _) |
hir::ExprUnary(_, ref e) |
hir::ExprField(ref e, _) |
hir::ExprTupField(ref e, _) => {
hir::ExprTupField(ref e, _) |
hir::ExprRepeat(ref e, _) => {
self.straightline(expr, pred, Some(&**e).into_iter())
}

View file

@ -51,6 +51,12 @@ impl DepGraph {
}
}
/// True if we are actually building the full dep-graph.
#[inline]
pub fn is_fully_enabled(&self) -> bool {
self.data.thread.is_fully_enabled()
}
pub fn query(&self) -> DepGraphQuery<DefId> {
self.data.thread.query()
}

View file

@ -45,6 +45,16 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
debug!("Ended task {:?}", task_id);
}
fn visit_trait_item(&mut self, i: &'tcx hir::TraitItem) {
let trait_item_def_id = self.tcx.map.local_def_id(i.id);
let task_id = (self.dep_node_fn)(trait_item_def_id);
let _task = self.tcx.dep_graph.in_task(task_id.clone());
debug!("Started task {:?}", task_id);
self.tcx.dep_graph.read(DepNode::Hir(trait_item_def_id));
self.visitor.visit_trait_item(i);
debug!("Ended task {:?}", task_id);
}
fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
let impl_item_def_id = self.tcx.map.local_def_id(i.id);
let task_id = (self.dep_node_fn)(impl_item_def_id);

View file

@ -177,6 +177,17 @@ pub trait Visitor<'v> : Sized {
}
}
/// Like `visit_nested_item()`, but for trait items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
#[allow(unused_variables)]
fn visit_nested_trait_item(&mut self, id: TraitItemId) {
let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
if let Some(item) = opt_item {
self.visit_trait_item(item);
}
}
/// Like `visit_nested_item()`, but for impl items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
@ -192,10 +203,10 @@ pub trait Visitor<'v> : Sized {
/// visit_nested_item, does nothing by default unless you override
/// `nested_visit_map` to return `Some(_)`, in which case it will walk the
/// body.
fn visit_body(&mut self, id: ExprId) {
let opt_expr = self.nested_visit_map().intra().map(|map| map.expr(id));
if let Some(expr) = opt_expr {
self.visit_expr(expr);
fn visit_nested_body(&mut self, id: BodyId) {
let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
if let Some(body) = opt_body {
self.visit_body(body);
}
}
@ -205,6 +216,10 @@ pub trait Visitor<'v> : Sized {
walk_item(self, i)
}
fn visit_body(&mut self, b: &'v Body) {
walk_body(self, b);
}
/// When invoking `visit_all_item_likes()`, you need to supply an
/// item-like visitor. This method converts a "intra-visit"
/// visitor into an item-like visitor that walks the entire tree.
@ -253,8 +268,6 @@ pub trait Visitor<'v> : Sized {
fn visit_expr(&mut self, ex: &'v Expr) {
walk_expr(self, ex)
}
fn visit_expr_post(&mut self, _ex: &'v Expr) {
}
fn visit_ty(&mut self, t: &'v Ty) {
walk_ty(self, t)
}
@ -267,12 +280,15 @@ pub trait Visitor<'v> : Sized {
fn visit_fn_decl(&mut self, fd: &'v FnDecl) {
walk_fn_decl(self, fd)
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: ExprId, s: Span, id: NodeId) {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
walk_fn(self, fk, fd, b, s, id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
walk_trait_item(self, ti)
}
fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) {
walk_trait_item_ref(self, ii)
}
fn visit_impl_item(&mut self, ii: &'v ImplItem) {
walk_impl_item(self, ii)
}
@ -378,6 +394,14 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_i
}
}
pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
for argument in &body.arguments {
visitor.visit_id(argument.id);
visitor.visit_pat(&argument.pat);
}
visitor.visit_expr(&body.value);
}
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
visitor.visit_id(local.id);
visitor.visit_pat(&local.pat);
@ -423,11 +447,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_id(item.id);
visitor.visit_path(path, item.id);
}
ItemStatic(ref typ, _, ref expr) |
ItemConst(ref typ, ref expr) => {
ItemStatic(ref typ, _, body) |
ItemConst(ref typ, body) => {
visitor.visit_id(item.id);
visitor.visit_ty(typ);
visitor.visit_expr(expr);
visitor.visit_nested_body(body);
}
ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
visitor.visit_fn(FnKind::ItemFn(item.name,
@ -469,9 +493,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_generics(type_parameters);
walk_list!(visitor, visit_trait_ref, opt_trait_reference);
visitor.visit_ty(typ);
for impl_item_ref in impl_item_refs {
visitor.visit_impl_item_ref(impl_item_ref);
}
walk_list!(visitor, visit_impl_item_ref, impl_item_refs);
}
ItemStruct(ref struct_definition, ref generics) |
ItemUnion(ref struct_definition, ref generics) => {
@ -479,11 +501,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
}
ItemTrait(_, ref generics, ref bounds, ref methods) => {
ItemTrait(_, ref generics, ref bounds, ref trait_item_refs) => {
visitor.visit_id(item.id);
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_trait_item, methods);
walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
}
}
walk_list!(visitor, visit_attribute, &item.attrs);
@ -511,7 +533,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
generics,
parent_item_id,
variant.span);
walk_list!(visitor, visit_expr, &variant.node.disr_expr);
walk_list!(visitor, visit_nested_body, variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
@ -544,9 +566,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
visitor.visit_ty(ty);
walk_list!(visitor, visit_ty_param_bound, bounds);
}
TyArray(ref ty, ref expression) => {
TyArray(ref ty, length) => {
visitor.visit_ty(ty);
visitor.visit_expr(expression)
visitor.visit_nested_body(length)
}
TyPolyTraitRef(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
@ -554,8 +576,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
TyImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
TyTypeof(ref expression) => {
visitor.visit_expr(expression)
TyTypeof(expression) => {
visitor.visit_nested_body(expression)
}
TyInfer => {}
}
@ -662,9 +684,12 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
visitor.visit_name(foreign_item.span, foreign_item.name);
match foreign_item.node {
ForeignItemFn(ref function_declaration, ref generics) => {
ForeignItemFn(ref function_declaration, ref names, ref generics) => {
visitor.visit_generics(generics);
visitor.visit_fn_decl(function_declaration);
visitor.visit_generics(generics)
for name in names {
visitor.visit_name(name.span, name.node);
}
}
ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
}
@ -732,18 +757,8 @@ pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionR
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
for argument in &function_declaration.inputs {
visitor.visit_id(argument.id);
visitor.visit_pat(&argument.pat);
visitor.visit_ty(&argument.ty)
}
walk_fn_ret_ty(visitor, &function_declaration.output)
}
pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
for argument in &function_declaration.inputs {
visitor.visit_id(argument.id);
visitor.visit_ty(&argument.ty)
for ty in &function_declaration.inputs {
visitor.visit_ty(ty)
}
walk_fn_ret_ty(visitor, &function_declaration.output)
}
@ -763,42 +778,33 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
function_kind: FnKind<'v>,
function_declaration: &'v FnDecl,
body_id: ExprId,
body_id: BodyId,
_span: Span,
id: NodeId) {
visitor.visit_id(id);
visitor.visit_fn_decl(function_declaration);
walk_fn_kind(visitor, function_kind);
visitor.visit_body(body_id)
}
pub fn walk_fn_with_body<'v, V: Visitor<'v>>(visitor: &mut V,
function_kind: FnKind<'v>,
function_declaration: &'v FnDecl,
body: &'v Expr,
_span: Span,
id: NodeId) {
visitor.visit_id(id);
visitor.visit_fn_decl(function_declaration);
walk_fn_kind(visitor, function_kind);
visitor.visit_expr(body)
visitor.visit_nested_body(body_id)
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
visitor.visit_name(trait_item.span, trait_item.name);
walk_list!(visitor, visit_attribute, &trait_item.attrs);
match trait_item.node {
ConstTraitItem(ref ty, ref default) => {
TraitItemKind::Const(ref ty, default) => {
visitor.visit_id(trait_item.id);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, default);
walk_list!(visitor, visit_nested_body, default);
}
MethodTraitItem(ref sig, None) => {
TraitItemKind::Method(ref sig, TraitMethod::Required(ref names)) => {
visitor.visit_id(trait_item.id);
visitor.visit_generics(&sig.generics);
visitor.visit_fn_decl(&sig.decl);
for name in names {
visitor.visit_name(name.span, name.node);
}
}
MethodTraitItem(ref sig, Some(body_id)) => {
TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => {
visitor.visit_fn(FnKind::Method(trait_item.name,
sig,
None,
@ -808,7 +814,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
trait_item.span,
trait_item.id);
}
TypeTraitItem(ref bounds, ref default) => {
TraitItemKind::Type(ref bounds, ref default) => {
visitor.visit_id(trait_item.id);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_ty, default);
@ -816,6 +822,15 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
}
}
pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
// NB: Deliberately force a compilation error if/when new fields are added.
let TraitItemRef { id, name, ref kind, span, ref defaultness } = *trait_item_ref;
visitor.visit_nested_trait_item(id);
visitor.visit_name(span, name);
visitor.visit_associated_item_kind(kind);
visitor.visit_defaultness(defaultness);
}
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
// NB: Deliberately force a compilation error if/when new fields are added.
let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item;
@ -825,10 +840,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
visitor.visit_defaultness(defaultness);
walk_list!(visitor, visit_attribute, attrs);
match *node {
ImplItemKind::Const(ref ty, ref expr) => {
ImplItemKind::Const(ref ty, body) => {
visitor.visit_id(impl_item.id);
visitor.visit_ty(ty);
visitor.visit_expr(expr);
visitor.visit_nested_body(body);
}
ImplItemKind::Method(ref sig, body_id) => {
visitor.visit_fn(FnKind::Method(impl_item.name,
@ -907,9 +922,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
ExprArray(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
ExprRepeat(ref element, ref count) => {
ExprRepeat(ref element, count) => {
visitor.visit_expr(element);
visitor.visit_expr(count)
visitor.visit_nested_body(count)
}
ExprStruct(ref qpath, ref fields, ref optional_base) => {
visitor.visit_qpath(qpath, expression.id, expression.span);
@ -1016,8 +1031,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
}
}
}
visitor.visit_expr_post(expression)
}
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
@ -1100,16 +1113,3 @@ impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> {
self.result.add(id);
}
}
/// Computes the id range for a single fn body, ignoring nested items.
pub fn compute_id_range_for_fn_body<'v>(fk: FnKind<'v>,
decl: &'v FnDecl,
body: &'v Expr,
sp: Span,
id: NodeId,
map: &map::Map<'v>)
-> IdRange {
let mut visitor = IdRangeComputingVisitor::new(map);
walk_fn_with_body(&mut visitor, fk, decl, body, sp, id);
visitor.result()
}

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::{Item, ImplItem};
use super::{Item, ImplItem, TraitItem};
use super::intravisit::Visitor;
/// The "item-like visitor" visitor defines only the top-level methods
@ -58,6 +58,7 @@ use super::intravisit::Visitor;
/// needed.
pub trait ItemLikeVisitor<'hir> {
fn visit_item(&mut self, item: &'hir Item);
fn visit_trait_item(&mut self, trait_item: &'hir TraitItem);
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem);
}
@ -80,6 +81,10 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
self.visitor.visit_item(item);
}
fn visit_trait_item(&mut self, trait_item: &'hir TraitItem) {
self.visitor.visit_trait_item(trait_item);
}
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
self.visitor.visit_impl_item(impl_item);
}

View file

@ -46,12 +46,10 @@ use hir::map::definitions::DefPathData;
use hir::def_id::{DefIndex, DefId};
use hir::def::{Def, PathResolution};
use session::Session;
use util::nodemap::NodeMap;
use rustc_data_structures::fnv::FnvHashMap;
use util::nodemap::{NodeMap, FxHashMap};
use std::collections::BTreeMap;
use std::iter;
use std::mem;
use syntax::ast::*;
use syntax::errors;
@ -71,13 +69,14 @@ pub struct LoweringContext<'a> {
// the form of a DefIndex) so that if we create a new node which introduces
// a definition, then we can properly create the def id.
parent_def: Option<DefIndex>,
exprs: FnvHashMap<hir::ExprId, hir::Expr>,
resolver: &'a mut Resolver,
/// The items being lowered are collected here.
items: BTreeMap<NodeId, hir::Item>,
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: FxHashMap<hir::BodyId, hir::Body>,
}
pub trait Resolver {
@ -105,10 +104,11 @@ pub fn lower_crate(sess: &Session,
crate_root: std_inject::injected_crate_name(krate),
sess: sess,
parent_def: None,
exprs: FnvHashMap(),
resolver: resolver,
items: BTreeMap::new(),
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
bodies: FxHashMap(),
}.lower_crate(krate)
}
@ -133,8 +133,9 @@ impl<'a> LoweringContext<'a> {
span: c.span,
exported_macros: exported_macros,
items: self.items,
trait_items: self.trait_items,
impl_items: self.impl_items,
exprs: mem::replace(&mut self.exprs, FnvHashMap()),
bodies: self.bodies,
}
}
@ -150,8 +151,15 @@ impl<'a> LoweringContext<'a> {
visit::walk_item(self, item);
}
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
let id = hir::TraitItemId { node_id: item.id };
let hir_item = self.lctx.lower_trait_item(item);
self.lctx.trait_items.insert(id, hir_item);
visit::walk_trait_item(self, item);
}
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
let id = self.lctx.lower_impl_item_ref(item).id;
let id = hir::ImplItemId { node_id: item.id };
let hir_item = self.lctx.lower_impl_item(item);
self.lctx.impl_items.insert(id, hir_item);
visit::walk_impl_item(self, item);
@ -162,9 +170,16 @@ impl<'a> LoweringContext<'a> {
visit::walk_crate(&mut item_lowerer, c);
}
fn record_expr(&mut self, expr: hir::Expr) -> hir::ExprId {
let id = hir::ExprId(expr.id);
self.exprs.insert(id, expr);
fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
-> hir::BodyId {
let body = hir::Body {
arguments: decl.map_or(hir_vec![], |decl| {
decl.inputs.iter().map(|x| self.lower_arg(x)).collect()
}),
value: value
};
let id = body.id();
self.bodies.insert(id, body);
id
}
@ -259,7 +274,7 @@ impl<'a> LoweringContext<'a> {
P(hir::Ty {
id: t.id,
node: match t.node {
TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
TyKind::Infer => hir::TyInfer,
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
TyKind::Rptr(ref region, ref mt) => {
@ -283,14 +298,27 @@ impl<'a> LoweringContext<'a> {
TyKind::Path(ref qself, ref path) => {
hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
}
TyKind::ImplicitSelf => {
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
def: self.expect_full_def(t.id),
segments: hir_vec![hir::PathSegment {
name: keywords::SelfType.name(),
parameters: hir::PathParameters::none()
}],
span: t.span,
})))
}
TyKind::ObjectSum(ref ty, ref bounds) => {
hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
}
TyKind::Array(ref ty, ref e) => {
hir::TyArray(self.lower_ty(ty), P(self.lower_expr(e)))
TyKind::Array(ref ty, ref length) => {
let length = self.lower_expr(length);
hir::TyArray(self.lower_ty(ty),
self.record_body(length, None))
}
TyKind::Typeof(ref expr) => {
hir::TyTypeof(P(self.lower_expr(expr)))
let expr = self.lower_expr(expr);
hir::TyTypeof(self.record_body(expr, None))
}
TyKind::PolyTraitRef(ref bounds) => {
hir::TyPolyTraitRef(self.lower_bounds(bounds))
@ -317,7 +345,10 @@ impl<'a> LoweringContext<'a> {
name: v.node.name.name,
attrs: self.lower_attrs(&v.node.attrs),
data: self.lower_variant_data(&v.node.data),
disr_expr: v.node.disr_expr.as_ref().map(|e| P(self.lower_expr(e))),
disr_expr: v.node.disr_expr.as_ref().map(|e| {
let e = self.lower_expr(e);
self.record_body(e, None)
}),
},
span: v.span,
}
@ -505,13 +536,24 @@ impl<'a> LoweringContext<'a> {
hir::Arg {
id: arg.id,
pat: self.lower_pat(&arg.pat),
ty: self.lower_ty(&arg.ty),
}
}
fn lower_fn_args_to_names(&mut self, decl: &FnDecl)
-> hir::HirVec<Spanned<Name>> {
decl.inputs.iter().map(|arg| {
match arg.pat.node {
PatKind::Ident(_, ident, None) => {
respan(ident.span, ident.node.name)
}
_ => respan(arg.pat.span, keywords::Invalid.name()),
}
}).collect()
}
fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
P(hir::FnDecl {
inputs: decl.inputs.iter().map(|x| self.lower_arg(x)).collect(),
inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(),
output: match decl.output {
FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
@ -839,17 +881,20 @@ impl<'a> LoweringContext<'a> {
hir::ItemUse(path, kind)
}
ItemKind::Static(ref t, m, ref e) => {
let value = self.lower_expr(e);
hir::ItemStatic(self.lower_ty(t),
self.lower_mutability(m),
P(self.lower_expr(e)))
self.record_body(value, None))
}
ItemKind::Const(ref t, ref e) => {
hir::ItemConst(self.lower_ty(t), P(self.lower_expr(e)))
let value = self.lower_expr(e);
hir::ItemConst(self.lower_ty(t),
self.record_body(value, None))
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
let body = self.lower_block(body);
let body = self.expr_block(body, ThinVec::new());
let body_id = self.record_expr(body);
let body_id = self.record_body(body, Some(decl));
hir::ItemFn(self.lower_fn_decl(decl),
self.lower_unsafety(unsafety),
self.lower_constness(constness),
@ -897,7 +942,7 @@ impl<'a> LoweringContext<'a> {
}
ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => {
let bounds = self.lower_bounds(bounds);
let items = items.iter().map(|item| self.lower_trait_item(item)).collect();
let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
hir::ItemTrait(self.lower_unsafety(unsafety),
self.lower_generics(generics),
bounds,
@ -915,20 +960,27 @@ impl<'a> LoweringContext<'a> {
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
TraitItemKind::Const(ref ty, ref default) => {
hir::ConstTraitItem(this.lower_ty(ty),
default.as_ref().map(|x| P(this.lower_expr(x))))
}
TraitItemKind::Method(ref sig, ref body) => {
hir::MethodTraitItem(this.lower_method_sig(sig),
body.as_ref().map(|x| {
let body = this.lower_block(x);
let expr = this.expr_block(body, ThinVec::new());
this.record_expr(expr)
hir::TraitItemKind::Const(this.lower_ty(ty),
default.as_ref().map(|x| {
let value = this.lower_expr(x);
this.record_body(value, None)
}))
}
TraitItemKind::Method(ref sig, None) => {
let names = this.lower_fn_args_to_names(&sig.decl);
hir::TraitItemKind::Method(this.lower_method_sig(sig),
hir::TraitMethod::Required(names))
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
let body = this.lower_block(body);
let expr = this.expr_block(body, ThinVec::new());
let body_id = this.record_body(expr, Some(&sig.decl));
hir::TraitItemKind::Method(this.lower_method_sig(sig),
hir::TraitMethod::Provided(body_id))
}
TraitItemKind::Type(ref bounds, ref default) => {
hir::TypeTraitItem(this.lower_bounds(bounds),
default.as_ref().map(|x| this.lower_ty(x)))
hir::TraitItemKind::Type(this.lower_bounds(bounds),
default.as_ref().map(|x| this.lower_ty(x)))
}
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
},
@ -937,6 +989,30 @@ impl<'a> LoweringContext<'a> {
})
}
fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
let (kind, has_default) = match i.node {
TraitItemKind::Const(_, ref default) => {
(hir::AssociatedItemKind::Const, default.is_some())
}
TraitItemKind::Type(_, ref default) => {
(hir::AssociatedItemKind::Type, default.is_some())
}
TraitItemKind::Method(ref sig, ref default) => {
(hir::AssociatedItemKind::Method {
has_self: sig.decl.has_self(),
}, default.is_some())
}
TraitItemKind::Macro(..) => unimplemented!(),
};
hir::TraitItemRef {
id: hir::TraitItemId { node_id: i.id },
name: i.ident.name,
span: i.span,
defaultness: self.lower_defaultness(Defaultness::Default, has_default),
kind: kind,
}
}
fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
self.with_parent_def(i.id, |this| {
hir::ImplItem {
@ -947,13 +1023,15 @@ impl<'a> LoweringContext<'a> {
defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
node: match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
hir::ImplItemKind::Const(this.lower_ty(ty), P(this.lower_expr(expr)))
let value = this.lower_expr(expr);
let body_id = this.record_body(value, None);
hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
}
ImplItemKind::Method(ref sig, ref body) => {
let body = this.lower_block(body);
let expr = this.expr_block(body, ThinVec::new());
let expr_id = this.record_expr(expr);
hir::ImplItemKind::Method(this.lower_method_sig(sig), expr_id)
let body_id = this.record_body(expr, Some(&sig.decl));
hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
}
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@ -976,7 +1054,7 @@ impl<'a> LoweringContext<'a> {
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
has_self: sig.decl.get_self().is_some(),
has_self: sig.decl.has_self(),
},
ImplItemKind::Macro(..) => unimplemented!(),
},
@ -1038,7 +1116,9 @@ impl<'a> LoweringContext<'a> {
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
ForeignItemKind::Fn(ref fdec, ref generics) => {
hir::ForeignItemFn(this.lower_fn_decl(fdec), this.lower_generics(generics))
hir::ForeignItemFn(this.lower_fn_decl(fdec),
this.lower_fn_args_to_names(fdec),
this.lower_generics(generics))
}
ForeignItemKind::Static(ref t, m) => {
hir::ForeignItemStatic(this.lower_ty(t), m)
@ -1051,24 +1131,13 @@ impl<'a> LoweringContext<'a> {
}
fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
let hir_sig = hir::MethodSig {
hir::MethodSig {
generics: self.lower_generics(&sig.generics),
abi: sig.abi,
unsafety: self.lower_unsafety(sig.unsafety),
constness: self.lower_constness(sig.constness),
decl: self.lower_fn_decl(&sig.decl),
};
// Check for `self: _` and `self: &_`
if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) {
match hir_sig.decl.get_self().map(|eself| eself.node) {
Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => {
self.diagnostic().span_err(sig.decl.inputs[0].ty.span,
"the type placeholder `_` is not allowed within types on item signatures");
}
_ => {}
}
}
hir_sig
}
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
@ -1318,8 +1387,8 @@ impl<'a> LoweringContext<'a> {
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = P(self.lower_expr(expr));
let count = P(self.lower_expr(count));
hir::ExprRepeat(expr, count)
let count = self.lower_expr(count);
hir::ExprRepeat(expr, self.record_body(count, None))
}
ExprKind::Tup(ref elts) => {
hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
@ -1402,7 +1471,7 @@ impl<'a> LoweringContext<'a> {
let expr = this.lower_expr(body);
hir::ExprClosure(this.lower_capture_clause(capture_clause),
this.lower_fn_decl(decl),
this.record_expr(expr),
this.record_body(expr, Some(decl)),
fn_decl_span)
})
}
@ -1686,13 +1755,7 @@ impl<'a> LoweringContext<'a> {
// `::std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
let body_block = self.lower_block(body);
let body_span = body_block.span;
let body_expr = P(hir::Expr {
id: self.next_id(),
node: hir::ExprBlock(body_block),
span: body_span,
attrs: ThinVec::new(),
});
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let pat = self.lower_pat(pat);
let some_pat = self.pat_some(e.span, pat);

View file

@ -48,7 +48,7 @@ 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::ExprId,
pub body: ast::BodyId,
pub kind: FnKind<'a>,
pub span: Span,
pub id: NodeId,
@ -62,7 +62,10 @@ impl MaybeFnLike for ast::Item {
impl MaybeFnLike for ast::TraitItem {
fn is_fn_like(&self) -> bool {
match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
match self.node {
ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
_ => false,
}
}
}
@ -115,7 +118,7 @@ struct ItemFnParts<'a> {
abi: abi::Abi,
vis: &'a ast::Visibility,
generics: &'a ast::Generics,
body: ast::ExprId,
body: ast::BodyId,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
@ -125,14 +128,14 @@ struct ItemFnParts<'a> {
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
decl: &'a FnDecl,
body: ast::ExprId,
body: ast::BodyId,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
}
impl<'a> ClosureParts<'a> {
fn new(d: &'a FnDecl, b: ast::ExprId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
fn new(d: &'a FnDecl, b: ast::BodyId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
ClosureParts {
decl: d,
body: b,
@ -172,9 +175,9 @@ impl<'a> FnLikeNode<'a> {
}
}
pub fn body(self) -> ast::ExprId {
pub fn body(self) -> ast::BodyId {
self.handle(|i: ItemFnParts<'a>| i.body,
|_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _| body,
|_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
|c: ClosureParts<'a>| c.body)
}
@ -227,7 +230,7 @@ impl<'a> FnLikeNode<'a> {
Name,
&'a ast::MethodSig,
Option<&'a ast::Visibility>,
ast::ExprId,
ast::BodyId,
Span,
&'a [Attribute])
-> A,
@ -252,7 +255,7 @@ impl<'a> FnLikeNode<'a> {
_ => bug!("item FnLikeNode that is not fn-like"),
},
map::NodeTraitItem(ti) => match ti.node {
ast::MethodTraitItem(ref sig, Some(body)) => {
ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
method(ti.id, ti.name, sig, None, body, ti.span, &ti.attrs)
}
_ => bug!("trait method FnLikeNode that is not fn-like"),

View file

@ -11,7 +11,6 @@
use super::*;
use hir::intravisit::{Visitor, NestedVisitorMap};
use middle::cstore::InlinedItem;
use std::iter::repeat;
use syntax::ast::{NodeId, CRATE_NODE_ID};
use syntax_pos::Span;
@ -21,7 +20,7 @@ pub struct NodeCollector<'ast> {
/// The crate
pub krate: &'ast Crate,
/// The node map
pub map: Vec<MapEntry<'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
@ -43,11 +42,11 @@ impl<'ast> NodeCollector<'ast> {
collector
}
pub fn extend(krate: &'ast Crate,
parent: &'ast InlinedItem,
parent_node: NodeId,
map: Vec<MapEntry<'ast>>)
-> NodeCollector<'ast> {
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,
@ -98,12 +97,22 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
}
}
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
self.visit_impl_item(self.krate.impl_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))
}
}
fn visit_body(&mut self, id: ExprId) {
self.visit_expr(self.krate.expr(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))
}
}
fn visit_nested_body(&mut self, id: BodyId) {
if !self.ignore_nested_items {
self.visit_body(self.krate.body(id))
}
}
fn visit_item(&mut self, i: &'ast Item) {
@ -113,11 +122,6 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
self.with_parent(i.id, |this| {
match i.node {
ItemEnum(ref enum_definition, _) => {
for v in &enum_definition.variants {
this.insert(v.node.data.id(), NodeVariant(v));
}
}
ItemStruct(ref struct_def, _) => {
// If this is a tuple-like struct, register the constructor.
if !struct_def.is_struct() {
@ -209,7 +213,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
}
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
b: ExprId, s: Span, id: NodeId) {
b: BodyId, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
intravisit::walk_fn(self, fk, fd, b, s, id);
}
@ -243,6 +247,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
self.insert_entry(macro_def.id, NotPresent);
}
fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) {
let id = v.node.data.id();
self.insert(id, NodeVariant(v));
self.with_parent(id, |this| {
intravisit::walk_variant(this, v, g, item_id);
});
}
fn visit_struct_field(&mut self, field: &'ast StructField) {
self.insert(field.id, NodeField(field));
self.with_parent(field.id, |this| {

View file

@ -16,7 +16,7 @@ use syntax::ext::hygiene::Mark;
use syntax::visit;
use syntax::symbol::{Symbol, keywords};
/// Creates def ids for nodes in the HIR.
/// Creates def ids for nodes in the AST.
pub struct DefCollector<'a> {
definitions: &'a mut Definitions,
parent_def: Option<DefIndex>,

View file

@ -220,7 +220,6 @@ impl DefPath {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DefPathData {
// Root: these should only be used for the root nodes, because
@ -339,7 +338,7 @@ impl Definitions {
data,
self.table.def_key(self.node_to_def_index[&node_id]));
assert!(parent.is_some() ^ (data == DefPathData::CrateRoot));
assert_eq!(parent.is_some(), data != DefPathData::CrateRoot);
// Find a unique DefKey. This basically means incrementing the disambiguator
// until we get no match.

View file

@ -17,7 +17,6 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
use dep_graph::{DepGraph, DepNode};
use middle::cstore::InlinedItem;
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use syntax::abi::Abi;
@ -26,7 +25,8 @@ use syntax::codemap::Spanned;
use syntax_pos::Span;
use hir::*;
use hir::print as pprust;
use hir::intravisit::Visitor;
use hir::print::Nested;
use arena::TypedArena;
use std::cell::RefCell;
@ -38,6 +38,15 @@ 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),
@ -60,14 +69,12 @@ pub enum Node<'ast> {
NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam),
NodeVisibility(&'ast Visibility),
NodeInlinedItem(&'ast InlinedItem),
}
/// Represents an entry and its parent NodeID.
/// The odd layout is to bring down the total size.
#[derive(Copy, Debug)]
pub enum MapEntry<'ast> {
enum MapEntry<'ast> {
/// Placeholder for holes in the map.
NotPresent,
@ -121,8 +128,6 @@ impl<'ast> MapEntry<'ast> {
NodeLifetime(n) => EntryLifetime(p, n),
NodeTyParam(n) => EntryTyParam(p, n),
NodeVisibility(n) => EntryVisibility(p, n),
NodeInlinedItem(n) => RootInlinedParent(n),
}
}
@ -171,10 +176,49 @@ impl<'ast> MapEntry<'ast> {
EntryLifetime(_, n) => NodeLifetime(n),
EntryTyParam(_, n) => NodeTyParam(n),
EntryVisibility(_, n) => NodeVisibility(n),
RootInlinedParent(n) => NodeInlinedItem(n),
_ => return None
})
}
fn is_body_owner(self, node_id: NodeId) -> bool {
match self {
EntryItem(_, item) => {
match item.node {
ItemConst(_, body) |
ItemStatic(.., body) |
ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
_ => false
}
}
EntryTraitItem(_, item) => {
match item.node {
TraitItemKind::Const(_, Some(body)) |
TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
body.node_id == node_id
}
_ => false
}
}
EntryImplItem(_, item) => {
match item.node {
ImplItemKind::Const(_, body) |
ImplItemKind::Method(_, body) => body.node_id == node_id,
_ => false
}
}
EntryExpr(_, expr) => {
match expr.node {
ExprClosure(.., body, _) => body.node_id == node_id,
_ => false
}
}
_ => false
}
}
}
/// Stores a crate and any number of inlined items from other crates.
@ -250,38 +294,34 @@ impl<'ast> Map<'ast> {
if !self.is_inlined_node_id(id) {
let mut last_expr = None;
loop {
match map[id.as_usize()] {
EntryItem(_, item) => {
assert_eq!(id, item.id);
let def_id = self.local_def_id(id);
let entry = map[id.as_usize()];
match entry {
EntryItem(..) |
EntryTraitItem(..) |
EntryImplItem(..) => {
if let Some(last_id) = last_expr {
// The body of the item may have a separate dep node
// (Note that trait items don't currently have
// their own dep node, so there's also just one
// HirBody node for all the items)
if self.is_body(last_id, item) {
// 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(def_id);
return DepNode::Hir(self.local_def_id(id));
}
EntryImplItem(_, item) => {
let def_id = self.local_def_id(id);
EntryVariant(p, v) => {
id = p;
if let Some(last_id) = last_expr {
// The body of the item may have a separate dep node
if self.is_impl_item_body(last_id, item) {
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);
}
}
return DepNode::Hir(def_id);
}
EntryForeignItem(p, _) |
EntryTraitItem(p, _) |
EntryVariant(p, _) |
EntryField(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
@ -308,7 +348,7 @@ impl<'ast> Map<'ast> {
bug!("node {} has inlined ancestor but is not inlined", id0),
NotPresent =>
// Some nodes, notably struct fields, are not
// 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.
@ -358,29 +398,6 @@ impl<'ast> Map<'ast> {
}
}
fn is_body(&self, node_id: NodeId, item: &Item) -> bool {
match item.node {
ItemFn(_, _, _, _, _, body) => body.node_id() == node_id,
// Since trait items currently don't get their own dep nodes,
// we check here whether node_id is the body of any of the items.
// If they get their own dep nodes, this can go away
ItemTrait(_, _, _, ref trait_items) => {
trait_items.iter().any(|trait_item| { match trait_item.node {
MethodTraitItem(_, Some(body)) => body.node_id() == node_id,
_ => false
}})
}
_ => false
}
}
fn is_impl_item_body(&self, node_id: NodeId, item: &ImplItem) -> bool {
match item.node {
ImplItemKind::Method(_, body) => body.node_id() == node_id,
_ => false
}
}
pub fn num_local_def_ids(&self) -> usize {
self.definitions.len()
}
@ -436,6 +453,14 @@ impl<'ast> Map<'ast> {
self.forest.krate()
}
pub fn trait_item(&self, id: TraitItemId) -> &'ast TraitItem {
self.read(id.node_id);
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.trait_item(id)
}
pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem {
self.read(id.node_id);
@ -444,6 +469,31 @@ impl<'ast> Map<'ast> {
self.forest.krate.impl_item(id)
}
pub fn body(&self, id: BodyId) -> &'ast Body {
self.read(id.node_id);
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.body(id)
}
/// Returns the `NodeId` that corresponds to the definition of
/// which this is the body of, i.e. a `fn`, `const` or `static`
/// item (possibly associated), or a closure, or the body itself
/// 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) {
parent
} else {
node_id
}
}
pub fn body_owner_def_id(&self, id: BodyId) -> DefId {
self.local_def_id(self.body_owner(id))
}
/// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
@ -687,17 +737,13 @@ impl<'ast> Map<'ast> {
}
}
pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem {
pub fn expect_inlined_body(&self, id: NodeId) -> &'ast Body {
match self.find_entry(id) {
Some(RootInlinedParent(inlined_item)) => inlined_item,
Some(RootInlinedParent(inlined_item)) => &inlined_item.body,
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
}
}
pub fn expr(&self, id: ExprId) -> &'ast Expr {
self.expect_expr(id.node_id())
}
/// Returns the name associated with the given NodeId's AST.
pub fn name(&self, id: NodeId) -> Name {
match self.get(id) {
@ -778,7 +824,7 @@ impl<'ast> Map<'ast> {
Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
Some(RootCrate) => self.forest.krate.span,
Some(RootInlinedParent(parent)) => parent.body.span,
Some(RootInlinedParent(parent)) => parent.body.value.span,
Some(NotPresent) | None => {
bug!("hir::map::Map::span: id not in map: {:?}", id)
}
@ -796,6 +842,10 @@ impl<'ast> Map<'ast> {
pub fn node_to_user_string(&self, id: NodeId) -> String {
node_id_to_string(self, id, false)
}
pub fn node_to_pretty_string(&self, id: NodeId) -> String {
print::to_string(self, |s| s.print_node(self.get(id)))
}
}
pub struct NodesMatchingSuffix<'a, 'ast:'a> {
@ -934,33 +984,47 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
}
}
/// Used for items loaded from external crate that are being inlined into this
/// Used for bodies loaded from external crate that are being inlined into this
/// crate.
pub fn map_decoded_item<'ast>(map: &Map<'ast>,
ii: InlinedItem,
ii_parent_id: NodeId)
-> &'ast InlinedItem {
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(ii);
let ii = map.forest.inlined_items.alloc(InlinedItem {
def_id: def_id,
body: body
});
let mut collector = NodeCollector::extend(map.krate(),
ii,
ii_parent_id,
parent_id,
mem::replace(&mut *map.map.borrow_mut(), vec![]));
ii.visit(&mut collector);
collector.visit_body(&ii.body);
*map.map.borrow_mut() = collector.map;
ii
&ii.body
}
pub trait NodePrinter {
fn print_node(&mut self, node: &Node) -> io::Result<()>;
/// 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> {
fn nested(&self, state: &mut print::State, nested: print::Nested) -> io::Result<()> {
match nested {
Nested::Item(id) => state.print_item(self.expect_item(id.id)),
Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
Nested::Body(id) => state.print_expr(&self.body(id).value),
Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
}
}
}
impl<'a> NodePrinter for pprust::State<'a> {
fn print_node(&mut self, node: &Node) -> io::Result<()> {
match *node {
impl<'a> print::State<'a> {
pub fn print_node(&mut self, node: Node) -> io::Result<()> {
match node {
NodeItem(a) => self.print_item(&a),
NodeForeignItem(a) => self.print_foreign_item(&a),
NodeTraitItem(a) => self.print_trait_item(a),
@ -970,8 +1034,17 @@ impl<'a> NodePrinter for pprust::State<'a> {
NodeStmt(a) => self.print_stmt(&a),
NodeTy(a) => self.print_type(&a),
NodeTraitRef(a) => self.print_trait_ref(&a),
NodeLocal(a) |
NodePat(a) => self.print_pat(&a),
NodeBlock(a) => self.print_block(&a),
NodeBlock(a) => {
use syntax::print::pprust::PrintState;
// containing cbox, will be closed by print-block at }
self.cbox(print::indent_unit)?;
// head-ibox, will be closed by print-block after {
self.ibox(0)?;
self.print_block(&a)
}
NodeLifetime(a) => self.print_lifetime(&a),
NodeVisibility(a) => self.print_visibility(&a),
NodeTyParam(_) => bug!("cannot print TyParam"),
@ -979,10 +1052,7 @@ impl<'a> NodePrinter for pprust::State<'a> {
// these cases do not carry enough information in the
// ast_map to reconstruct their full structure for pretty
// printing.
NodeLocal(_) => bug!("cannot print isolated Local"),
NodeStructCtor(_) => bug!("cannot print isolated StructCtor"),
NodeInlinedItem(_) => bug!("cannot print inlined item"),
}
}
}
@ -1045,9 +1115,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
}
Some(NodeTraitItem(ti)) => {
let kind = match ti.node {
ConstTraitItem(..) => "assoc constant",
MethodTraitItem(..) => "trait method",
TypeTraitItem(..) => "assoc type",
TraitItemKind::Const(..) => "assoc constant",
TraitItemKind::Method(..) => "trait method",
TraitItemKind::Type(..) => "assoc type",
};
format!("{} {} in {}{}", kind, ti.name, path_str(), id_str)
@ -1062,33 +1132,32 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
field.name,
path_str(), id_str)
}
Some(NodeExpr(ref expr)) => {
format!("expr {}{}", pprust::expr_to_string(&expr), id_str)
Some(NodeExpr(_)) => {
format!("expr {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeStmt(ref stmt)) => {
format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
Some(NodeStmt(_)) => {
format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeTy(ref ty)) => {
format!("type {}{}", pprust::ty_to_string(&ty), id_str)
Some(NodeTy(_)) => {
format!("type {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeTraitRef(ref tr)) => {
format!("trait_ref {}{}", pprust::path_to_string(&tr.path), id_str)
Some(NodeTraitRef(_)) => {
format!("trait_ref {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeLocal(ref pat)) => {
format!("local {}{}", pprust::pat_to_string(&pat), id_str)
Some(NodeLocal(_)) => {
format!("local {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodePat(ref pat)) => {
format!("pat {}{}", pprust::pat_to_string(&pat), id_str)
Some(NodePat(_)) => {
format!("pat {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeBlock(ref block)) => {
format!("block {}{}", pprust::block_to_string(&block), id_str)
Some(NodeBlock(_)) => {
format!("block {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeStructCtor(_)) => {
format!("struct_ctor {}{}", path_str(), id_str)
}
Some(NodeLifetime(ref l)) => {
format!("lifetime {}{}",
pprust::lifetime_to_string(&l), id_str)
Some(NodeLifetime(_)) => {
format!("lifetime {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeTyParam(ref ty_param)) => {
format!("typaram {:?}{}", ty_param, id_str)
@ -1096,9 +1165,6 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
Some(NodeVisibility(ref vis)) => {
format!("visibility {:?}{}", vis, id_str)
}
Some(NodeInlinedItem(_)) => {
format!("inlined item {}", id_str)
}
None => {
format!("unknown node{}", id_str)
}

View file

@ -22,7 +22,6 @@ pub use self::Item_::*;
pub use self::Mutability::*;
pub use self::PrimTy::*;
pub use self::Stmt_::*;
pub use self::TraitItem_::*;
pub use self::Ty_::*;
pub use self::TyParamBound::*;
pub use self::UnOp::*;
@ -32,11 +31,10 @@ pub use self::PathParameters::*;
use hir::def::Def;
use hir::def_id::DefId;
use util::nodemap::{NodeMap, FxHashSet};
use rustc_data_structures::fnv::FnvHashMap;
use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
use syntax::codemap::{self, respan, Spanned};
use syntax_pos::{Span, ExpnId, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
@ -87,7 +85,7 @@ impl fmt::Debug for Lifetime {
write!(f,
"lifetime({}: {})",
self.id,
print::lifetime_to_string(self))
print::to_string(print::NO_ANN, |s| s.print_lifetime(self)))
}
}
@ -119,13 +117,8 @@ impl Path {
impl fmt::Debug for Path {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "path({})", print::path_to_string(self))
}
}
impl fmt::Display for Path {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", print::path_to_string(self))
write!(f, "path({})",
print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
}
}
@ -431,8 +424,9 @@ pub struct Crate {
// slightly different results.
pub items: BTreeMap<NodeId, Item>,
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
pub exprs: FnvHashMap<ExprId, Expr>,
pub bodies: FxHashMap<BodyId, Body>,
}
impl Crate {
@ -440,6 +434,10 @@ impl Crate {
&self.items[&id]
}
pub fn trait_item(&self, id: TraitItemId) -> &TraitItem {
&self.trait_items[&id]
}
pub fn impl_item(&self, id: ImplItemId) -> &ImplItem {
&self.impl_items[&id]
}
@ -459,13 +457,17 @@ impl Crate {
visitor.visit_item(item);
}
for (_, trait_item) in &self.trait_items {
visitor.visit_trait_item(trait_item);
}
for (_, impl_item) in &self.impl_items {
visitor.visit_impl_item(impl_item);
}
}
pub fn expr(&self, id: ExprId) -> &Expr {
&self.exprs[&id]
pub fn body(&self, id: BodyId) -> &Body {
&self.bodies[&id]
}
}
@ -503,7 +505,8 @@ pub struct Pat {
impl fmt::Debug for Pat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pat({}: {})", self.id, print::pat_to_string(self))
write!(f, "pat({}: {})", self.id,
print::to_string(print::NO_ANN, |s| s.print_pat(self)))
}
}
@ -755,7 +758,7 @@ impl fmt::Debug for Stmt_ {
write!(f,
"stmt({}: {})",
spanned.node.id(),
print::stmt_to_string(&spanned))
print::to_string(print::NO_ANN, |s| s.print_stmt(&spanned)))
}
}
@ -853,12 +856,23 @@ pub enum UnsafeSource {
UserProvided,
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ExprId(NodeId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct BodyId {
pub node_id: NodeId,
}
impl ExprId {
pub fn node_id(self) -> NodeId {
self.0
/// The body of a function or constant value.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Body {
pub arguments: HirVec<Arg>,
pub value: Expr
}
impl Body {
pub fn id(&self) -> BodyId {
BodyId {
node_id: self.value.id
}
}
}
@ -871,15 +885,10 @@ pub struct Expr {
pub attrs: ThinVec<Attribute>,
}
impl Expr {
pub fn expr_id(&self) -> ExprId {
ExprId(self.id)
}
}
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "expr({}: {})", self.id, print::expr_to_string(self))
write!(f, "expr({}: {})", self.id,
print::to_string(print::NO_ANN, |s| s.print_expr(self)))
}
}
@ -936,7 +945,7 @@ pub enum Expr_ {
/// A closure (for example, `move |a, b, c| {a + b + c}`).
///
/// The final span is the span of the argument block `|...|`
ExprClosure(CaptureClause, P<FnDecl>, ExprId, Span),
ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span),
/// A block (`{ ... }`)
ExprBlock(P<Block>),
@ -980,7 +989,7 @@ pub enum Expr_ {
///
/// For example, `[1; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
ExprRepeat(P<Expr>, P<Expr>),
ExprRepeat(P<Expr>, BodyId),
}
/// Optionally `Self`-qualified value/type path or associated extension.
@ -1003,12 +1012,6 @@ pub enum QPath {
TypeRelative(P<Ty>, P<PathSegment>)
}
impl fmt::Display for QPath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", print::qpath_to_string(self))
}
}
/// Hints at the original code for a `match _ { .. }`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum MatchSource {
@ -1070,6 +1073,14 @@ pub struct MethodSig {
pub generics: Generics,
}
// The bodies for items are stored "out of line", in a separate
// hashmap in the `Crate`. Here we just record the node-id of the item
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TraitItemId {
pub node_id: NodeId,
}
/// Represents an item declaration within a trait declaration,
/// possibly including a default implementation. A trait item is
/// either required (meaning it doesn't have an implementation, just a
@ -1079,21 +1090,31 @@ pub struct TraitItem {
pub id: NodeId,
pub name: Name,
pub attrs: HirVec<Attribute>,
pub node: TraitItem_,
pub node: TraitItemKind,
pub span: Span,
}
/// A trait method's body (or just argument names).
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum TraitMethod {
/// No default body in the trait, just a signature.
Required(HirVec<Spanned<Name>>),
/// Both signature and body are provided in the trait.
Provided(BodyId),
}
/// Represents a trait method or associated constant or type
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum TraitItem_ {
pub enum TraitItemKind {
/// An associated constant with an optional value (otherwise `impl`s
/// must contain a value)
ConstTraitItem(P<Ty>, Option<P<Expr>>),
Const(P<Ty>, Option<BodyId>),
/// A method with an optional body
MethodTraitItem(MethodSig, Option<ExprId>),
Method(MethodSig, TraitMethod),
/// An associated type with (possibly empty) bounds and optional concrete
/// type
TypeTraitItem(TyParamBounds, Option<P<Ty>>),
Type(TyParamBounds, Option<P<Ty>>),
}
// The bodies for items are stored "out of line", in a separate
@ -1121,9 +1142,9 @@ pub struct ImplItem {
pub enum ImplItemKind {
/// An associated constant of the given type, set to the constant result
/// of the expression
Const(P<Ty>, P<Expr>),
Const(P<Ty>, BodyId),
/// A method implementation with the given signature and body
Method(MethodSig, ExprId),
Method(MethodSig, BodyId),
/// An associated type
Type(P<Ty>),
}
@ -1147,7 +1168,8 @@ pub struct Ty {
impl fmt::Debug for Ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "type({})", print::ty_to_string(self))
write!(f, "type({})",
print::to_string(print::NO_ANN, |s| s.print_type(self)))
}
}
@ -1176,7 +1198,7 @@ pub enum Ty_ {
/// A variable length slice (`[T]`)
TySlice(P<Ty>),
/// A fixed length array (`[T; n]`)
TyArray(P<Ty>, P<Expr>),
TyArray(P<Ty>, BodyId),
/// A raw pointer (`*const T` or `*mut T`)
TyPtr(MutTy),
/// A reference (`&'a T` or `&'a mut T`)
@ -1200,7 +1222,7 @@ pub enum Ty_ {
/// An `impl TraitA+TraitB` type.
TyImplTrait(TyParamBounds),
/// Unused for now
TyTypeof(P<Expr>),
TyTypeof(BodyId),
/// TyInfer means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
TyInfer,
@ -1229,67 +1251,18 @@ pub struct InlineAsm {
/// represents an argument in a function header
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Arg {
pub ty: P<Ty>,
pub pat: P<Pat>,
pub id: NodeId,
}
/// Alternative representation for `Arg`s describing `self` parameter of methods.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum SelfKind {
/// `self`, `mut self`
Value(Mutability),
/// `&'lt self`, `&'lt mut self`
Region(Option<Lifetime>, Mutability),
/// `self: TYPE`, `mut self: TYPE`
Explicit(P<Ty>, Mutability),
}
pub type ExplicitSelf = Spanned<SelfKind>;
impl Arg {
pub fn to_self(&self) -> Option<ExplicitSelf> {
if let PatKind::Binding(BindByValue(mutbl), _, name, _) = self.pat.node {
if name.node == keywords::SelfValue.name() {
return match self.ty.node {
TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
}
_ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
SelfKind::Explicit(self.ty.clone(), mutbl)))
}
}
}
None
}
pub fn is_self(&self) -> bool {
if let PatKind::Binding(_, _, name, _) = self.pat.node {
name.node == keywords::SelfValue.name()
} else {
false
}
}
}
/// Represents the header (not the body) of a function declaration
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct FnDecl {
pub inputs: HirVec<Arg>,
pub inputs: HirVec<P<Ty>>,
pub output: FunctionRetTy,
pub variadic: bool,
}
impl FnDecl {
pub fn get_self(&self) -> Option<ExplicitSelf> {
self.inputs.get(0).and_then(Arg::to_self)
}
pub fn has_self(&self) -> bool {
self.inputs.get(0).map(Arg::is_self).unwrap_or(false)
}
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Unsafety {
Unsafe,
@ -1403,7 +1376,7 @@ pub struct Variant_ {
pub attrs: HirVec<Attribute>,
pub data: VariantData,
/// Explicit discriminant, eg `Foo = 1`
pub disr_expr: Option<P<Expr>>,
pub disr_expr: Option<BodyId>,
}
pub type Variant = Spanned<Variant_>;
@ -1562,11 +1535,11 @@ pub enum Item_ {
ItemUse(P<Path>, UseKind),
/// A `static` item
ItemStatic(P<Ty>, Mutability, P<Expr>),
ItemStatic(P<Ty>, Mutability, BodyId),
/// A `const` item
ItemConst(P<Ty>, P<Expr>),
ItemConst(P<Ty>, BodyId),
/// A function declaration
ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, ExprId),
ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, BodyId),
/// A module
ItemMod(Mod),
/// An external module
@ -1580,7 +1553,7 @@ pub enum Item_ {
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
ItemUnion(VariantData, Generics),
/// Represents a Trait Declaration
ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
// Default trait implementations
///
@ -1616,6 +1589,21 @@ impl Item_ {
}
}
/// A reference from an trait to one of its associated items. This
/// contains the item's id, naturally, but also the item's name and
/// some other high-level details (like whether it is an associated
/// type or method, and whether it is public). This allows other
/// passes to find the impl they want without loading the id (which
/// means fewer edges in the incremental compilation graph).
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TraitItemRef {
pub id: TraitItemId,
pub name: Name,
pub kind: AssociatedItemKind,
pub span: Span,
pub defaultness: Defaultness,
}
/// A reference from an impl to one of its associated items. This
/// contains the item's id, naturally, but also the item's name and
/// some other high-level details (like whether it is an associated
@ -1653,7 +1641,7 @@ pub struct ForeignItem {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum ForeignItem_ {
/// A foreign function
ForeignItemFn(P<FnDecl>, Generics),
ForeignItemFn(P<FnDecl>, HirVec<Spanned<Name>>, Generics),
/// A foreign static item (`static ext: u8`), with optional mutability
/// (the boolean is true when mutable)
ForeignItemStatic(P<Ty>, bool),

View file

@ -13,7 +13,6 @@ pub use self::AnnNode::*;
use syntax::abi::Abi;
use syntax::ast;
use syntax::codemap::{CodeMap, Spanned};
use syntax::parse::token::{self, BinOpToken};
use syntax::parse::lexer::comments;
use syntax::print::pp::{self, break_offset, word, space, hardbreak};
use syntax::print::pp::{Breaks, eof};
@ -25,7 +24,7 @@ use syntax_pos::{self, BytePos};
use errors;
use hir;
use hir::{Crate, PatKind, RegionTyParamBound, SelfKind, TraitTyParamBound, TraitBoundModifier};
use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use std::io::{self, Write, Read};
@ -38,7 +37,18 @@ pub enum AnnNode<'a> {
NodePat(&'a hir::Pat),
}
pub enum Nested {
Item(hir::ItemId),
TraitItem(hir::TraitItemId),
ImplItem(hir::ImplItemId),
Body(hir::BodyId),
BodyArgPat(hir::BodyId, usize)
}
pub trait PpAnn {
fn nested(&self, _state: &mut State, _nested: Nested) -> io::Result<()> {
Ok(())
}
fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
Ok(())
}
@ -47,14 +57,23 @@ pub trait PpAnn {
}
}
#[derive(Copy, Clone)]
pub struct NoAnn;
impl PpAnn for NoAnn {}
pub const NO_ANN: &'static PpAnn = &NoAnn;
impl PpAnn for hir::Crate {
fn nested(&self, state: &mut State, nested: Nested) -> io::Result<()> {
match nested {
Nested::Item(id) => state.print_item(self.item(id.id)),
Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
Nested::Body(id) => state.print_expr(&self.body(id).value),
Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
}
}
}
pub struct State<'a> {
krate: Option<&'a Crate>,
pub s: pp::Printer<'a>,
cm: Option<&'a CodeMap>,
comments: Option<Vec<comments::Comment>>,
@ -86,30 +105,6 @@ impl<'a> PrintState<'a> for State<'a> {
}
}
pub fn rust_printer<'a>(writer: Box<Write + 'a>, krate: Option<&'a Crate>) -> State<'a> {
static NO_ANN: NoAnn = NoAnn;
rust_printer_annotated(writer, &NO_ANN, krate)
}
pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>,
ann: &'a PpAnn,
krate: Option<&'a Crate>)
-> State<'a> {
State {
krate: krate,
s: pp::mk_printer(writer, default_columns),
cm: None,
comments: None,
literals: None,
cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
cur_cmnt: 0,
cur_lit: 0,
},
boxes: Vec::new(),
ann: ann,
}
}
#[allow(non_upper_case_globals)]
pub const indent_unit: usize = 4;
@ -130,7 +125,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
is_expanded: bool)
-> io::Result<()> {
let mut s = State::new_from_input(cm, span_diagnostic, filename, input,
out, ann, is_expanded, Some(krate));
out, ann, is_expanded);
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
@ -147,8 +142,7 @@ impl<'a> State<'a> {
input: &mut Read,
out: Box<Write + 'a>,
ann: &'a PpAnn,
is_expanded: bool,
krate: Option<&'a Crate>)
is_expanded: bool)
-> State<'a> {
let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
filename,
@ -165,19 +159,16 @@ impl<'a> State<'a> {
None
} else {
Some(lits)
},
krate)
})
}
pub fn new(cm: &'a CodeMap,
out: Box<Write + 'a>,
ann: &'a PpAnn,
comments: Option<Vec<comments::Comment>>,
literals: Option<Vec<comments::Literal>>,
krate: Option<&'a Crate>)
literals: Option<Vec<comments::Literal>>)
-> State<'a> {
State {
krate: krate,
s: pp::mk_printer(out, default_columns),
cm: Some(cm),
comments: comments.clone(),
@ -192,144 +183,36 @@ impl<'a> State<'a> {
}
}
pub fn to_string<F>(f: F) -> String
pub fn to_string<F>(ann: &PpAnn, f: F) -> String
where F: FnOnce(&mut State) -> io::Result<()>
{
let mut wr = Vec::new();
{
let mut printer = rust_printer(Box::new(&mut wr), None);
let mut printer = State {
s: pp::mk_printer(Box::new(&mut wr), default_columns),
cm: None,
comments: None,
literals: None,
cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
cur_cmnt: 0,
cur_lit: 0,
},
boxes: Vec::new(),
ann: ann,
};
f(&mut printer).unwrap();
eof(&mut printer.s).unwrap();
}
String::from_utf8(wr).unwrap()
}
pub fn binop_to_string(op: BinOpToken) -> &'static str {
match op {
token::Plus => "+",
token::Minus => "-",
token::Star => "*",
token::Slash => "/",
token::Percent => "%",
token::Caret => "^",
token::And => "&",
token::Or => "|",
token::Shl => "<<",
token::Shr => ">>",
}
}
pub fn ty_to_string(ty: &hir::Ty) -> String {
to_string(|s| s.print_type(ty))
}
pub fn bounds_to_string(bounds: &[hir::TyParamBound]) -> String {
to_string(|s| s.print_bounds("", bounds))
}
pub fn pat_to_string(pat: &hir::Pat) -> String {
to_string(|s| s.print_pat(pat))
}
pub fn arm_to_string(arm: &hir::Arm) -> String {
to_string(|s| s.print_arm(arm))
}
pub fn expr_to_string(e: &hir::Expr) -> String {
to_string(|s| s.print_expr(e))
}
pub fn lifetime_to_string(e: &hir::Lifetime) -> String {
to_string(|s| s.print_lifetime(e))
}
pub fn stmt_to_string(stmt: &hir::Stmt) -> String {
to_string(|s| s.print_stmt(stmt))
}
pub fn item_to_string(i: &hir::Item) -> String {
to_string(|s| s.print_item(i))
}
pub fn impl_item_to_string(i: &hir::ImplItem) -> String {
to_string(|s| s.print_impl_item(i))
}
pub fn trait_item_to_string(i: &hir::TraitItem) -> String {
to_string(|s| s.print_trait_item(i))
}
pub fn generics_to_string(generics: &hir::Generics) -> String {
to_string(|s| s.print_generics(generics))
}
pub fn where_clause_to_string(i: &hir::WhereClause) -> String {
to_string(|s| s.print_where_clause(i))
}
pub fn fn_block_to_string(p: &hir::FnDecl) -> String {
to_string(|s| s.print_fn_block_args(p))
}
pub fn path_to_string(p: &hir::Path) -> String {
to_string(|s| s.print_path(p, false))
}
pub fn qpath_to_string(p: &hir::QPath) -> String {
to_string(|s| s.print_qpath(p, false))
}
pub fn name_to_string(name: ast::Name) -> String {
to_string(|s| s.print_name(name))
}
pub fn fun_to_string(decl: &hir::FnDecl,
unsafety: hir::Unsafety,
constness: hir::Constness,
name: ast::Name,
generics: &hir::Generics)
-> String {
to_string(|s| {
s.head("")?;
s.print_fn(decl,
unsafety,
constness,
Abi::Rust,
Some(name),
generics,
&hir::Inherited)?;
s.end()?; // Close the head box
s.end() // Close the outer box
pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String {
to_string(NO_ANN, |s| {
s.print_visibility(vis)?;
word(&mut s.s, w)
})
}
pub fn block_to_string(blk: &hir::Block) -> String {
to_string(|s| {
// containing cbox, will be closed by print-block at }
s.cbox(indent_unit)?;
// head-ibox, will be closed by print-block after {
s.ibox(0)?;
s.print_block(blk)
})
}
pub fn variant_to_string(var: &hir::Variant) -> String {
to_string(|s| s.print_variant(var))
}
pub fn arg_to_string(arg: &hir::Arg) -> String {
to_string(|s| s.print_arg(arg, false))
}
pub fn visibility_qualified(vis: &hir::Visibility, s: &str) -> String {
match *vis {
hir::Public => format!("pub {}", s),
hir::Visibility::Crate => format!("pub(crate) {}", s),
hir::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s),
hir::Inherited => s.to_string(),
}
}
fn needs_parentheses(expr: &hir::Expr) -> bool {
match expr.node {
hir::ExprAssign(..) |
@ -462,8 +345,8 @@ impl<'a> State<'a> {
pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
self.print_inner_attributes(attrs)?;
for item_id in &_mod.item_ids {
self.print_item_id(item_id)?;
for &item_id in &_mod.item_ids {
self.ann.nested(self, Nested::Item(item_id))?;
}
Ok(())
}
@ -545,16 +428,16 @@ impl<'a> State<'a> {
hir::TyImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
}
hir::TyArray(ref ty, ref v) => {
hir::TyArray(ref ty, v) => {
word(&mut self.s, "[")?;
self.print_type(&ty)?;
word(&mut self.s, "; ")?;
self.print_expr(&v)?;
self.ann.nested(self, Nested::Body(v))?;
word(&mut self.s, "]")?;
}
hir::TyTypeof(ref e) => {
hir::TyTypeof(e) => {
word(&mut self.s, "typeof(")?;
self.print_expr(&e)?;
self.ann.nested(self, Nested::Body(e))?;
word(&mut self.s, ")")?;
}
hir::TyInfer => {
@ -569,7 +452,7 @@ impl<'a> State<'a> {
self.maybe_print_comment(item.span.lo)?;
self.print_outer_attributes(&item.attrs)?;
match item.node {
hir::ForeignItemFn(ref decl, ref generics) => {
hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
self.head("")?;
self.print_fn(decl,
hir::Unsafety::Normal,
@ -577,7 +460,9 @@ impl<'a> State<'a> {
Abi::Rust,
Some(item.name),
generics,
&item.vis)?;
&item.vis,
arg_names,
None)?;
self.end()?; // end head-ibox
word(&mut self.s, ";")?;
self.end() // end the outer fn box
@ -600,7 +485,7 @@ impl<'a> State<'a> {
fn print_associated_const(&mut self,
name: ast::Name,
ty: &hir::Ty,
default: Option<&hir::Expr>,
default: Option<hir::BodyId>,
vis: &hir::Visibility)
-> io::Result<()> {
word(&mut self.s, &visibility_qualified(vis, ""))?;
@ -611,7 +496,7 @@ impl<'a> State<'a> {
if let Some(expr) = default {
space(&mut self.s)?;
self.word_space("=")?;
self.print_expr(expr)?;
self.ann.nested(self, Nested::Body(expr))?;
}
word(&mut self.s, ";")
}
@ -634,25 +519,6 @@ impl<'a> State<'a> {
word(&mut self.s, ";")
}
pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> {
if let Some(krate) = self.krate {
// skip nested items if krate context was not provided
let item = &krate.items[&item_id.id];
self.print_item(item)
} else {
Ok(())
}
}
pub fn print_expr_id(&mut self, expr_id: &hir::ExprId) -> io::Result<()> {
if let Some(krate) = self.krate {
let expr = &krate.exprs[expr_id];
self.print_expr(expr)
} else {
Ok(())
}
}
/// Pretty-print an item
pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
self.hardbreak_if_not_bol()?;
@ -697,7 +563,7 @@ impl<'a> State<'a> {
self.end()?; // end inner head-block
self.end()?; // end outer head-block
}
hir::ItemStatic(ref ty, m, ref expr) => {
hir::ItemStatic(ref ty, m, expr) => {
self.head(&visibility_qualified(&item.vis, "static"))?;
if m == hir::MutMutable {
self.word_space("mut")?;
@ -709,11 +575,11 @@ impl<'a> State<'a> {
self.end()?; // end the head-ibox
self.word_space("=")?;
self.print_expr(&expr)?;
self.ann.nested(self, Nested::Body(expr))?;
word(&mut self.s, ";")?;
self.end()?; // end the outer cbox
}
hir::ItemConst(ref ty, ref expr) => {
hir::ItemConst(ref ty, expr) => {
self.head(&visibility_qualified(&item.vis, "const"))?;
self.print_name(item.name)?;
self.word_space(":")?;
@ -722,11 +588,11 @@ impl<'a> State<'a> {
self.end()?; // end the head-ibox
self.word_space("=")?;
self.print_expr(&expr)?;
self.ann.nested(self, Nested::Body(expr))?;
word(&mut self.s, ";")?;
self.end()?; // end the outer cbox
}
hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
self.head("")?;
self.print_fn(decl,
unsafety,
@ -734,11 +600,13 @@ impl<'a> State<'a> {
abi,
Some(item.name),
typarams,
&item.vis)?;
&item.vis,
&[],
Some(body))?;
word(&mut self.s, " ")?;
self.end()?; // need to close a box
self.end()?; // need to close a box
self.print_expr_id(body)?;
self.ann.nested(self, Nested::Body(body))?;
}
hir::ItemMod(ref _mod) => {
self.head(&visibility_qualified(&item.vis, "mod"))?;
@ -832,7 +700,7 @@ impl<'a> State<'a> {
self.bopen()?;
self.print_inner_attributes(&item.attrs)?;
for impl_item in impl_items {
self.print_impl_item_ref(impl_item)?;
self.ann.nested(self, Nested::ImplItem(impl_item.id))?;
}
self.bclose(item.span)?;
}
@ -858,7 +726,7 @@ impl<'a> State<'a> {
word(&mut self.s, " ")?;
self.bopen()?;
for trait_item in trait_items {
self.print_trait_item(trait_item)?;
self.ann.nested(self, Nested::TraitItem(trait_item.id))?;
}
self.bclose(item.span)?;
}
@ -928,8 +796,11 @@ impl<'a> State<'a> {
match *vis {
hir::Public => self.word_nbsp("pub"),
hir::Visibility::Crate => self.word_nbsp("pub(crate)"),
hir::Visibility::Restricted { ref path, .. } =>
self.word_nbsp(&format!("pub({})", path)),
hir::Visibility::Restricted { ref path, .. } => {
word(&mut self.s, "pub(")?;
self.print_path(path, false)?;
self.word_nbsp(")")
}
hir::Inherited => Ok(()),
}
}
@ -985,19 +856,19 @@ impl<'a> State<'a> {
self.head("")?;
let generics = hir::Generics::empty();
self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
match v.node.disr_expr {
Some(ref d) => {
space(&mut self.s)?;
self.word_space("=")?;
self.print_expr(&d)
}
_ => Ok(()),
if let Some(d) = v.node.disr_expr {
space(&mut self.s)?;
self.word_space("=")?;
self.ann.nested(self, Nested::Body(d))?;
}
Ok(())
}
pub fn print_method_sig(&mut self,
name: ast::Name,
m: &hir::MethodSig,
vis: &hir::Visibility)
vis: &hir::Visibility,
arg_names: &[Spanned<ast::Name>],
body_id: Option<hir::BodyId>)
-> io::Result<()> {
self.print_fn(&m.decl,
m.unsafety,
@ -1005,7 +876,9 @@ impl<'a> State<'a> {
m.abi,
Some(name),
&m.generics,
vis)
vis,
arg_names,
body_id)
}
pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> {
@ -1014,27 +887,22 @@ impl<'a> State<'a> {
self.maybe_print_comment(ti.span.lo)?;
self.print_outer_attributes(&ti.attrs)?;
match ti.node {
hir::ConstTraitItem(ref ty, ref default) => {
self.print_associated_const(ti.name,
&ty,
default.as_ref().map(|expr| &**expr),
&hir::Inherited)?;
hir::TraitItemKind::Const(ref ty, default) => {
self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
}
hir::MethodTraitItem(ref sig, ref body) => {
if body.is_some() {
self.head("")?;
}
self.print_method_sig(ti.name, sig, &hir::Inherited)?;
if let Some(ref body) = *body {
self.nbsp()?;
self.end()?; // need to close a box
self.end()?; // need to close a box
self.print_expr_id(body)?;
} else {
word(&mut self.s, ";")?;
}
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => {
self.print_method_sig(ti.name, sig, &hir::Inherited, arg_names, None)?;
word(&mut self.s, ";")?;
}
hir::TypeTraitItem(ref bounds, ref default) => {
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
self.head("")?;
self.print_method_sig(ti.name, sig, &hir::Inherited, &[], Some(body))?;
self.nbsp()?;
self.end()?; // need to close a box
self.end()?; // need to close a box
self.ann.nested(self, Nested::Body(body))?;
}
hir::TraitItemKind::Type(ref bounds, ref default) => {
self.print_associated_type(ti.name,
Some(bounds),
default.as_ref().map(|ty| &**ty))?;
@ -1043,16 +911,6 @@ impl<'a> State<'a> {
self.ann.post(self, NodeSubItem(ti.id))
}
pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> {
if let Some(krate) = self.krate {
// skip nested items if krate context was not provided
let item = &krate.impl_item(item_ref.id);
self.print_impl_item(item)
} else {
Ok(())
}
}
pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
self.ann.pre(self, NodeSubItem(ii.id))?;
self.hardbreak_if_not_bol()?;
@ -1065,16 +923,16 @@ impl<'a> State<'a> {
}
match ii.node {
hir::ImplItemKind::Const(ref ty, ref expr) => {
self.print_associated_const(ii.name, &ty, Some(&expr), &ii.vis)?;
hir::ImplItemKind::Const(ref ty, expr) => {
self.print_associated_const(ii.name, &ty, Some(expr), &ii.vis)?;
}
hir::ImplItemKind::Method(ref sig, ref body) => {
hir::ImplItemKind::Method(ref sig, body) => {
self.head("")?;
self.print_method_sig(ii.name, sig, &ii.vis)?;
self.print_method_sig(ii.name, sig, &ii.vis, &[], Some(body))?;
self.nbsp()?;
self.end()?; // need to close a box
self.end()?; // need to close a box
self.print_expr_id(body)?;
self.ann.nested(self, Nested::Body(body))?;
}
hir::ImplItemKind::Type(ref ty) => {
self.print_associated_type(ii.name, None, Some(ty))?;
@ -1246,12 +1104,12 @@ impl<'a> State<'a> {
self.end()
}
fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> {
fn print_expr_repeat(&mut self, element: &hir::Expr, count: hir::BodyId) -> io::Result<()> {
self.ibox(indent_unit)?;
word(&mut self.s, "[")?;
self.print_expr(element)?;
self.word_space(";")?;
self.print_expr(count)?;
self.ann.nested(self, Nested::Body(count))?;
word(&mut self.s, "]")?;
self.end()
}
@ -1362,8 +1220,8 @@ impl<'a> State<'a> {
hir::ExprArray(ref exprs) => {
self.print_expr_vec(exprs)?;
}
hir::ExprRepeat(ref element, ref count) => {
self.print_expr_repeat(&element, &count)?;
hir::ExprRepeat(ref element, count) => {
self.print_expr_repeat(&element, count)?;
}
hir::ExprStruct(ref qpath, ref fields, ref wth) => {
self.print_expr_struct(qpath, &fields[..], wth)?;
@ -1434,14 +1292,14 @@ impl<'a> State<'a> {
}
self.bclose_(expr.span, indent_unit)?;
}
hir::ExprClosure(capture_clause, ref decl, ref body, _fn_decl_span) => {
hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => {
self.print_capture_clause(capture_clause)?;
self.print_fn_block_args(&decl)?;
self.print_closure_args(&decl, body)?;
space(&mut self.s)?;
// this is a bare expression
self.print_expr_id(body)?;
self.ann.nested(self, Nested::Body(body))?;
self.end()?; // need to close a box
// a box will be closed by print_expr, but we didn't want an overall
@ -1615,8 +1473,8 @@ impl<'a> State<'a> {
}
self.end()
}
hir::DeclItem(ref item) => {
self.print_item_id(item)
hir::DeclItem(item) => {
self.ann.nested(self, Nested::Item(item))
}
}
}
@ -1637,10 +1495,10 @@ impl<'a> State<'a> {
self.print_expr(coll)
}
fn print_path(&mut self,
path: &hir::Path,
colons_before_params: bool)
-> io::Result<()> {
pub fn print_path(&mut self,
path: &hir::Path,
colons_before_params: bool)
-> io::Result<()> {
self.maybe_print_comment(path.span.lo)?;
for (i, segment) in path.segments.iter().enumerate() {
@ -1656,10 +1514,10 @@ impl<'a> State<'a> {
Ok(())
}
fn print_qpath(&mut self,
qpath: &hir::QPath,
colons_before_params: bool)
-> io::Result<()> {
pub fn print_qpath(&mut self,
qpath: &hir::QPath,
colons_before_params: bool)
-> io::Result<()> {
match *qpath {
hir::QPath::Resolved(None, ref path) => {
self.print_path(path, colons_before_params)
@ -1954,27 +1812,6 @@ impl<'a> State<'a> {
self.end() // close enclosing cbox
}
fn print_explicit_self(&mut self, explicit_self: &hir::ExplicitSelf) -> io::Result<()> {
match explicit_self.node {
SelfKind::Value(m) => {
self.print_mutability(m)?;
word(&mut self.s, "self")
}
SelfKind::Region(ref lt, m) => {
word(&mut self.s, "&")?;
self.print_opt_lifetime(lt)?;
self.print_mutability(m)?;
word(&mut self.s, "self")
}
SelfKind::Explicit(ref typ, m) => {
self.print_mutability(m)?;
word(&mut self.s, "self")?;
self.word_space(":")?;
self.print_type(&typ)
}
}
}
pub fn print_fn(&mut self,
decl: &hir::FnDecl,
unsafety: hir::Unsafety,
@ -1982,7 +1819,9 @@ impl<'a> State<'a> {
abi: Abi,
name: Option<ast::Name>,
generics: &hir::Generics,
vis: &hir::Visibility)
vis: &hir::Visibility,
arg_names: &[Spanned<ast::Name>],
body_id: Option<hir::BodyId>)
-> io::Result<()> {
self.print_fn_header_info(unsafety, constness, abi, vis)?;
@ -1991,24 +1830,51 @@ impl<'a> State<'a> {
self.print_name(name)?;
}
self.print_generics(generics)?;
self.print_fn_args_and_ret(decl)?;
self.print_where_clause(&generics.where_clause)
}
pub fn print_fn_args_and_ret(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
self.popen()?;
self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
let mut i = 0;
// Make sure we aren't supplied *both* `arg_names` and `body_id`.
assert!(arg_names.is_empty() || body_id.is_none());
self.commasep(Inconsistent, &decl.inputs, |s, ty| {
s.ibox(indent_unit)?;
if let Some(name) = arg_names.get(i) {
word(&mut s.s, &name.node.as_str())?;
word(&mut s.s, ":")?;
space(&mut s.s)?;
} else if let Some(body_id) = body_id {
s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
word(&mut s.s, ":")?;
space(&mut s.s)?;
}
i += 1;
s.print_type(ty)?;
s.end()
})?;
if decl.variadic {
word(&mut self.s, ", ...")?;
}
self.pclose()?;
self.print_fn_output(decl)
self.print_fn_output(decl)?;
self.print_where_clause(&generics.where_clause)
}
pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) -> io::Result<()> {
word(&mut self.s, "|")?;
self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
let mut i = 0;
self.commasep(Inconsistent, &decl.inputs, |s, ty| {
s.ibox(indent_unit)?;
s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
i += 1;
if ty.node != hir::TyInfer {
word(&mut s.s, ":")?;
space(&mut s.s)?;
s.print_type(ty)?;
}
s.end()
})?;
word(&mut self.s, "|")?;
if let hir::DefaultReturn(..) = decl.output {
@ -2180,31 +2046,6 @@ impl<'a> State<'a> {
self.print_type(&mt.ty)
}
pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> {
self.ibox(indent_unit)?;
match input.ty.node {
hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
_ => {
if let Some(eself) = input.to_self() {
self.print_explicit_self(&eself)?;
} else {
let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
name.node == keywords::Invalid.name()
} else {
false
};
if !invalid {
self.print_pat(&input.pat)?;
word(&mut self.s, ":")?;
space(&mut self.s)?;
}
self.print_type(&input.ty)?;
}
}
}
self.end()
}
pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
if let hir::DefaultReturn(..) = decl.output {
return Ok(());
@ -2252,7 +2093,9 @@ impl<'a> State<'a> {
abi,
name,
&generics,
&hir::Inherited)?;
&hir::Inherited,
&[],
None)?;
self.end()
}

View file

@ -75,7 +75,6 @@ use std::collections::HashSet;
use hir::map as ast_map;
use hir;
use hir::print as pprust;
use lint;
use hir::def::Def;
@ -1051,8 +1050,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
Some(ref node) => match *node {
ast_map::NodeItem(ref item) => {
match item.node {
hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
Some((fn_decl, gen, unsafety, constness, item.name, item.span))
hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => {
Some((fn_decl, gen, unsafety, constness, item.name, item.span, body))
}
_ => None,
}
@ -1066,26 +1065,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
return;
}
}
if let hir::ImplItemKind::Method(ref sig, _) = item.node {
if let hir::ImplItemKind::Method(ref sig, body) = item.node {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
item.span))
item.span,
body))
} else {
None
}
},
ast_map::NodeTraitItem(item) => {
match item.node {
hir::MethodTraitItem(ref sig, Some(_)) => {
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
item.span))
item.span,
body))
}
_ => None,
}
@ -1094,12 +1095,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
},
None => None,
};
let (fn_decl, generics, unsafety, constness, name, span)
let (fn_decl, generics, unsafety, constness, name, span, body)
= node_inner.expect("expect item fn");
let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
let (fn_decl, generics) = rebuilder.rebuild();
self.give_expl_lifetime_param(
err, &fn_decl, unsafety, constness, name, &generics, span);
err, &fn_decl, unsafety, constness, name, &generics, span, body);
}
pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
@ -1375,23 +1376,14 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
}
fn rebuild_args_ty(&self,
inputs: &[hir::Arg],
inputs: &[P<hir::Ty>],
lifetime: hir::Lifetime,
anon_nums: &HashSet<u32>,
region_names: &HashSet<ast::Name>)
-> hir::HirVec<hir::Arg> {
let mut new_inputs = Vec::new();
for arg in inputs {
let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime,
anon_nums, region_names);
let possibly_new_arg = hir::Arg {
ty: new_ty,
pat: arg.pat.clone(),
id: arg.id
};
new_inputs.push(possibly_new_arg);
}
new_inputs.into()
-> hir::HirVec<P<hir::Ty>> {
inputs.iter().map(|arg_ty| {
self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names)
}).collect()
}
fn rebuild_output(&self, ty: &hir::FunctionRetTy,
@ -1634,10 +1626,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
constness: hir::Constness,
name: ast::Name,
generics: &hir::Generics,
span: Span) {
let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, generics);
let msg = format!("consider using an explicit lifetime \
parameter as shown: {}", suggested_fn);
span: Span,
body: hir::BodyId) {
let s = hir::print::to_string(&self.tcx.map, |s| {
use syntax::abi::Abi;
use syntax::print::pprust::PrintState;
s.head("")?;
s.print_fn(decl,
unsafety,
constness,
Abi::Rust,
Some(name),
generics,
&hir::Inherited,
&[],
Some(body))?;
s.end()?; // Close the head box
s.end() // Close the outer box
});
let msg = format!("consider using an explicit lifetime parameter as shown: {}", s);
err.span_help(span, &msg[..]);
}

View file

@ -33,6 +33,7 @@
#![cfg_attr(stage0, feature(item_like_imports))]
#![feature(libc)]
#![feature(nonzero)]
#![feature(pub_restricted)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
@ -80,9 +81,8 @@ pub mod lint;
pub mod middle {
pub mod astconv_util;
pub mod expr_use_visitor; // STAGE0: increase glitch immunity
pub mod expr_use_visitor;
pub mod const_val;
pub mod const_qualif;
pub mod cstore;
pub mod dataflow;
pub mod dead;

View file

@ -821,6 +821,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
self.with_lint_attrs(&e.attrs, |cx| {
run_lints!(cx, check_expr, late_passes, e);
hir_visit::walk_expr(cx, e);
run_lints!(cx, check_expr_post, late_passes, e);
})
}
@ -835,8 +836,8 @@ 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::ExprId, span: Span, id: ast::NodeId) {
let body = self.tcx.map.expr(body_id);
body_id: hir::BodyId, span: Span, id: ast::NodeId) {
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);
@ -909,10 +910,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
hir_visit::walk_decl(self, d);
}
fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
run_lints!(self, check_expr_post, late_passes, e);
}
fn visit_generics(&mut self, g: &'tcx hir::Generics) {
run_lints!(self, check_generics, late_passes, g);
hir_visit::walk_generics(self, g);

View file

@ -162,14 +162,14 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
_: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
_: &'tcx hir::FnDecl,
_: &'tcx hir::Expr,
_: &'tcx hir::Body,
_: Span,
_: ast::NodeId) { }
fn check_fn_post(&mut self,
_: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
_: &'tcx hir::FnDecl,
_: &'tcx hir::Expr,
_: &'tcx hir::Body,
_: Span,
_: ast::NodeId) { }
fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { }

View file

@ -1,44 +0,0 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Const qualification, from partial to completely promotable.
bitflags! {
#[derive(RustcEncodable, RustcDecodable)]
flags ConstQualif: u8 {
// Inner mutability (can not be placed behind a reference) or behind
// &mut in a non-global expression. Can be copied from static memory.
const MUTABLE_MEM = 1 << 0,
// Constant value with a type that implements Drop. Can be copied
// from static memory, similar to MUTABLE_MEM.
const NEEDS_DROP = 1 << 1,
// Even if the value can be placed in static memory, copying it from
// there is more expensive than in-place instantiation, and/or it may
// be too large. This applies to [T; N] and everything containing it.
// N.B.: references need to clear this flag to not end up on the stack.
const PREFER_IN_PLACE = 1 << 2,
// May use more than 0 bytes of memory, doesn't impact the constness
// directly, but is not allowed to be borrowed mutably in a constant.
const NON_ZERO_SIZED = 1 << 3,
// Actually borrowed, has to always be in static memory. Does not
// propagate, and requires the expression to behave like a 'static
// lvalue. The set of expressions with this flag is the minimum
// that have to be promoted.
const HAS_STATIC_BORROWS = 1 << 4,
// Invalid const for miscellaneous reasons (e.g. not implemented).
const NOT_CONST = 1 << 5,
// Borrowing the expression won't produce &'static T if any of these
// bits are set, though the value could be copied from static memory
// if `NOT_CONST` isn't set.
const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
ConstQualif::NEEDS_DROP.bits |
ConstQualif::NOT_CONST.bits
}
}

View file

@ -33,17 +33,17 @@ use mir::Mir;
use session::Session;
use session::search_paths::PathKind;
use util::nodemap::{NodeSet, DefIdMap};
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::rc::Rc;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::SyntaxExtension;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use rustc_back::target::Target;
use hir;
use hir::intravisit::Visitor;
use rustc_back::PanicStrategy;
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
@ -134,102 +134,6 @@ pub struct NativeLibrary {
pub foreign_items: Vec<DefIndex>,
}
/// 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(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct InlinedItem {
pub def_id: DefId,
pub body: P<hir::Expr>,
pub const_fn_args: Vec<Option<DefId>>,
}
/// A borrowed version of `hir::InlinedItem`. This is what's encoded when saving
/// a crate; it then gets read as an InlinedItem.
#[derive(Clone, PartialEq, Eq, RustcEncodable, Hash, Debug)]
pub struct InlinedItemRef<'a> {
pub def_id: DefId,
pub body: &'a hir::Expr,
pub const_fn_args: Vec<Option<DefId>>,
}
fn get_fn_args(decl: &hir::FnDecl) -> Vec<Option<DefId>> {
decl.inputs.iter().map(|arg| match arg.pat.node {
hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
_ => None
}).collect()
}
impl<'a> InlinedItemRef<'a> {
pub fn from_item<'b, 'tcx>(def_id: DefId,
item: &'a hir::Item,
tcx: TyCtxt<'b, 'a, 'tcx>)
-> InlinedItemRef<'a> {
let (body, args) = match item.node {
hir::ItemFn(ref decl, _, _, _, _, body_id) =>
(tcx.map.expr(body_id), get_fn_args(decl)),
hir::ItemConst(_, ref body) => (&**body, Vec::new()),
_ => bug!("InlinedItemRef::from_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: body,
const_fn_args: args
}
}
pub fn from_trait_item(def_id: DefId,
item: &'a hir::TraitItem,
_tcx: TyCtxt)
-> InlinedItemRef<'a> {
let (body, args) = match item.node {
hir::ConstTraitItem(_, Some(ref body)) =>
(&**body, Vec::new()),
hir::ConstTraitItem(_, None) => {
bug!("InlinedItemRef::from_trait_item called for const without body")
},
_ => bug!("InlinedItemRef::from_trait_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: body,
const_fn_args: args
}
}
pub fn from_impl_item<'b, 'tcx>(def_id: DefId,
item: &'a hir::ImplItem,
tcx: TyCtxt<'b, 'a, 'tcx>)
-> InlinedItemRef<'a> {
let (body, args) = match item.node {
hir::ImplItemKind::Method(ref sig, body_id) =>
(tcx.map.expr(body_id), get_fn_args(&sig.decl)),
hir::ImplItemKind::Const(_, ref body) =>
(&**body, Vec::new()),
_ => bug!("InlinedItemRef::from_impl_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: body,
const_fn_args: args
}
}
pub fn visit<V>(&self, visitor: &mut V)
where V: Visitor<'a>
{
visitor.visit_expr(&self.body);
}
}
impl InlinedItem {
pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
where V: Visitor<'ast>
{
visitor.visit_expr(&self.body);
}
}
pub enum LoadedMacro {
MacroRules(ast::MacroDef),
ProcMacro(Rc<SyntaxExtension>),
@ -346,10 +250,10 @@ pub trait CrateStore<'tcx> {
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
// misc. metadata
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<(&'tcx InlinedItem, ast::NodeId)>;
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<&'tcx hir::Body>;
fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>;
fn is_item_mir_available(&self, def: DefId) -> bool;
@ -516,15 +420,15 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
// misc. metadata
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<(&'tcx InlinedItem, ast::NodeId)> {
bug!("maybe_get_item_ast")
fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<&'tcx hir::Body> {
bug!("maybe_get_item_body")
}
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
bug!("local_node_for_inlined_defid")
fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
bug!("item_body_nested_bodies")
}
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
bug!("defid_for_inlined_node")
fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
bug!("const_is_rvalue_promotable_to_static")
}
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)

View file

@ -108,6 +108,9 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
}
impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
fn nested(&self, state: &mut pprust::State, nested: pprust::Nested) -> io::Result<()> {
pprust::PpAnn::nested(&self.tcx.map, state, nested)
}
fn pre(&self,
ps: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> {
@ -160,7 +163,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
}
}
fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
fn build_nodeid_to_index(body: Option<&hir::Body>,
cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
let mut index = NodeMap();
@ -168,8 +171,8 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
// into cfg itself? i.e. introduce a fn-based flow-graph in
// addition to the current block-based flow-graph, rather than
// have to put traversals like this here?
if let Some(decl) = decl {
add_entries_from_fn_decl(&mut index, decl, cfg.entry);
if let Some(body) = body {
add_entries_from_fn_body(&mut index, body, cfg.entry);
}
cfg.graph.each_node(|node_idx, node| {
@ -181,20 +184,24 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
return index;
fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
decl: &hir::FnDecl,
/// Add mappings from the ast nodes for the formal bindings to
/// the entry-node in the graph.
fn add_entries_from_fn_body(index: &mut NodeMap<Vec<CFGIndex>>,
body: &hir::Body,
entry: CFGIndex) {
//! add mappings from the ast nodes for the formal bindings to
//! the entry-node in the graph.
use hir::intravisit::Visitor;
struct Formals<'a> {
entry: CFGIndex,
index: &'a mut NodeMap<Vec<CFGIndex>>,
}
let mut formals = Formals { entry: entry, index: index };
intravisit::walk_fn_decl(&mut formals, decl);
impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
for arg in &body.arguments {
formals.visit_pat(&arg.pat);
}
impl<'a, 'v> Visitor<'v> for Formals<'a> {
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
panic!("should not encounter fn bodies or items")
intravisit::NestedVisitorMap::None
}
fn visit_pat(&mut self, p: &hir::Pat) {
@ -227,7 +234,7 @@ pub enum KillFrom {
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis_name: &'static str,
decl: Option<&hir::FnDecl>,
body: Option<&hir::Body>,
cfg: &cfg::CFG,
oper: O,
id_range: IdRange,
@ -250,7 +257,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
let kills2 = zeroes;
let on_entry = vec![entry; num_nodes * words_per_id];
let nodeid_to_index = build_nodeid_to_index(decl, cfg);
let nodeid_to_index = build_nodeid_to_index(body, cfg);
DataFlowContext {
tcx: tcx,
@ -502,7 +509,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
// ^^^^^^^^^^^^^ only needed for pretty printing
pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) {
pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
//! Performs the data flow analysis.
if self.bits_per_id == 0 {
@ -526,20 +533,11 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
}
debug!("Dataflow result for {}:", self.analysis_name);
debug!("{}", {
let mut v = Vec::new();
self.pretty_print_to(box &mut v, body).unwrap();
String::from_utf8(v).unwrap()
});
}
fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
body: &hir::Expr) -> io::Result<()> {
let mut ps = pprust::rust_printer_annotated(wr, self, None);
ps.cbox(pprust::indent_unit)?;
ps.ibox(0)?;
ps.print_expr(body)?;
pp::eof(&mut ps.s)
debug!("{}", pprust::to_string(self, |s| {
s.cbox(pprust::indent_unit)?;
s.ibox(0)?;
s.print_expr(&body.value)
}));
}
}

View file

@ -328,11 +328,12 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
self.worklist.extend(enum_def.variants.iter()
.map(|variant| variant.node.data.id()));
}
hir::ItemTrait(.., ref trait_items) => {
for trait_item in trait_items {
hir::ItemTrait(.., ref trait_item_refs) => {
for trait_item_ref in trait_item_refs {
let trait_item = self.krate.trait_item(trait_item_ref.id);
match trait_item.node {
hir::ConstTraitItem(_, Some(_)) |
hir::MethodTraitItem(_, Some(_)) => {
hir::TraitItemKind::Const(_, Some(_)) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
self.worklist.push(trait_item.id);
}
@ -354,6 +355,10 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
}
}
fn visit_trait_item(&mut self, _item: &hir::TraitItem) {
// ignore: we are handling this in `visit_item` above
}
fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
// ignore: we are handling this in `visit_item` above
}
@ -546,19 +551,19 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node {
hir::ImplItemKind::Const(_, ref expr) => {
hir::ImplItemKind::Const(_, body_id) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.name, "associated const");
}
intravisit::walk_expr(self, expr)
self.visit_nested_body(body_id)
}
hir::ImplItemKind::Method(_, body_id) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.name, "method");
}
self.visit_body(body_id)
self.visit_nested_body(body_id)
}
hir::ImplItemKind::Type(..) => {}
}
@ -567,15 +572,13 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
// Overwrite so that we don't warn the trait item itself.
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node {
hir::ConstTraitItem(_, Some(ref body)) => {
intravisit::walk_expr(self, body)
hir::TraitItemKind::Const(_, Some(body_id)) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
self.visit_nested_body(body_id)
}
hir::MethodTraitItem(_, Some(body_id)) => {
self.visit_body(body_id)
}
hir::ConstTraitItem(_, None) |
hir::MethodTraitItem(_, None) |
hir::TypeTraitItem(..) => {}
hir::TraitItemKind::Const(_, None) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
hir::TraitItemKind::Type(..) => {}
}
}
}

View file

@ -98,7 +98,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
}
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
body_id: hir::ExprId, span: Span, id: ast::NodeId) {
body_id: hir::BodyId, span: Span, id: ast::NodeId) {
let (is_item_fn, is_unsafe_fn) = match fn_kind {
FnKind::ItemFn(_, _, unsafety, ..) =>

View file

@ -17,7 +17,7 @@ use syntax::ast::NodeId;
use syntax::attr;
use syntax::entry::EntryPointType;
use syntax_pos::Span;
use hir::{Item, ItemFn, ImplItem};
use hir::{Item, ItemFn, ImplItem, TraitItem};
use hir::itemlikevisit::ItemLikeVisitor;
struct EntryContext<'a, 'tcx: 'a> {
@ -47,6 +47,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
find_item(item, self, at_root);
}
fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) {
// entry fn is never a trait item
}
fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
// entry fn is never an impl item

View file

@ -287,20 +287,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
}
pub fn walk_fn(&mut self,
decl: &hir::FnDecl,
body: &hir::Expr) {
self.walk_arg_patterns(decl, body);
self.consume_expr(body);
}
fn walk_arg_patterns(&mut self,
decl: &hir::FnDecl,
body: &hir::Expr) {
for arg in &decl.inputs {
pub fn consume_body(&mut self, body: &hir::Body) {
for arg in &body.arguments {
let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
let fn_body_scope_r = self.tcx().node_scope_region(body.id);
let fn_body_scope_r = self.tcx().node_scope_region(body.value.id);
let arg_cmt = self.mc.cat_rvalue(
arg.id,
arg.pat.span,
@ -309,6 +300,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
self.walk_irrefutable_pat(arg_cmt, &arg.pat);
}
self.consume_expr(&body.value);
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@ -537,9 +530,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
}
hir::ExprRepeat(ref base, ref count) => {
hir::ExprRepeat(ref base, _) => {
self.consume_expr(&base);
self.consume_expr(&count);
}
hir::ExprClosure(.., fn_decl_span) => {

View file

@ -34,13 +34,13 @@ struct ItemVisitor<'a, 'tcx: 'a> {
}
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
fn visit_const(&mut self, item_id: ast::NodeId, expr: &'tcx hir::Expr) {
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_expr(expr);
visitor.visit_nested_body(body);
});
}
}
@ -122,33 +122,33 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
}
// const, static and N in [T; N].
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
fn visit_body(&mut self, body: &'tcx hir::Body) {
self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_expr(expr);
visitor.visit_body(body);
});
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
self.visit_const(item.id, expr);
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(_, ref expr) = item.node {
self.visit_const(item.id, expr);
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::ExprId, s: Span, id: ast::NodeId) {
b: hir::BodyId, s: Span, id: ast::NodeId) {
if let FnKind::Closure(..) = fk {
span_bug!(s, "intrinsicck: closure outside of function")
}

View file

@ -140,6 +140,10 @@ impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
// at present, lang items are always items, not trait items
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// at present, lang items are always items, not impl items
}

View file

@ -127,7 +127,6 @@ use syntax_pos::Span;
use hir::Expr;
use hir;
use hir::print::{expr_to_string, block_to_string};
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
/// For use with `propagate_through_loop`.
@ -188,7 +187,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
b: hir::ExprId, s: Span, id: NodeId) {
b: hir::BodyId, s: Span, id: NodeId) {
visit_fn(self, fk, fd, b, s, id);
}
fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
@ -354,13 +353,9 @@ 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::OnlyBodies(&self.ir.tcx.map)
NestedVisitorMap::None
}
fn visit_fn(&mut self, _: FnKind<'tcx>, _: &'tcx hir::FnDecl,
_: hir::ExprId, _: Span, _: NodeId) {
// do not check contents of nested fns
}
fn visit_local(&mut self, l: &'tcx hir::Local) {
check_local(self, l);
}
@ -375,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
body_id: hir::ExprId,
body_id: hir::BodyId,
sp: Span,
id: ast::NodeId) {
debug!("visit_fn");
@ -385,7 +380,9 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps);
for arg in &decl.inputs {
let body = ir.tcx.map.body(body_id);
for arg in &body.arguments {
arg.pat.each_binding(|_bm, arg_id, _x, path1| {
debug!("adding argument {}", arg_id);
let name = path1.node;
@ -408,16 +405,14 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
clean_exit_var: fn_maps.add_variable(CleanExit)
};
let body = ir.tcx.map.expr(body_id);
// compute liveness
let mut lsets = Liveness::new(&mut fn_maps, specials);
let entry_ln = lsets.compute(body);
let entry_ln = lsets.compute(&body.value);
// check for various error conditions
lsets.visit_expr(body);
lsets.visit_body(body);
lsets.check_ret(id, sp, fk, entry_ln, body);
lsets.warn_about_unused_args(decl, entry_ln);
lsets.warn_about_unused_args(body, entry_ln);
}
fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
@ -823,7 +818,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// effectively a return---this only occurs in `for` loops,
// where the body is really a closure.
debug!("compute: using id for body, {}", expr_to_string(body));
debug!("compute: using id for body, {}", self.ir.tcx.map.node_to_pretty_string(body.id));
let exit_ln = self.s.exit_ln;
let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| {
@ -916,7 +911,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
-> LiveNode {
debug!("propagate_through_expr: {}", expr_to_string(expr));
debug!("propagate_through_expr: {}", self.ir.tcx.map.node_to_pretty_string(expr.id));
match expr.node {
// Interesting cases with control flow or which gen/kill
@ -935,14 +930,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprClosure(.., blk_id, _) => {
debug!("{} is an ExprClosure",
expr_to_string(expr));
self.ir.tcx.map.node_to_pretty_string(expr.id));
/*
The next-node for a break is the successor of the entire
loop. The next-node for a continue is the top of this loop.
*/
let node = self.live_node(expr.id, expr.span);
self.with_loop_nodes(blk_id.node_id(), succ, node, |this| {
self.with_loop_nodes(blk_id.node_id, succ, node, |this| {
// the construction of a closure itself is not important,
// but we have to consider the closed over variables.
@ -1088,11 +1083,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_exprs(exprs, succ)
}
hir::ExprRepeat(ref element, ref count) => {
let succ = self.propagate_through_expr(&count, succ);
self.propagate_through_expr(&element, succ)
}
hir::ExprStruct(_, ref fields, ref with_expr) => {
let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
fields.iter().rev().fold(succ, |succ, field| {
@ -1149,7 +1139,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprAddrOf(_, ref e) |
hir::ExprCast(ref e, _) |
hir::ExprType(ref e, _) |
hir::ExprUnary(_, ref e) => {
hir::ExprUnary(_, ref e) |
hir::ExprRepeat(ref e, _) => {
self.propagate_through_expr(&e, succ)
}
@ -1315,7 +1306,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
}
debug!("propagate_through_loop: using id for loop body {} {}",
expr.id, block_to_string(body));
expr.id, self.ir.tcx.map.node_to_pretty_string(body.id));
let cond_ln = match kind {
LoopLoop => ln,
@ -1443,7 +1434,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
sp: Span,
fk: FnKind,
entry_ln: LiveNode,
body: &hir::Expr)
body: &hir::Body)
{
let fn_ty = if let FnKind::Closure(_) = fk {
self.ir.tcx.tables().node_id_to_type(id)
@ -1460,7 +1451,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// and must outlive the *call-site* of the function.
let fn_ret =
self.ir.tcx.liberate_late_bound_regions(
self.ir.tcx.region_maps.call_site_extent(id, body.id),
self.ir.tcx.region_maps.call_site_extent(id, body.value.id),
&fn_ret);
if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
@ -1510,8 +1501,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
}
fn warn_about_unused_args(&self, decl: &hir::FnDecl, entry_ln: LiveNode) {
for arg in &decl.inputs {
fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
for arg in &body.arguments {
arg.pat.each_binding(|_bm, p_id, sp, path1| {
let var = self.variable(p_id, sp);
// Ignore unused self.

View file

@ -73,7 +73,6 @@ use self::Aliasability::*;
use hir::def_id::DefId;
use hir::map as ast_map;
use infer::InferCtxt;
use middle::const_qualif::ConstQualif;
use hir::def::{Def, CtorKind};
use ty::adjustment;
use ty::{self, Ty, TyCtxt};
@ -705,7 +704,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
};
match fn_expr.node {
hir::ExprClosure(.., body_id, _) => body_id.node_id(),
hir::ExprClosure(.., body_id, _) => body_id.node_id,
_ => bug!()
}
};
@ -773,23 +772,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
span: Span,
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
.unwrap_or(ConstQualif::NOT_CONST);
let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned()
.unwrap_or(false);
// Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted.
let qualif = match expr_ty.sty {
ty::TyArray(_, 0) => qualif,
_ => ConstQualif::NOT_CONST
let promotable = match expr_ty.sty {
ty::TyArray(_, 0) => true,
_ => promotable & false
};
// 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 qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.temporary_scope(id)
} else {
let re = if promotable {
self.tcx().mk_region(ty::ReStatic)
} else {
self.temporary_scope(id)
};
let ret = self.cat_rvalue(id, span, re, expr_ty);
debug!("cat_rvalue_node ret {:?}", ret);

View file

@ -166,9 +166,10 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
}
Some(ast_map::NodeTraitItem(trait_method)) => {
match trait_method.node {
hir::ConstTraitItem(_, ref default) => default.is_some(),
hir::MethodTraitItem(_, ref body) => body.is_some(),
hir::TypeTraitItem(..) => false,
hir::TraitItemKind::Const(_, ref default) => default.is_some(),
hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
hir::TraitItemKind::Type(..) => false,
}
}
Some(ast_map::NodeImplItem(impl_item)) => {
@ -250,15 +251,15 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
match item.node {
hir::ItemFn(.., body) => {
if item_might_be_inlined(&item) {
self.visit_body(body);
self.visit_nested_body(body);
}
}
// Reachable constants will be inlined into other crates
// unconditionally, so we need to make sure that their
// contents are also reachable.
hir::ItemConst(_, ref init) => {
self.visit_expr(&init);
hir::ItemConst(_, init) => {
self.visit_nested_body(init);
}
// These are normal, nothing reachable about these
@ -274,28 +275,26 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
}
ast_map::NodeTraitItem(trait_method) => {
match trait_method.node {
hir::ConstTraitItem(_, None) |
hir::MethodTraitItem(_, None) => {
hir::TraitItemKind::Const(_, None) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
// Keep going, nothing to get exported
}
hir::ConstTraitItem(_, Some(ref body)) => {
self.visit_expr(body);
hir::TraitItemKind::Const(_, Some(body_id)) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
self.visit_nested_body(body_id);
}
hir::MethodTraitItem(_, Some(body_id)) => {
self.visit_body(body_id);
}
hir::TypeTraitItem(..) => {}
hir::TraitItemKind::Type(..) => {}
}
}
ast_map::NodeImplItem(impl_item) => {
match impl_item.node {
hir::ImplItemKind::Const(_, ref expr) => {
self.visit_expr(&expr);
hir::ImplItemKind::Const(_, body) => {
self.visit_nested_body(body);
}
hir::ImplItemKind::Method(ref sig, body) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, sig, impl_item, did) {
self.visit_body(body)
self.visit_nested_body(body)
}
}
hir::ImplItemKind::Type(_) => {}
@ -358,6 +357,8 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a,
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// processed in visit_item above
}

View file

@ -1088,7 +1088,7 @@ fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a
fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
kind: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
body_id: hir::ExprId,
body_id: hir::BodyId,
sp: Span,
id: ast::NodeId) {
debug!("region::resolve_fn(id={:?}, \
@ -1101,22 +1101,22 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
visitor.cx.parent);
visitor.cx.parent = visitor.new_code_extent(
CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
let fn_decl_scope = visitor.new_code_extent(
CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id() });
CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
if let Some(root_id) = visitor.cx.root_id {
visitor.region_maps.record_fn_parent(body_id.node_id(), root_id);
visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
}
let outer_cx = visitor.cx;
let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
visitor.terminating_scopes.insert(body_id.node_id());
visitor.terminating_scopes.insert(body_id.node_id);
// The arguments and `self` are parented to the fn.
visitor.cx = Context {
root_id: Some(body_id.node_id()),
root_id: Some(body_id.node_id),
parent: ROOT_CODE_EXTENT,
var_parent: fn_decl_scope,
};
@ -1126,11 +1126,11 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
// The body of the every fn is a root scope.
visitor.cx = Context {
root_id: Some(body_id.node_id()),
root_id: Some(body_id.node_id),
parent: fn_decl_scope,
var_parent: fn_decl_scope
};
visitor.visit_body(body_id);
visitor.visit_nested_body(body_id);
// Restore context we had at the start.
visitor.cx = outer_cx;
@ -1195,7 +1195,7 @@ impl<'ast, 'a> Visitor<'ast> for RegionResolutionVisitor<'ast, 'a> {
}
fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl,
b: hir::ExprId, s: Span, n: NodeId) {
b: hir::BodyId, s: Span, n: NodeId) {
resolve_fn(self, fk, fd, b, s, n);
}
fn visit_arm(&mut self, a: &'ast Arm) {

View file

@ -33,7 +33,6 @@ use util::nodemap::NodeMap;
use rustc_data_structures::fx::FxHashSet;
use hir;
use hir::print::lifetime_to_string;
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
@ -190,7 +189,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// Items always introduce a new root scope
self.with(RootScope, |_, this| {
match item.node {
hir::ForeignItemFn(ref decl, ref generics) => {
hir::ForeignItemFn(ref decl, _, ref generics) => {
this.visit_early_late(item.id, decl, generics, |this| {
intravisit::walk_foreign_item(this, item);
})
@ -206,7 +205,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
b: hir::ExprId, s: Span, fn_id: ast::NodeId) {
b: hir::BodyId, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
self.visit_early_late(fn_id,decl, generics, |this| {
@ -266,7 +265,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// methods in an impl can reuse label names.
let saved = replace(&mut self.labels_in_fn, vec![]);
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) =
trait_item.node {
self.visit_early_late(
trait_item.id,
&sig.decl, &sig.generics,
@ -407,7 +407,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
// if one of the label shadows a lifetime or another label.
fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) {
struct GatherLabels<'a> {
sess: &'a Session,
scope: Scope<'a>,
@ -419,7 +419,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
scope: ctxt.scope,
labels_in_fn: &mut ctxt.labels_in_fn,
};
gather.visit_expr(ctxt.hir_map.expr(b));
gather.visit_body(ctxt.hir_map.body(b));
return;
impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
@ -501,7 +501,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn add_scope_and_walk_fn(&mut self,
fk: FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
fb: hir::ExprId,
fb: hir::BodyId,
_span: Span,
fn_id: ast::NodeId) {
match fk {
@ -522,8 +522,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// `self.labels_in_fn`.
extract_labels(self, fb);
self.with(FnScope { fn_id: fn_id, body_id: fb.node_id(), s: self.scope },
|_old_scope, this| this.visit_body(fb))
self.with(FnScope { fn_id: fn_id, body_id: fb.node_id, s: self.scope },
|_old_scope, this| this.visit_nested_body(fb))
}
// FIXME(#37666) this works around a limitation in the region inferencer
@ -821,9 +821,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
probably a bug in syntax::fold");
}
debug!("lifetime_ref={:?} id={:?} resolved to {:?} span={:?}",
lifetime_to_string(lifetime_ref),
lifetime_ref.id,
debug!("{} resolved to {:?} span={:?}",
self.hir_map.node_to_string(lifetime_ref.id),
def,
self.sess.codemap().span_to_string(lifetime_ref.span));
self.map.defs.insert(lifetime_ref.id, def);
@ -860,8 +859,8 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
let mut constrained_by_input = ConstrainedCollector { regions: FxHashSet() };
for arg in &decl.inputs {
constrained_by_input.visit_ty(&arg.ty);
for arg_ty in &decl.inputs {
constrained_by_input.visit_ty(arg_ty);
}
let mut appears_in_output = AllCollector {

View file

@ -48,7 +48,7 @@ impl<'a, 'tcx> MirSource {
match tcx.map.get(id) {
map::NodeItem(&Item { node: ItemConst(..), .. }) |
map::NodeTraitItem(&TraitItem { node: ConstTraitItem(..), .. }) |
map::NodeTraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
MirSource::Const(id)
}

View file

@ -508,14 +508,6 @@ pub struct GlobalCtxt<'tcx> {
/// FIXME(arielb1): why is this separate from populated_external_types?
pub populated_external_primitive_impls: RefCell<DefIdSet>,
/// Cache used by const_eval when decoding external constants.
/// Contains `None` when the constant has been fetched but doesn't exist.
/// Constains `Some(expr_id, type)` otherwise.
/// `type` is `None` in case it's not a primitive type
pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
/// Cache used by const_eval when decoding extern const fns
pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
/// Maps any item's def-id to its stability index.
pub stability: RefCell<stability::Index<'tcx>>,
@ -537,8 +529,8 @@ pub struct GlobalCtxt<'tcx> {
/// Caches the representation hints for struct definitions.
repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
/// Maps Expr NodeId's to their constant qualification.
pub const_qualif_map: RefCell<NodeMap<middle::const_qualif::ConstQualif>>,
/// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
@ -787,13 +779,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
used_trait_imports: RefCell::new(NodeSet()),
populated_external_types: RefCell::new(DefIdSet()),
populated_external_primitive_impls: RefCell::new(DefIdSet()),
extern_const_statics: RefCell::new(DefIdMap()),
extern_const_fns: RefCell::new(DefIdMap()),
stability: RefCell::new(stability),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
const_qualif_map: RefCell::new(NodeMap()),
rvalue_promotable_to_static: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap()),

View file

@ -1206,13 +1206,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
tcx.construct_parameter_environment(
impl_item.span,
tcx.map.local_def_id(id),
tcx.region_maps.call_site_extent(id, body.node_id()))
tcx.region_maps.call_site_extent(id, body.node_id))
}
}
}
Some(ast_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
hir::TypeTraitItem(..) | hir::ConstTraitItem(..) => {
hir::TraitItemKind::Type(..) | hir::TraitItemKind::Const(..) => {
// associated types don't have their own entry (for some reason),
// so for now just grab environment for the trait
let trait_id = tcx.map.get_parent(id);
@ -1221,13 +1221,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
trait_def_id,
tcx.region_maps.item_extent(id))
}
hir::MethodTraitItem(_, ref body) => {
hir::TraitItemKind::Method(_, ref body) => {
// Use call-site for extent (unless this is a
// trait method with no default; then fallback
// to the method id).
let extent = if let Some(body_id) = *body {
let extent = if let hir::TraitMethod::Provided(body_id) = *body {
// default impl: use call_site extent as free_id_outlive bound.
tcx.region_maps.call_site_extent(id, body_id.node_id())
tcx.region_maps.call_site_extent(id, body_id.node_id)
} else {
// no default impl: use item extent as free_id_outlive bound.
tcx.region_maps.item_extent(id)
@ -1248,7 +1248,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
tcx.construct_parameter_environment(
item.span,
fn_def_id,
tcx.region_maps.call_site_extent(id, body_id.node_id()))
tcx.region_maps.call_site_extent(id, body_id.node_id))
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
@ -1284,7 +1284,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
tcx.construct_parameter_environment(
expr.span,
base_def_id,
tcx.region_maps.call_site_extent(id, body.node_id()))
tcx.region_maps.call_site_extent(id, body.node_id))
} else {
tcx.empty_parameter_environment()
}
@ -2100,10 +2100,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
hir::ItemTrait(.., ref trait_items) => {
for trait_item in trait_items {
hir::ItemTrait(.., ref trait_item_refs) => {
for trait_item_ref in trait_item_refs {
let assoc_item =
self.associated_item_from_trait_item_ref(parent_def_id, trait_item);
self.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
}
}
@ -2121,28 +2121,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
fn associated_item_from_trait_item_ref(self,
parent_def_id: DefId,
trait_item: &hir::TraitItem)
trait_item_ref: &hir::TraitItemRef)
-> AssociatedItem {
let def_id = self.map.local_def_id(trait_item.id);
let (kind, has_self, has_value) = match trait_item.node {
hir::MethodTraitItem(ref sig, ref body) => {
(AssociatedKind::Method, sig.decl.get_self().is_some(),
body.is_some())
}
hir::ConstTraitItem(_, ref value) => {
(AssociatedKind::Const, false, value.is_some())
}
hir::TypeTraitItem(_, ref ty) => {
(AssociatedKind::Type, false, ty.is_some())
let def_id = self.map.local_def_id(trait_item_ref.id.node_id);
let (kind, has_self) = match trait_item_ref.kind {
hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
hir::AssociatedItemKind::Method { has_self } => {
(ty::AssociatedKind::Method, has_self)
}
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
};
AssociatedItem {
name: trait_item.name,
name: trait_item_ref.name,
kind: kind,
vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self),
defaultness: hir::Defaultness::Default { has_value: has_value },
vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self),
defaultness: trait_item_ref.defaultness,
def_id: def_id,
container: TraitContainer(parent_def_id),
method_has_self_argument: has_self
@ -2187,11 +2181,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let id = self.map.as_local_node_id(def_id).unwrap();
let item = self.map.expect_item(id);
let vec: Vec<_> = match item.node {
hir::ItemTrait(.., ref trait_items) => {
trait_items.iter()
.map(|trait_item| trait_item.id)
.map(|id| self.map.local_def_id(id))
.collect()
hir::ItemTrait(.., ref trait_item_refs) => {
trait_item_refs.iter()
.map(|trait_item_ref| trait_item_ref.id)
.map(|id| self.map.local_def_id(id.node_id))
.collect()
}
hir::ItemImpl(.., ref impl_item_refs) => {
impl_item_refs.iter()

View file

@ -189,9 +189,8 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &move_data::FlowedMoveData<'c, 'tcx>,
all_loans: &[Loan<'tcx>],
fn_id: ast::NodeId,
decl: &hir::FnDecl,
body: &hir::Expr) {
debug!("check_loans(body id={})", body.id);
body: &hir::Body) {
debug!("check_loans(body id={})", body.value.id);
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
@ -202,7 +201,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
all_loans: all_loans,
param_env: &infcx.parameter_environment
};
euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(decl, body);
euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body);
}
#[derive(PartialEq)]

View file

@ -41,21 +41,20 @@ mod move_error;
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
fn_id: NodeId,
decl: &hir::FnDecl,
body: &hir::Expr)
body: &hir::Body)
-> (Vec<Loan<'tcx>>,
move_data::MoveData<'tcx>) {
let mut glcx = GatherLoanCtxt {
bccx: bccx,
all_loans: Vec::new(),
item_ub: bccx.tcx.region_maps.node_extent(body.id),
item_ub: bccx.tcx.region_maps.node_extent(body.value.id),
move_data: MoveData::new(),
move_error_collector: move_error::MoveErrorCollector::new(),
};
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(decl, body);
euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body);
glcx.report_potential_errors();
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
@ -548,14 +547,14 @@ impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
item_id: ast::NodeId,
expr: &'tcx hir::Expr) {
body: hir::BodyId) {
debug!("gather_loans_in_static_initializer(expr={:?})", expr);
debug!("gather_loans_in_static_initializer(expr={:?})", body);
let mut sicx = StaticInitializerCtxt {
bccx: bccx,
item_id: item_id
};
sicx.visit_expr(expr);
sicx.visit_nested_body(body);
}

View file

@ -11,10 +11,7 @@
use borrowck::BorrowckCtxt;
use syntax::ast::{self, MetaItem};
use syntax_pos::{Span, DUMMY_SP};
use rustc::hir;
use rustc::hir::intravisit::{FnKind};
use syntax_pos::DUMMY_SP;
use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
use rustc::session::Session;
@ -57,27 +54,14 @@ pub struct MoveDataParamEnv<'tcx> {
}
pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
fk: FnKind,
_decl: &hir::FnDecl,
body: &hir::Expr,
_sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
match fk {
FnKind::ItemFn(name, ..) |
FnKind::Method(name, ..) => {
debug!("borrowck_mir({}) UNIMPLEMENTED", name);
}
FnKind::Closure(_) => {
debug!("borrowck_mir closure (body.id={}) UNIMPLEMENTED", body.id);
}
}
let tcx = bcx.tcx;
let def_id = tcx.map.local_def_id(id);
debug!("borrowck_mir({}) UNIMPLEMENTED", tcx.item_path_str(def_id));
let mir = &tcx.item_mir(def_id);
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let mir = &tcx.item_mir(tcx.map.local_def_id(id));
let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let flow_inits =

View file

@ -68,7 +68,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
b: hir::ExprId, s: Span, id: ast::NodeId) {
b: hir::BodyId, s: Span, id: ast::NodeId) {
match fk {
FnKind::ItemFn(..) |
FnKind::Method(..) => {
@ -88,15 +88,15 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
gather_loans::gather_loans_in_static_initializer(self, ti.id, &expr);
if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node {
gather_loans::gather_loans_in_static_initializer(self, ti.id, expr);
}
intravisit::walk_trait_item(self, ti);
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
gather_loans::gather_loans_in_static_initializer(self, ii.id, &expr);
if let hir::ImplItemKind::Const(_, expr) = ii.node {
gather_loans::gather_loans_in_static_initializer(self, ii.id, expr);
}
intravisit::walk_impl_item(self, ii);
}
@ -141,9 +141,9 @@ fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::I
// loan step is intended for things that have a data
// flow dependent conditions.
match item.node {
hir::ItemStatic(.., ref ex) |
hir::ItemConst(_, ref ex) => {
gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
hir::ItemStatic(.., ex) |
hir::ItemConst(_, ex) => {
gather_loans::gather_loans_in_static_initializer(this, item.id, ex);
}
_ => { }
}
@ -161,25 +161,25 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
body_id: hir::ExprId,
body_id: hir::BodyId,
sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
debug!("borrowck_fn(id={})", id);
let body = this.tcx.map.expr(body_id);
let body = this.tcx.map.body(body_id);
if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
this.with_temp_region_map(id, |this| {
mir::borrowck_mir(this, fk, decl, body, sp, id, attributes)
mir::borrowck_mir(this, id, attributes)
});
}
let cfg = cfg::CFG::new(this.tcx, body);
let cfg = cfg::CFG::new(this.tcx, &body.value);
let AnalysisData { all_loans,
loans: loan_dfcx,
move_data: flowed_moves } =
build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
build_borrowck_dataflow_data(this, &cfg, body, id);
move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
this.tcx,
@ -194,31 +194,31 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
&flowed_moves,
&all_loans[..],
id,
decl,
body);
intravisit::walk_fn(this, fk, decl, body_id, sp, id);
}
fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
cfg: &cfg::CFG,
body: &'tcx hir::Expr,
sp: Span,
body: &'tcx hir::Body,
id: ast::NodeId)
-> AnalysisData<'a, 'tcx>
{
// Check the body of fn items.
let tcx = this.tcx;
let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body, sp, id, &tcx.map);
let id_range = {
let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.map);
visitor.visit_body(body);
visitor.result()
};
let (all_loans, move_data) =
gather_loans::gather_loans_in_fn(this, id, decl, body);
gather_loans::gather_loans_in_fn(this, id, body);
let mut loan_dfcx =
DataFlowContext::new(this.tcx,
"borrowck",
Some(decl),
Some(body),
cfg,
LoanDataFlowOperator,
id_range,
@ -235,7 +235,6 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
this.tcx,
cfg,
id_range,
decl,
body);
AnalysisData { all_loans: all_loans,
@ -263,14 +262,11 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
}
};
let body = tcx.map.expr(fn_parts.body);
let body = tcx.map.body(fn_parts.body);
let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
fn_parts.kind,
&fn_parts.decl,
cfg,
body,
fn_parts.span,
fn_parts.id);
(bccx, dataflow_data)
@ -416,7 +412,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
match tcx.map.get(closure_id) {
hir_map::NodeExpr(expr) => match expr.node {
hir::ExprClosure(.., body_id, _) => {
body_id.node_id()
body_id.node_id
}
_ => {
bug!("encountered non-closure id: {}", closure_id)
@ -1121,22 +1117,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
if let Categorization::Local(local_id) = inner_cmt.cat {
let parent = self.tcx.map.get_parent_node(local_id);
let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
.map(|fn_like| fn_like.decl());
if let Some(fn_decl) = opt_fn_decl {
if let Some(ref arg) = fn_decl.inputs.iter()
.find(|ref arg| arg.pat.id == local_id) {
if let Some(fn_like) = FnLikeNode::from_node(self.tcx.map.get(parent)) {
if let Some(i) = self.tcx.map.body(fn_like.body()).arguments.iter()
.position(|arg| arg.pat.id == local_id) {
let arg_ty = &fn_like.decl().inputs[i];
if let hir::TyRptr(
opt_lifetime,
hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
arg.ty.node {
arg_ty.node {
if let Some(lifetime) = opt_lifetime {
if let Ok(snippet) = self.tcx.sess.codemap()
.span_to_snippet(ty.span) {
if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
.span_to_snippet(lifetime.span) {
db.span_label(arg.ty.span,
db.span_label(arg_ty.span,
&format!("use `&{} mut {}` \
here to make mutable",
lifetime_snippet,
@ -1145,9 +1140,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
}
else if let Ok(snippet) = self.tcx.sess.codemap()
.span_to_snippet(arg.ty.span) {
.span_to_snippet(arg_ty.span) {
if snippet.starts_with("&") {
db.span_label(arg.ty.span,
db.span_label(arg_ty.span,
&format!("use `{}` here to make mutable",
snippet.replace("&", "&mut ")));
}

View file

@ -655,13 +655,12 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cfg: &cfg::CFG,
id_range: IdRange,
decl: &hir::FnDecl,
body: &hir::Expr)
body: &hir::Body)
-> FlowedMoveData<'a, 'tcx> {
let mut dfcx_moves =
DataFlowContext::new(tcx,
"flowed_move_data_moves",
Some(decl),
Some(body),
cfg,
MoveDataFlowOperator,
id_range,
@ -669,7 +668,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
let mut dfcx_assign =
DataFlowContext::new(tcx,
"flowed_move_data_assigns",
Some(decl),
Some(body),
cfg,
AssignDataFlowOperator,
id_range,

View file

@ -30,7 +30,6 @@ use rustc_errors::DiagnosticBuilder;
use rustc::hir::def::*;
use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
use rustc::hir::print::pat_to_string;
use rustc::hir::{self, Pat, PatKind};
use rustc_back::slice;
@ -43,39 +42,17 @@ struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
fn visit_expr(&mut self, _expr: &'tcx hir::Expr) {
return // const, static and N in [T; N] - shouldn't contain anything
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
if let hir::ConstTraitItem(..) = item.node {
return // nothing worth match checking in a constant
} else {
intravisit::walk_trait_item(self, item);
}
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
if let hir::ImplItemKind::Const(..) = item.node {
return // nothing worth match checking in a constant
} else {
intravisit::walk_impl_item(self, item);
}
NestedVisitorMap::OnlyBodies(&self.tcx.map)
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
b: hir::ExprId, s: Span, id: ast::NodeId) {
if let FnKind::Closure(..) = fk {
span_bug!(s, "check_match: closure outside of function")
}
b: hir::BodyId, s: Span, id: ast::NodeId) {
intravisit::walk_fn(self, fk, fd, b, s, id);
MatchVisitor {
tcx: self.tcx,
param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
}.visit_fn(fk, fd, b, s, id);
}.visit_body(self.tcx.map.body(b));
}
}
@ -96,7 +73,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.tcx.map)
NestedVisitorMap::None
}
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
@ -119,13 +96,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
self.check_patterns(false, slice::ref_slice(&loc.pat));
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
b: hir::ExprId, s: Span, n: ast::NodeId) {
intravisit::walk_fn(self, fk, fd, b, s, n);
fn visit_body(&mut self, body: &'tcx hir::Body) {
intravisit::walk_body(self, body);
for input in &fd.inputs {
self.check_irrefutable(&input.pat, true);
self.check_patterns(false, slice::ref_slice(&input.pat));
for arg in &body.arguments {
self.check_irrefutable(&arg.pat, true);
self.check_patterns(false, slice::ref_slice(&arg.pat));
}
}
}
@ -254,7 +230,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
Useful => bug!()
};
let pattern_string = pat_to_string(witness[0].single_pattern());
let pattern_string = hir::print::to_string(&self.tcx.map, |s| {
s.print_pat(witness[0].single_pattern())
});
let mut diag = struct_span_err!(
self.tcx.sess, pat.span, E0005,
"refutable pattern in {}: `{}` not covered",
@ -405,7 +383,9 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
},
_ => bug!(),
};
let pattern_string = pat_to_string(witness);
let pattern_string = hir::print::to_string(&cx.tcx.map, |s| {
s.print_pat(witness)
});
struct_span_err!(cx.tcx.sess, sp, E0297,
"refutable pattern in `for` loop binding: \
`{}` not covered",
@ -415,7 +395,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
},
_ => {
let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
pat_to_string(w)
hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w))
}).collect();
const LIMIT: usize = 3;
let joined_patterns = match pattern_strings.len() {

View file

@ -576,18 +576,18 @@ https://doc.rust-lang.org/reference.html#ffi-attributes
E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
In an array type `[T; N]`, `N` is the number of elements in the array. This
must be an unsigned integer. Erroneous code example:
```compile_fail,E0306
let x = [0i32; true]; // error: expected positive integer for repeat count,
// found boolean
const X: [i32; true] = [0]; // error: expected `usize` for array length,
// found boolean
```
Working example:
```
let x = [0i32; 2];
const X: [i32; 1] = [0];
```
"##,
}

View file

@ -17,7 +17,6 @@ use self::EvalHint::*;
use rustc::hir::map as ast_map;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::cstore::InlinedItem;
use rustc::traits;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
@ -56,15 +55,17 @@ macro_rules! math {
fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
variant_def: DefId)
-> Option<&'tcx Expr> {
fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
-> Option<&'a Expr> {
let variant_expr = |variants: &'tcx [hir::Variant], id: ast::NodeId |
-> Option<&'tcx Expr> {
for variant in variants {
if variant.node.data.id() == id {
return variant.node.disr_expr.as_ref().map(|e| &**e);
return variant.node.disr_expr.map(|e| {
&tcx.map.body(e).value
});
}
}
None
}
};
if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
let enum_node_id = tcx.map.get_parent(variant_node_id);
@ -96,21 +97,24 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
match tcx.map.find(node_id) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
hir::ItemConst(ref ty, ref const_expr) => {
Some((&const_expr, tcx.ast_ty_to_prim_ty(ty)))
hir::ItemConst(ref ty, body) => {
Some((&tcx.map.body(body).value,
tcx.ast_ty_to_prim_ty(ty)))
}
_ => None
},
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
hir::ConstTraitItem(ref ty, ref expr_option) => {
hir::TraitItemKind::Const(ref ty, default) => {
if let Some(substs) = substs {
// If we have a trait item and the substitutions for it,
// `resolve_trait_associated_const` will select an impl
// or the default.
let trait_id = tcx.map.get_parent(node_id);
let trait_id = tcx.map.local_def_id(trait_id);
let default_value = expr_option.as_ref()
.map(|expr| (&**expr, tcx.ast_ty_to_prim_ty(ty)));
let default_value = default.map(|body| {
(&tcx.map.body(body).value,
tcx.ast_ty_to_prim_ty(ty))
});
resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
} else {
// Technically, without knowing anything about the
@ -125,29 +129,19 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_ => None
},
Some(ast_map::NodeImplItem(ii)) => match ii.node {
hir::ImplItemKind::Const(ref ty, ref expr) => {
Some((&expr, tcx.ast_ty_to_prim_ty(ty)))
hir::ImplItemKind::Const(ref ty, body) => {
Some((&tcx.map.body(body).value,
tcx.ast_ty_to_prim_ty(ty)))
}
_ => None
},
Some(_) => None
}
} else {
match tcx.extern_const_statics.borrow().get(&def_id) {
Some(&None) => return None,
Some(&Some((expr_id, ty))) => {
return Some((tcx.map.expect_expr(expr_id), ty));
}
None => {}
}
let mut used_substs = false;
let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
Some((&InlinedItem { body: ref const_expr, .. }, _)) => {
Some((&**const_expr, Some(tcx.sess.cstore.item_type(tcx, def_id))))
}
_ => None
};
let expr_ty = match tcx.sess.cstore.describe_def(def_id) {
let expr_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
(&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id)))
});
match tcx.sess.cstore.describe_def(def_id) {
Some(Def::AssociatedConst(_)) => {
let trait_id = tcx.sess.cstore.trait_of_item(def_id);
// As mentioned in the comments above for in-crate
@ -155,8 +149,6 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// trait-associated const if the caller gives us the
// substitutions for the reference to it.
if let Some(trait_id) = trait_id {
used_substs = true;
if let Some(substs) = substs {
resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
} else {
@ -168,70 +160,27 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
},
Some(Def::Const(..)) => expr_ty,
_ => None
};
// If we used the substitutions, particularly to choose an impl
// of a trait-associated const, don't cache that, because the next
// lookup with the same def_id may yield a different result.
if !used_substs {
tcx.extern_const_statics
.borrow_mut()
.insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
}
expr_ty
}
}
fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<ast::NodeId> {
match tcx.extern_const_fns.borrow().get(&def_id) {
Some(&ast::DUMMY_NODE_ID) => return None,
Some(&fn_id) => return Some(fn_id),
None => {}
}
if !tcx.sess.cstore.is_const_fn(def_id) {
tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
return None;
}
let fn_id = tcx.sess.cstore.maybe_get_item_ast(tcx, def_id).map(|t| t.1);
tcx.extern_const_fns.borrow_mut().insert(def_id,
fn_id.unwrap_or(ast::DUMMY_NODE_ID));
fn_id
}
pub enum ConstFnNode<'tcx> {
Local(FnLikeNode<'tcx>),
Inlined(&'tcx InlinedItem)
}
pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Option<ConstFnNode<'tcx>>
fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Option<&'tcx hir::Body>
{
let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
node_id
} else {
if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
if let ast_map::NodeInlinedItem(ii) = tcx.map.get(fn_id) {
return Some(ConstFnNode::Inlined(ii));
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| {
if fn_like.constness() == hir::Constness::Const {
Some(tcx.map.body(fn_like.body()))
} else {
bug!("Got const fn from external crate, but it's not inlined")
None
}
} else {
return None;
}
};
let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
Some(fn_like) => fn_like,
None => return None
};
if fn_like.constness() == hir::Constness::Const {
Some(ConstFnNode::Local(fn_like))
})
} else {
None
if tcx.sess.cstore.is_const_fn(def_id) {
tcx.sess.cstore.maybe_get_item_body(tcx, def_id)
} else {
None
}
}
}
@ -864,18 +813,15 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
callee => signal!(e, CallOn(callee)),
};
let (arg_defs, body_id) = match lookup_const_fn_by_id(tcx, did) {
Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), ii.body.expr_id()),
Some(ConstFnNode::Local(fn_like)) =>
(fn_like.decl().inputs.iter()
.map(|arg| match arg.pat.node {
hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
_ => None
}).collect(),
fn_like.body()),
let body = match lookup_const_fn_by_id(tcx, did) {
Some(body) => body,
None => signal!(e, NonConstPath),
};
let result = tcx.map.expr(body_id);
let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
_ => None
}).collect::<Vec<_>>();
assert_eq!(arg_defs.len(), args.len());
let mut call_args = DefIdMap();
@ -893,7 +839,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
debug!("const call({:?})", call_args);
eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
eval_const_expr_partial(tcx, &body.value, ty_hint, Some(&call_args))?
},
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
Ok(val) => val,
@ -953,11 +899,12 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
hir::ExprRepeat(_, ref n) => {
hir::ExprRepeat(_, n) => {
let len_hint = ty_hint.checked_or(tcx.types.usize);
let n = &tcx.map.body(n).value;
Repeat(
e.id,
match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
match eval_const_expr_partial(tcx, n, len_hint, fn_args)? {
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
Integral(_) => signal!(e, RepeatCountNotNatural),
_ => signal!(e, RepeatCountNotInt),
@ -1373,7 +1320,8 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
if let Def::Local(..) = path.def {
diag.note(&format!("`{}` is a variable", path));
diag.note(&format!("`{}` is a variable",
tcx.map.node_to_pretty_string(count_expr.id)));
}
}

View file

@ -35,6 +35,9 @@ impl<'v> ItemLikeVisitor<'v> for Finder {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -47,7 +47,7 @@ use std::path::Path;
use std::str::FromStr;
use rustc::hir::map as hir_map;
use rustc::hir::map::{blocks, NodePrinter};
use rustc::hir::map::blocks;
use rustc::hir;
use rustc::hir::print as pprust_hir;
@ -320,7 +320,16 @@ impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> {
}
impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {
fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
-> io::Result<()> {
if let Some(ref map) = self.ast_map {
pprust_hir::PpAnn::nested(map, state, nested)
} else {
Ok(())
}
}
}
struct IdentifiedAnnotation<'ast> {
sess: &'ast Session,
@ -393,6 +402,14 @@ impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
}
impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
-> io::Result<()> {
if let Some(ref map) = self.ast_map {
pprust_hir::PpAnn::nested(map, state, nested)
} else {
Ok(())
}
}
fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
match node {
pprust_hir::NodeExpr(_) => s.popen(),
@ -488,6 +505,10 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
}
impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
-> io::Result<()> {
pprust_hir::PpAnn::nested(&self.tcx.map, state, nested)
}
fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
match node {
pprust_hir::NodeExpr(_) => s.popen(),
@ -702,8 +723,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
let cfg = match code {
blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
blocks::Code::FnLike(fn_like) => {
let body = tcx.map.expr(fn_like.body());
cfg::CFG::new(tcx, body)
let body = tcx.map.body(fn_like.body());
cfg::CFG::new(tcx, &body.value)
},
};
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
@ -909,11 +930,10 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
&mut rdr,
box out,
annotation.pp_ann(),
true,
Some(ast_map.krate()));
true);
for node_id in uii.all_matching_node_ids(ast_map) {
let node = ast_map.get(node_id);
pp_state.print_node(&node)?;
pp_state.print_node(node)?;
pp::space(&mut pp_state.s)?;
let path = annotation.node_path(node_id)
.expect("--unpretty missing node paths");

View file

@ -171,6 +171,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> {
self.process_attrs(item.id, &item.attrs);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
self.process_attrs(trait_item.id, &trait_item.attrs);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.process_attrs(impl_item.id, &impl_item.attrs);
}

View file

@ -234,6 +234,11 @@ impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
visit::walk_item(self, item);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item));
visit::walk_trait_item(self, trait_item);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
visit::walk_impl_item(self, impl_item);

View file

@ -188,7 +188,7 @@ enum SawAbiComponent<'a> {
SawTraitItem(SawTraitOrImplItemComponent),
SawImplItem(SawTraitOrImplItemComponent),
SawStructField,
SawVariant,
SawVariant(bool),
SawQPath,
SawPathSegment,
SawPathParameters,
@ -473,12 +473,14 @@ enum SawTraitOrImplItemComponent {
SawTraitOrImplItemType
}
fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
match *ti {
ConstTraitItem(..) => SawTraitOrImplItemConst,
MethodTraitItem(ref sig, ref body) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, body.is_some()),
TypeTraitItem(..) => SawTraitOrImplItemType
TraitItemKind::Const(..) => SawTraitOrImplItemConst,
TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
TraitItemKind::Type(..) => SawTraitOrImplItemType
}
}
@ -584,7 +586,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
g: &'tcx Generics,
item_id: NodeId) {
debug!("visit_variant: st={:?}", self.st);
SawVariant.hash(self.st);
SawVariant(v.node.disr_expr.is_some()).hash(self.st);
hash_attrs!(self, &v.node.attrs);
visit::walk_variant(self, v, g, item_id)
}
@ -616,7 +618,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
// implicitly hashing the discriminant of SawExprComponent.
hash_span!(self, ex.span, force_span);
hash_attrs!(self, &ex.attrs);
visit::walk_expr(self, ex)
// Always hash nested constant bodies (e.g. n in `[x; n]`).
let hash_bodies = self.hash_bodies;
self.hash_bodies = true;
visit::walk_expr(self, ex);
self.hash_bodies = hash_bodies;
}
fn visit_stmt(&mut self, s: &'tcx Stmt) {
@ -686,7 +693,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
debug!("visit_ty: st={:?}", self.st);
SawTy(saw_ty(&t.node)).hash(self.st);
hash_span!(self, t.span);
visit::walk_ty(self, t)
// Always hash nested constant bodies (e.g. N in `[T; N]`).
let hash_bodies = self.hash_bodies;
self.hash_bodies = true;
visit::walk_ty(self, t);
self.hash_bodies = hash_bodies;
}
fn visit_generics(&mut self, g: &'tcx Generics) {
@ -1157,8 +1169,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
// These fields are handled separately:
exported_macros: _,
items: _,
trait_items: _,
impl_items: _,
exprs: _,
bodies: _,
} = *krate;
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);

View file

@ -185,6 +185,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
@ -229,6 +232,9 @@ impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx,
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -243,7 +243,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Expr,
_: &hir::Body,
span: Span,
id: ast::NodeId) {
match fk {
@ -271,12 +271,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
}
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(_, None) = trait_item.node {
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(ref names)) = item.node {
self.check_snake_case(cx,
"trait method",
&trait_item.name.as_str(),
Some(trait_item.span));
&item.name.as_str(),
Some(item.span));
for name in names {
self.check_snake_case(cx, "variable", &name.node.as_str(), Some(name.span));
}
}
}
@ -288,14 +291,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
}
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
// Exclude parameter names from foreign functions
let parent_node = cx.tcx.map.get_parent_node(p.id);
if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) {
if let hir::ForeignItemFn(..) = item.node {
return;
}
}
if let &PatKind::Binding(_, _, ref path1, _) = &p.node {
self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
}
@ -363,7 +358,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
match ti.node {
hir::ConstTraitItem(..) => {
hir::TraitItemKind::Const(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
}
_ => {}

View file

@ -222,7 +222,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
cx: &LateContext,
fk: FnKind<'tcx>,
_: &hir::FnDecl,
_: &hir::Expr,
_: &hir::Body,
span: Span,
_: ast::NodeId) {
match fk {
@ -240,11 +240,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
}
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE,
trait_item.span,
item.span,
"declaration of an `unsafe` method")
}
}
@ -374,12 +374,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
hir::ItemEnum(..) => "an enum",
hir::ItemStruct(..) => "a struct",
hir::ItemUnion(..) => "a union",
hir::ItemTrait(.., ref items) => {
hir::ItemTrait(.., ref trait_item_refs) => {
// Issue #11592, traits are always considered exported, even when private.
if it.vis == hir::Visibility::Inherited {
self.private_traits.insert(it.id);
for itm in items {
self.private_traits.insert(itm.id);
for trait_item_ref in trait_item_refs {
self.private_traits.insert(trait_item_ref.id.node_id);
}
return;
}
@ -418,9 +418,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
}
let desc = match trait_item.node {
hir::ConstTraitItem(..) => "an associated constant",
hir::MethodTraitItem(..) => "a trait method",
hir::TypeTraitItem(..) => "an associated type",
hir::TraitItemKind::Const(..) => "an associated constant",
hir::TraitItemKind::Method(..) => "a trait method",
hir::TraitItemKind::Type(..) => "an associated type",
};
self.check_missing_docs_attrs(cx,
@ -674,7 +674,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
cx: &LateContext,
fn_kind: FnKind,
_: &hir::FnDecl,
blk: &hir::Expr,
body: &hir::Body,
sp: Span,
id: ast::NodeId) {
let method = match fn_kind {
@ -712,7 +712,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
// to have behaviour like the above, rather than
// e.g. accidentally recurring after an assert.
let cfg = cfg::CFG::new(cx.tcx, blk);
let cfg = cfg::CFG::new(cx.tcx, &body.value);
let mut work_queue = vec![cfg.entry];
let mut reached_exit_without_self_call = false;

View file

@ -679,7 +679,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
self.check_type_for_ffi_and_report_errors(input_hir.ty.span, input_ty);
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
}
if let hir::Return(ref ret_hir) = decl.output {
@ -713,7 +713,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
for ni in &nmod.items {
match ni.node {
hir::ForeignItemFn(ref decl, _) => {
hir::ForeignItemFn(ref decl, _, _) => {
vis.check_foreign_fn(ni.id, decl);
}
hir::ForeignItemStatic(ref ty, _) => {

View file

@ -97,11 +97,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
fn check_fn(&mut self,
cx: &LateContext,
_: FnKind,
decl: &hir::FnDecl,
_: &hir::Expr,
_: &hir::FnDecl,
body: &hir::Body,
_: Span,
_: ast::NodeId) {
for a in &decl.inputs {
for a in &body.arguments {
self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
}
}

View file

@ -16,8 +16,7 @@ use cstore::CrateMetadata;
use encoder::EncodeContext;
use schema::*;
use rustc::middle::cstore::{InlinedItem, InlinedItemRef};
use rustc::middle::const_qualif::ConstQualif;
use rustc::hir;
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt, Ty};
@ -29,8 +28,10 @@ use rustc_serialize::Encodable;
#[derive(RustcEncodable, RustcDecodable)]
pub struct Ast<'tcx> {
id_range: IdRange,
item: Lazy<InlinedItem>,
body: Lazy<hir::Body>,
side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>,
pub nested_bodies: LazySeq<hir::Body>,
pub rvalue_promotable_to_static: bool,
}
#[derive(RustcEncodable, RustcDecodable)]
@ -39,16 +40,17 @@ enum TableEntry<'tcx> {
NodeType(Ty<'tcx>),
ItemSubsts(ty::ItemSubsts<'tcx>),
Adjustment(ty::adjustment::Adjustment<'tcx>),
ConstQualif(ConstQualif),
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
pub fn encode_inlined_item(&mut self, ii: InlinedItemRef<'tcx>) -> Lazy<Ast<'tcx>> {
let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
ii.visit(&mut id_visitor);
pub fn encode_body(&mut self, body: hir::BodyId) -> Lazy<Ast<'tcx>> {
let body = self.tcx.map.body(body);
let ii_pos = self.position();
ii.encode(self).unwrap();
let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
id_visitor.visit_body(body);
let body_pos = self.position();
body.encode(self).unwrap();
let tables_pos = self.position();
let tables_count = {
@ -56,14 +58,29 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ecx: self,
count: 0,
};
ii.visit(&mut visitor);
visitor.visit_body(body);
visitor.count
};
let nested_pos = self.position();
let nested_count = {
let mut visitor = NestedBodyEncodingVisitor {
ecx: self,
count: 0,
};
visitor.visit_body(body);
visitor.count
};
let rvalue_promotable_to_static =
self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
self.lazy(&Ast {
id_range: id_visitor.result(),
item: Lazy::with_position(ii_pos),
body: Lazy::with_position(body_pos),
side_tables: LazySeq::with_position_and_length(tables_pos, tables_count),
nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count),
rvalue_promotable_to_static: rvalue_promotable_to_static
})
}
}
@ -94,18 +111,36 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType));
encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif));
}
}
/// Decodes an item from its AST in the cdata's metadata and adds it to the
struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> {
ecx: &'a mut EncodeContext<'b, 'tcx>,
count: usize,
}
impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
fn visit_nested_body(&mut self, body: hir::BodyId) {
let body = self.ecx.tcx.map.body(body);
body.encode(self.ecx).unwrap();
self.count += 1;
self.visit_body(body);
}
}
/// Decodes an item's body from its AST in the cdata's metadata and adds it to the
/// ast-map.
pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ast: Ast<'tcx>,
orig_did: DefId)
-> &'tcx InlinedItem {
debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did));
pub fn decode_body<'a, 'tcx>(cdata: &CrateMetadata,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
ast: Ast<'tcx>)
-> &'tcx hir::Body {
debug!("> Decoding inlined fn: {}", tcx.item_path_str(def_id));
let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize();
let start = tcx.sess.reserve_node_ids(cnt);
@ -115,12 +150,6 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
max: ast::NodeId::new(start.as_usize() + cnt),
}];
let ii = ast.item.decode((cdata, tcx, id_ranges));
let item_node_id = tcx.sess.next_node_id();
let ii = ast_map::map_decoded_item(&tcx.map,
ii,
item_node_id);
for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
match entry {
TableEntry::TypeRelativeDef(def) => {
@ -135,11 +164,9 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
TableEntry::Adjustment(adj) => {
tcx.tables.borrow_mut().adjustments.insert(id, adj);
}
TableEntry::ConstQualif(qualif) => {
tcx.const_qualif_map.borrow_mut().insert(id, qualif);
}
}
}
ii
let body = ast.body.decode((cdata, tcx, id_ranges));
ast_map::map_decoded_body(&tcx.map, def_id, body, tcx.sess.next_node_id())
}

View file

@ -88,13 +88,6 @@ pub struct CrateMetadata {
pub dllimport_foreign_items: FxHashSet<DefIndex>,
}
pub struct CachedInlinedItem {
/// The NodeId of the RootInlinedParent HIR map entry
pub inlined_root: ast::NodeId,
/// The local NodeId of the inlined entity
pub item_id: ast::NodeId,
}
pub struct CStore {
pub dep_graph: DepGraph,
metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
@ -104,8 +97,7 @@ pub struct CStore {
used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
pub inlined_item_cache: RefCell<DefIdMap<Option<ast::NodeId>>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
}
@ -121,7 +113,6 @@ impl CStore {
dllimport_foreign_items: RefCell::new(FxHashSet()),
visible_parent_map: RefCell::new(FxHashMap()),
inlined_item_cache: RefCell::new(FxHashMap()),
defid_for_inlined_node: RefCell::new(FxHashMap()),
}
}

View file

@ -13,7 +13,7 @@ use encoder;
use locator;
use schema;
use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
use rustc::hir::def::{self, Def};
use rustc::middle::lang_items;
@ -36,6 +36,8 @@ use rustc::hir::svh::Svh;
use rustc_back::target::Target;
use rustc::hir;
use std::collections::BTreeMap;
impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn describe_def(&self, def: DefId) -> Option<Def> {
self.dep_graph.read(DepNode::MetaData(def));
@ -128,7 +130,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
{
self.dep_graph.read(DepNode::MetaData(did));
// FIXME(#38501) We've skipped a `read` on the `HirBody` of
// a `fn` when encoding, so the dep-tracking wouldn't work.
// This is only used by rustdoc anyway, which shouldn't have
// incremental recompilation ever enabled.
assert!(!self.dep_graph.is_fully_enabled());
self.get_crate_data(did.krate).get_fn_arg_names(did.index)
}
@ -423,94 +429,42 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
})
}
fn maybe_get_item_ast<'a>(&'tcx self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<(&'tcx InlinedItem, ast::NodeId)>
fn maybe_get_item_body<'a>(&'tcx self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<&'tcx hir::Body>
{
self.dep_graph.read(DepNode::MetaData(def_id));
match self.inlined_item_cache.borrow().get(&def_id) {
Some(&None) => {
return None; // Not inlinable
}
Some(&Some(ref cached_inlined_item)) => {
if let Some(&cached) = self.inlined_item_cache.borrow().get(&def_id) {
return cached.map(|root_id| {
// Already inline
debug!("maybe_get_item_ast({}): already inline as node id {}",
tcx.item_path_str(def_id), cached_inlined_item.item_id);
return Some((tcx.map.expect_inlined_item(cached_inlined_item.inlined_root),
cached_inlined_item.item_id));
}
None => {
// Not seen yet
}
debug!("maybe_get_item_body({}): already inline", tcx.item_path_str(def_id));
tcx.map.expect_inlined_body(root_id)
});
}
debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id));
debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
let inlined = self.get_crate_data(def_id.krate).maybe_get_item_ast(tcx, def_id.index);
let inlined = self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index);
let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| {
let cache_entry = cstore::CachedInlinedItem {
inlined_root: inlined_root_node_id,
item_id: inlined_item_id,
};
self.inlined_item_cache
.borrow_mut()
.insert(original_def_id, Some(cache_entry));
self.defid_for_inlined_node
.borrow_mut()
.insert(inlined_item_id, original_def_id);
};
self.inlined_item_cache.borrow_mut().insert(def_id, inlined.map(|body| {
let root_id = tcx.map.get_parent_node(body.value.id);
assert_eq!(tcx.map.get_parent_node(root_id), root_id);
root_id
}));
let find_inlined_item_root = |inlined_item_id| {
let mut node = inlined_item_id;
// If we can't find the inline root after a thousand hops, we can
// be pretty sure there's something wrong with the HIR map.
for _ in 0 .. 1000 {
let parent_node = tcx.map.get_parent_node(node);
if parent_node == node {
return node;
}
node = parent_node;
}
bug!("cycle in HIR map parent chain")
};
match inlined {
None => {
self.inlined_item_cache
.borrow_mut()
.insert(def_id, None);
}
Some(&InlinedItem { ref body, .. }) => {
let inlined_root_node_id = find_inlined_item_root(body.id);
cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
}
}
// We can be sure to hit the cache now
return self.maybe_get_item_ast(tcx, def_id);
inlined
}
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
assert!(!def_id.is_local());
match self.inlined_item_cache.borrow().get(&def_id) {
Some(&Some(ref cached_inlined_item)) => {
Some(cached_inlined_item.item_id)
}
Some(&None) => {
None
}
_ => {
bug!("Trying to lookup inlined NodeId for unexpected item");
}
}
fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).item_body_nested_bodies(def.index)
}
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x)
fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).const_is_rvalue_promotable_to_static(def.index)
}
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> {

View file

@ -10,7 +10,7 @@
// Decoding metadata from a single crate's metadata
use astencode::decode_inlined_item;
use astencode::decode_body;
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
use schema::*;
@ -18,7 +18,7 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData};
use rustc::hir;
use rustc::hir::intravisit::IdRange;
use rustc::middle::cstore::{InlinedItem, LinkagePreference};
use rustc::middle::cstore::LinkagePreference;
use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items;
@ -32,6 +32,7 @@ use rustc::mir::Mir;
use std::borrow::Cow;
use std::cell::Ref;
use std::collections::BTreeMap;
use std::io;
use std::mem;
use std::str;
@ -819,20 +820,27 @@ impl<'a, 'tcx> CrateMetadata {
}
}
pub fn maybe_get_item_ast(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: DefIndex)
-> Option<&'tcx InlinedItem> {
debug!("Looking up item: {:?}", id);
pub fn maybe_get_item_body(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: DefIndex)
-> Option<&'tcx hir::Body> {
if self.is_proc_macro(id) { return None; }
let item_doc = self.entry(id);
let item_did = self.local_def_id(id);
item_doc.ast.map(|ast| {
let ast = ast.decode(self);
decode_inlined_item(self, tcx, ast, item_did)
self.entry(id).ast.map(|ast| {
decode_body(self, tcx, self.local_def_id(id), ast.decode(self))
})
}
pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
self.entry(id).ast.into_iter().flat_map(|ast| {
ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
}).collect()
}
pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool {
self.entry(id).ast.expect("const item missing `ast`")
.decode(self).rvalue_promotable_to_static
}
pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
!self.is_proc_macro(id) &&
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()

View file

@ -12,8 +12,7 @@ use cstore;
use index::Index;
use schema::*;
use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary};
use rustc::hir::def;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
use rustc::hir::map::definitions::DefPathTable;
@ -34,6 +33,7 @@ use std::io::Cursor;
use std::rc::Rc;
use std::u32;
use syntax::ast::{self, CRATE_NODE_ID};
use syntax::codemap::Spanned;
use syntax::attr;
use syntax::symbol::Symbol;
use syntax_pos;
@ -442,10 +442,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let kind = match trait_item.kind {
ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
ty::AssociatedKind::Method => {
let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
let arg_names = match *m {
hir::TraitMethod::Required(ref names) => {
self.encode_fn_arg_names(names)
}
hir::TraitMethod::Provided(body) => {
self.encode_fn_arg_names_for_body(body)
}
};
FnData {
constness: hir::Constness::NotConst,
arg_names: self.encode_fn_arg_names(&sig.decl),
arg_names: arg_names
}
} else {
bug!()
@ -486,13 +494,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
ast: if let hir::ConstTraitItem(_, Some(_)) = ast_item.node {
// We only save the HIR for associated consts with bodies
// (InlinedItemRef::from_trait_item panics otherwise)
let trait_def_id = trait_item.container.id();
Some(self.encode_inlined_item(
InlinedItemRef::from_trait_item(trait_def_id, ast_item, tcx)
))
ast: if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
Some(self.encode_body(body))
} else {
None
},
@ -501,12 +504,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
let tcx = self.tcx;
let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
let ast_item = self.tcx.map.expect_impl_item(node_id);
let impl_item = self.tcx.associated_item(def_id);
let impl_def_id = impl_item.container.id();
let container = match impl_item.defaultness {
hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
@ -518,10 +518,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let kind = match impl_item.kind {
ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
ty::AssociatedKind::Method => {
let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
FnData {
constness: sig.constness,
arg_names: self.encode_fn_arg_names(&sig.decl),
arg_names: self.encode_fn_arg_names_for_body(body),
}
} else {
bug!()
@ -535,17 +535,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
};
let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const {
(true, true)
} else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node {
(Some(body), true)
} else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
let generics = self.tcx.item_generics(def_id);
let types = generics.parent_types as usize + generics.types.len();
let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
let is_const_fn = sig.constness == hir::Constness::Const;
let ast = if is_const_fn { Some(body) } else { None };
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
(is_const_fn, needs_inline || is_const_fn || always_encode_mir)
(ast, needs_inline || is_const_fn || always_encode_mir)
} else {
(false, false)
(None, false)
};
Entry {
@ -563,27 +564,28 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
ast: if ast {
Some(self.encode_inlined_item(
InlinedItemRef::from_impl_item(impl_def_id, ast_item, tcx)
))
} else {
None
},
ast: ast.map(|body| self.encode_body(body)),
mir: if mir { self.encode_mir(def_id) } else { None },
}
}
fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
self.lazy_seq(decl.inputs.iter().map(|arg| {
if let PatKind::Binding(_, _, ref path1, _) = arg.pat.node {
path1.node
} else {
Symbol::intern("")
fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId)
-> LazySeq<ast::Name> {
let _ignore = self.tcx.dep_graph.in_ignore();
let body = self.tcx.map.body(body_id);
self.lazy_seq(body.arguments.iter().map(|arg| {
match arg.pat.node {
PatKind::Binding(_, _, name, _) => name.node,
_ => Symbol::intern("")
}
}))
}
fn encode_fn_arg_names(&mut self, names: &[Spanned<ast::Name>])
-> LazySeq<ast::Name> {
self.lazy_seq(names.iter().map(|name| name.node))
}
fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
}
@ -619,10 +621,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
hir::ItemConst(..) => EntryKind::Const,
hir::ItemFn(ref decl, _, constness, ..) => {
hir::ItemFn(_, _, constness, .., body) => {
let data = FnData {
constness: constness,
arg_names: self.encode_fn_arg_names(&decl),
arg_names: self.encode_fn_arg_names_for_body(body),
};
EntryKind::Fn(self.lazy(&data))
@ -793,16 +795,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
},
ast: match item.node {
hir::ItemConst(..) |
hir::ItemFn(_, _, hir::Constness::Const, ..) => {
Some(self.encode_inlined_item(
InlinedItemRef::from_item(def_id, item, tcx)
))
hir::ItemConst(_, body) |
hir::ItemFn(_, _, hir::Constness::Const, _, _, body) => {
Some(self.encode_body(body))
}
_ => None,
},
mir: match item.node {
hir::ItemStatic(..) |
hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
self.encode_mir(def_id)
}
hir::ItemConst(..) => self.encode_mir(def_id),
hir::ItemFn(_, _, constness, _, ref generics, _) => {
let tps_len = generics.ty_params.len();
@ -913,10 +915,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
let kind = match nitem.node {
hir::ForeignItemFn(ref fndecl, _) => {
hir::ForeignItemFn(_, ref names, _) => {
let data = FnData {
constness: hir::Constness::NotConst,
arg_names: self.encode_fn_arg_names(&fndecl),
arg_names: self.encode_fn_arg_names(names),
};
EntryKind::ForeignFn(self.lazy(&data))
}
@ -1162,6 +1164,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &'v hir::TraitItem) {}
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
// handled in `visit_item` above
}

View file

@ -729,7 +729,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
name: Some(name),
source_info: Some(source_info),
});
let extent = self.extent_of_innermost_scope();
let extent = self.hir.tcx().region_maps.var_scope(var_id);
self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
self.var_indices.insert(var_id, var);

View file

@ -126,7 +126,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
arguments: A,
abi: Abi,
return_ty: Ty<'gcx>,
ast_body: &'gcx hir::Expr)
body: &'gcx hir::Body)
-> Mir<'tcx>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{
@ -136,17 +136,16 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
let span = tcx.map.span(fn_id);
let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
let body_id = ast_body.id;
let call_site_extent =
tcx.region_maps.lookup_code_extent(
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
let arg_extent =
tcx.region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
let mut block = START_BLOCK;
unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
unpack!(block = builder.in_scope(arg_extent, block, |builder| {
builder.args_and_body(block, &arguments, arg_extent, ast_body)
builder.args_and_body(block, &arguments, arg_extent, &body.value)
}));
// Attribute epilogue to function's closing brace
let fn_end = Span { lo: span.hi, ..span };
@ -197,9 +196,10 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
item_id: ast::NodeId,
ast_expr: &'tcx hir::Expr)
body_id: hir::BodyId)
-> Mir<'tcx> {
let tcx = hir.tcx();
let ast_expr = &tcx.map.body(body_id).value;
let ty = tcx.tables().expr_ty_adjusted(ast_expr);
let span = tcx.map.span(item_id);
let mut builder = Builder::new(hir, span, 0, ty);

View file

@ -253,7 +253,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
f: F)
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
{
let extent = self.extent_of_innermost_scope();
let extent = self.scopes.last().map(|scope| scope.extent).unwrap();
let loop_scope = LoopScope {
extent: extent.clone(),
continue_block: loop_block,
@ -411,10 +411,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
pub fn extent_of_innermost_scope(&self) -> CodeExtent {
self.scopes.last().map(|scope| scope.extent).unwrap()
}
/// Returns the extent of the scope which should be exited by a
/// return.
pub fn extent_of_return_scope(&self) -> CodeExtent {

View file

@ -575,7 +575,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
// Now comes the rote stuff:
hir::ExprRepeat(ref v, ref c) => {
hir::ExprRepeat(ref v, c) => {
let c = &cx.tcx.map.body(c).value;
ExprKind::Repeat {
value: v.to_ref(),
count: TypedConstVal {
@ -585,7 +586,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
ConstVal::Integral(ConstInt::Usize(u)) => u,
other => bug!("constant evaluation of repeat count yielded {:?}", other),
},
},
}
}
}
hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
@ -780,7 +781,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let body_id = match cx.tcx.map.find(closure_expr_id) {
Some(map::NodeExpr(expr)) => {
match expr.node {
hir::ExprClosure(.., body_id, _) => body_id.node_id(),
hir::ExprClosure(.., body, _) => body.node_id,
_ => {
span_bug!(expr.span, "closure expr is not a closure expr");
}

View file

@ -129,16 +129,17 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
}
impl<'a, 'gcx> BuildMir<'a, 'gcx> {
fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
fn build_const_integer(&mut self, body: hir::BodyId) {
let body = self.tcx.map.body(body);
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
// Type-checking should not let closures get
// this far in an integer constant position.
if let hir::ExprClosure(..) = expr.node {
if let hir::ExprClosure(..) = body.value.node {
return;
}
self.cx(MirSource::Const(expr.id)).build(|cx| {
build::construct_const(cx, expr.id, expr)
self.cx(MirSource::Const(body.value.id)).build(|cx| {
build::construct_const(cx, body.value.id, body.id())
});
}
}
@ -151,12 +152,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Const and static items.
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
hir::ItemConst(_, ref expr) => {
hir::ItemConst(_, expr) => {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
}
hir::ItemStatic(_, m, ref expr) => {
hir::ItemStatic(_, m, expr) => {
self.cx(MirSource::Static(item.id, m)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
@ -168,7 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Trait associated const defaults.
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
if let hir::TraitItemKind::Const(_, Some(expr)) = item.node {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
@ -178,7 +179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Impl associated const.
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
if let hir::ImplItemKind::Const(_, ref expr) = item.node {
if let hir::ImplItemKind::Const(_, expr) = item.node {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
@ -188,7 +189,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Repeat counts, i.e. [expr; constant].
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
if let hir::ExprRepeat(_, ref count) = expr.node {
if let hir::ExprRepeat(_, count) = expr.node {
self.build_const_integer(count);
}
intravisit::walk_expr(self, expr);
@ -196,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Array lengths, i.e. [T; constant].
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
if let hir::TyArray(_, ref length) = ty.node {
if let hir::TyArray(_, length) = ty.node {
self.build_const_integer(length);
}
intravisit::walk_ty(self, ty);
@ -205,7 +206,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
// Enum variant discriminant values.
fn visit_variant(&mut self, v: &'tcx hir::Variant,
g: &'tcx hir::Generics, item_id: ast::NodeId) {
if let Some(ref expr) = v.node.disr_expr {
if let Some(expr) = v.node.disr_expr {
self.build_const_integer(expr);
}
intravisit::walk_variant(self, v, g, item_id);
@ -214,7 +215,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
fn visit_fn(&mut self,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
body_id: hir::ExprId,
body_id: hir::BodyId,
span: Span,
id: ast::NodeId) {
// fetch the fully liberated fn signature (that is, all bound
@ -227,22 +228,21 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
};
let (abi, implicit_argument) = if let FnKind::Closure(..) = fk {
(Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id()), None)))
(Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id), None)))
} else {
let def_id = self.tcx.map.local_def_id(id);
(self.tcx.item_type(def_id).fn_abi(), None)
};
let body = self.tcx.map.body(body_id);
let explicit_arguments =
decl.inputs
body.arguments
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs()[index], Some(&*arg.pat))
});
let body = self.tcx.map.expr(body_id);
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
self.cx(MirSource::Fn(id)).build(|cx| {
build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)

View file

@ -26,8 +26,8 @@
use rustc::dep_graph::DepNode;
use rustc::ty::cast::CastKind;
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
use rustc_const_eval::{ConstFnNode, eval_const_expr_partial, lookup_const_by_id};
use rustc_const_eval::{ConstEvalErr, compare_lit_exprs};
use rustc_const_eval::{eval_const_expr_partial};
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
use rustc_const_eval::ErrKind::UnresolvedPath;
@ -35,80 +35,36 @@ use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_math::{ConstMathErr, Op};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::middle::const_qualif::ConstQualif;
use rustc::util::nodemap::NodeSet;
use rustc::lint::builtin::CONST_ERR;
use rustc::hir::{self, PatKind};
use syntax::ast;
use syntax_pos::Span;
use rustc::hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use std::collections::hash_map::Entry;
use std::cmp::Ordering;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Mode {
Const,
ConstFn,
Static,
StaticMut,
// An expression that occurs outside of any constant context
// (i.e. `const`, `static`, array lengths, etc.). The value
// can be variable at runtime, but will be promotable to
// static memory if we can prove it is actually constant.
Var,
}
use std::mem;
struct CheckCrateVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mode: Mode,
qualif: ConstQualif,
rvalue_borrows: NodeMap<hir::Mutability>,
in_fn: bool,
promotable: bool,
mut_rvalue_borrows: NodeSet,
param_env: ty::ParameterEnvironment<'tcx>,
}
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R
where F: FnOnce(&mut CheckCrateVisitor<'a, 'gcx>) -> R
{
let (old_mode, old_qualif) = (self.mode, self.qualif);
self.mode = mode;
self.qualif = ConstQualif::empty();
let r = f(self);
self.mode = old_mode;
self.qualif = old_qualif;
r
}
fn with_euv<F, R>(&mut self, item_id: Option<ast::NodeId>, f: F) -> R
where F: for<'b, 'tcx> FnOnce(&mut euv::ExprUseVisitor<'b, 'gcx, 'tcx>) -> R
{
let param_env = match item_id {
Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
None => self.tcx.empty_parameter_environment(),
};
self.tcx
.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable)
.enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
}
fn global_expr(&mut self, mode: Mode, expr: &'gcx hir::Expr) -> ConstQualif {
assert!(mode != Mode::Var);
match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry.
entry.insert(ConstQualif::empty());
}
}
fn check_const_eval(&self, expr: &'gcx hir::Expr) {
if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
match err.kind {
UnimplementedConstVal(_) => {}
@ -124,184 +80,78 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
}
}
}
self.with_mode(mode, |this| {
this.with_euv(None, |euv| euv.consume_expr(expr));
this.visit_expr(expr);
this.qualif
})
}
fn fn_like(&mut self,
fk: FnKind<'gcx>,
fd: &'gcx hir::FnDecl,
b: hir::ExprId,
s: Span,
fn_id: ast::NodeId)
-> ConstQualif {
match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry.
entry.insert(ConstQualif::empty());
}
// Adds the worst effect out of all the values of one type.
fn add_type(&mut self, ty: Ty<'gcx>) {
if ty.type_contents(self.tcx).interior_unsafe() {
self.promotable = false;
}
let mode = match fk {
FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
=> Mode::ConstFn,
FnKind::Method(_, m, ..) => {
if m.constness == hir::Constness::Const {
Mode::ConstFn
} else {
Mode::Var
}
}
_ => Mode::Var,
if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
self.promotable = false;
}
}
fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
self.add_type(ret_ty);
self.promotable &= if let Some(fn_id) = self.tcx.map.as_local_node_id(def_id) {
FnLikeNode::from_node(self.tcx.map.get(fn_id)).map_or(false, |fn_like| {
fn_like.constness() == hir::Constness::Const
})
} else {
self.tcx.sess.cstore.is_const_fn(def_id)
};
let qualif = self.with_mode(mode, |this| {
let body = this.tcx.map.expr(b);
this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, body));
intravisit::walk_fn(this, fk, fd, b, s, fn_id);
this.qualif
});
// Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
// and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
qualif
}
fn add_qualif(&mut self, qualif: ConstQualif) {
self.qualif = self.qualif | qualif;
}
/// Returns true if the call is to a const fn or method.
fn handle_const_fn_call(&mut self, _expr: &hir::Expr, def_id: DefId, ret_ty: Ty<'gcx>) -> bool {
match lookup_const_fn_by_id(self.tcx, def_id) {
Some(ConstFnNode::Local(fn_like)) => {
let qualif = self.fn_like(fn_like.kind(),
fn_like.decl(),
fn_like.body(),
fn_like.span(),
fn_like.id());
self.add_qualif(qualif);
if ret_ty.type_contents(self.tcx).interior_unsafe() {
self.add_qualif(ConstQualif::MUTABLE_MEM);
}
true
},
Some(ConstFnNode::Inlined(ii)) => {
let node_id = ii.body.id;
let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(node_id) {
Entry::Occupied(entry) => *entry.get(),
_ => bug!("const qualif entry missing for inlined item")
};
self.add_qualif(qualif);
if ret_ty.type_contents(self.tcx).interior_unsafe() {
self.add_qualif(ConstQualif::MUTABLE_MEM);
}
true
},
None => false
}
}
fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
match self.rvalue_borrows.entry(id) {
Entry::Occupied(mut entry) => {
// Merge the two borrows, taking the most demanding
// one, mutability-wise.
if mutbl == hir::MutMutable {
entry.insert(mutbl);
}
}
Entry::Vacant(entry) => {
entry.insert(mutbl);
}
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.tcx.map)
NestedVisitorMap::None
}
fn visit_item(&mut self, i: &'tcx hir::Item) {
debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
assert_eq!(self.mode, Mode::Var);
match i.node {
hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
self.global_expr(Mode::Static, &expr);
}
hir::ItemStatic(_, hir::MutMutable, ref expr) => {
self.global_expr(Mode::StaticMut, &expr);
}
hir::ItemConst(_, ref expr) => {
self.global_expr(Mode::Const, &expr);
}
hir::ItemEnum(ref enum_definition, _) => {
for var in &enum_definition.variants {
if let Some(ref ex) = var.node.disr_expr {
self.global_expr(Mode::Const, &ex);
}
}
}
_ => {
intravisit::walk_item(self, i);
fn visit_nested_body(&mut self, body: hir::BodyId) {
match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body.node_id) {
Entry::Occupied(_) => return,
Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry.
entry.insert(false);
}
}
}
fn visit_trait_item(&mut self, t: &'tcx hir::TraitItem) {
match t.node {
hir::ConstTraitItem(_, ref default) => {
if let Some(ref expr) = *default {
self.global_expr(Mode::Const, &expr);
} else {
intravisit::walk_trait_item(self, t);
}
}
_ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
let item_id = self.tcx.map.body_owner(body);
let outer_in_fn = self.in_fn;
self.in_fn = match MirSource::from_node(self.tcx, item_id) {
MirSource::Fn(_) => true,
_ => false
};
let body = self.tcx.map.body(body);
if !self.in_fn {
self.check_const_eval(&body.value);
}
}
fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
match i.node {
hir::ImplItemKind::Const(_, ref expr) => {
self.global_expr(Mode::Const, &expr);
}
_ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
}
}
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
let outer_param_env = mem::replace(&mut self.param_env, param_env);
self.tcx.infer_ctxt(None, Some(self.param_env.clone()), Reveal::NotSpecializable)
.enter(|infcx| euv::ExprUseVisitor::new(self, &infcx).consume_body(body));
fn visit_fn(&mut self,
fk: FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
b: hir::ExprId,
s: Span,
fn_id: ast::NodeId) {
self.fn_like(fk, fd, b, s, fn_id);
self.visit_body(body);
self.param_env = outer_param_env;
self.in_fn = outer_in_fn;
}
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
match p.node {
PatKind::Lit(ref lit) => {
self.global_expr(Mode::Const, &lit);
self.check_const_eval(lit);
}
PatKind::Range(ref start, ref end) => {
self.global_expr(Mode::Const, &start);
self.global_expr(Mode::Const, &end);
self.check_const_eval(start);
self.check_const_eval(end);
match compare_lit_exprs(self.tcx, p.span, start, end) {
Ok(Ordering::Less) |
@ -315,119 +165,60 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
Err(ErrorReported) => {}
}
}
_ => intravisit::walk_pat(self, p),
_ => {}
}
intravisit::walk_pat(self, p);
}
fn visit_block(&mut self, block: &'tcx hir::Block) {
// Check all statements in the block
for stmt in &block.stmts {
match stmt.node {
hir::StmtDecl(ref decl, _) => {
match decl.node {
hir::DeclLocal(_) => {}
// Item statements are allowed
hir::DeclItem(_) => continue,
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
match stmt.node {
hir::StmtDecl(ref decl, _) => {
match decl.node {
hir::DeclLocal(_) => {
self.promotable = false;
}
// Item statements are allowed
hir::DeclItem(_) => {}
}
hir::StmtExpr(..) => {}
hir::StmtSemi(..) => {}
}
self.add_qualif(ConstQualif::NOT_CONST);
hir::StmtExpr(..) |
hir::StmtSemi(..) => {
self.promotable = false;
}
}
intravisit::walk_block(self, block);
intravisit::walk_stmt(self, stmt);
}
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
let mut outer = self.qualif;
self.qualif = ConstQualif::empty();
let outer = self.promotable;
self.promotable = true;
let node_ty = self.tcx.tables().node_id_to_type(ex.id);
check_expr(self, ex, node_ty);
check_adjustments(self, ex);
// Special-case some expressions to avoid certain flags bubbling up.
match ex.node {
hir::ExprCall(ref callee, ref args) => {
for arg in args {
self.visit_expr(&arg)
}
let inner = self.qualif;
self.visit_expr(&callee);
// The callee's size doesn't count in the call.
let added = self.qualif - inner;
self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
}
hir::ExprRepeat(ref element, _) => {
self.visit_expr(&element);
// The count is checked elsewhere (typeck).
let count = match node_ty.sty {
ty::TyArray(_, n) => n,
_ => bug!(),
};
// [element; 0] is always zero-sized.
if count == 0 {
self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
if let hir::ExprMatch(ref discr, ref arms, _) = ex.node {
// Compute the most demanding borrow from all the arms'
// patterns and set that on the discriminator.
let mut mut_borrow = false;
for pat in arms.iter().flat_map(|arm| &arm.pats) {
if self.mut_rvalue_borrows.remove(&pat.id) {
mut_borrow = true;
}
}
hir::ExprMatch(ref discr, ref arms, _) => {
// Compute the most demanding borrow from all the arms'
// patterns and set that on the discriminator.
let mut borrow = None;
for pat in arms.iter().flat_map(|arm| &arm.pats) {
let pat_borrow = self.rvalue_borrows.remove(&pat.id);
match (borrow, pat_borrow) {
(None, _) |
(_, Some(hir::MutMutable)) => {
borrow = pat_borrow;
}
_ => {}
}
}
if let Some(mutbl) = borrow {
self.record_borrow(discr.id, mutbl);
}
intravisit::walk_expr(self, ex);
if mut_borrow {
self.mut_rvalue_borrows.insert(discr.id);
}
_ => intravisit::walk_expr(self, ex),
}
intravisit::walk_expr(self, ex);
// Handle borrows on (or inside the autorefs of) this expression.
match self.rvalue_borrows.remove(&ex.id) {
Some(hir::MutImmutable) => {
// Constants cannot be borrowed if they contain interior mutability as
// it means that our "silent insertion of statics" could change
// initializer values (very bad).
// If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
// propagated from another error, so erroring again would be just noise.
let tc = node_ty.type_contents(self.tcx);
if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | ConstQualif::NOT_CONST;
}
// If the reference has to be 'static, avoid in-place initialization
// as that will end up pointing to the stack instead.
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
Some(hir::MutMutable) => {
// `&mut expr` means expr could be mutated, unless it's zero-sized.
if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
if self.mode == Mode::Var {
outer = outer | ConstQualif::NOT_CONST;
self.add_qualif(ConstQualif::MUTABLE_MEM);
}
}
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
None => {}
if self.mut_rvalue_borrows.remove(&ex.id) {
self.promotable = false;
}
if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) {
if self.in_fn && self.promotable {
match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
Ok(_) => {}
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
@ -448,9 +239,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
}
}
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
// Don't propagate certain flags.
self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
self.tcx.rvalue_promotable_to_static.borrow_mut().insert(ex.id, self.promotable);
self.promotable &= outer;
}
}
@ -463,7 +253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
match node_ty.sty {
ty::TyAdt(def, _) if def.has_dtor() => {
v.add_qualif(ConstQualif::NEEDS_DROP);
v.promotable = false;
}
_ => {}
}
@ -473,17 +263,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
hir::ExprUnary(..) |
hir::ExprBinary(..) |
hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
hir::ExprBox(_) => {
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
hir::ExprUnary(op, ref inner) => {
match v.tcx.tables().node_id_to_type(inner.id).sty {
ty::TyRawPtr(_) => {
assert!(op == hir::UnDeref);
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
_ => {}
}
@ -495,7 +285,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
op.node == hir::BiLe || op.node == hir::BiLt ||
op.node == hir::BiGe || op.node == hir::BiGt);
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
_ => {}
}
@ -505,7 +295,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
match v.tcx.cast_kinds.borrow().get(&from.id) {
None => span_bug!(e.span, "no kind for cast"),
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
_ => {}
}
@ -513,33 +303,24 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
hir::ExprPath(ref qpath) => {
let def = v.tcx.tables().qpath_def(qpath, e.id);
match def {
Def::VariantCtor(_, CtorKind::Const) => {
// Size is determined by the whole enum, may be non-zero.
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Def::VariantCtor(..) | Def::StructCtor(..) |
Def::Fn(..) | Def::Method(..) => {}
Def::Static(..) => {
match v.mode {
Mode::Static | Mode::StaticMut => {}
Mode::Const | Mode::ConstFn => {}
Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
}
}
Def::Const(did) | Def::AssociatedConst(did) => {
let substs = Some(v.tcx.tables().node_id_item_substs(e.id)
.unwrap_or_else(|| v.tcx.intern_substs(&[])));
if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
let inner = v.global_expr(Mode::Const, expr);
v.add_qualif(inner);
}
}
Def::Local(..) if v.mode == Mode::ConstFn => {
// Sadly, we can't determine whether the types are zero-sized.
v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
Def::AssociatedConst(_) => v.add_type(node_ty),
Def::Const(did) => {
v.promotable &= if let Some(node_id) = v.tcx.map.as_local_node_id(did) {
match v.tcx.map.expect_item(node_id).node {
hir::ItemConst(_, body) => {
v.visit_nested_body(body);
v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
}
_ => false
}
} else {
v.tcx.sess.cstore.const_is_rvalue_promotable_to_static(did)
};
}
_ => {
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
}
}
@ -560,65 +341,48 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
} else {
Def::Err
};
let is_const = match def {
match def {
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => {
// `NON_ZERO_SIZED` is about the call result, not about the ctor itself.
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
true
}
Def::VariantCtor(_, CtorKind::Fn) => {}
Def::Fn(did) => {
v.handle_const_fn_call(e, did, node_ty)
v.handle_const_fn_call(did, node_ty)
}
Def::Method(did) => {
match v.tcx.associated_item(did).container {
ty::ImplContainer(_) => {
v.handle_const_fn_call(e, did, node_ty)
v.handle_const_fn_call(did, node_ty)
}
ty::TraitContainer(_) => false
ty::TraitContainer(_) => v.promotable = false
}
}
_ => false
};
if !is_const {
v.add_qualif(ConstQualif::NOT_CONST);
_ => v.promotable = false
}
}
hir::ExprMethodCall(..) => {
let method = v.tcx.tables().method_map[&method_call];
let is_const = match v.tcx.associated_item(method.def_id).container {
ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
ty::TraitContainer(_) => false
};
if !is_const {
v.add_qualif(ConstQualif::NOT_CONST);
match v.tcx.associated_item(method.def_id).container {
ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
ty::TraitContainer(_) => v.promotable = false
}
}
hir::ExprStruct(..) => {
if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
// unsafe_cell_type doesn't necessarily exist with no_core
if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
v.add_qualif(ConstQualif::MUTABLE_MEM);
v.promotable = false;
}
}
}
hir::ExprLit(_) |
hir::ExprAddrOf(..) => {
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
hir::ExprRepeat(..) => {
v.add_qualif(ConstQualif::PREFER_IN_PLACE);
}
hir::ExprAddrOf(..) |
hir::ExprRepeat(..) => {}
hir::ExprClosure(..) => {
// Paths in constant contexts cannot refer to local variables,
// as there are none, and thus closures can't have upvars there.
if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
assert!(v.mode == Mode::Var,
"global closures can't capture anything");
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
}
@ -647,7 +411,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
hir::ExprAssign(..) |
hir::ExprAssignOp(..) |
hir::ExprInlineAsm(..) => {
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
}
}
@ -666,7 +430,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
Some(Adjust::DerefRef { autoderefs, .. }) => {
if (0..autoderefs as u32)
.any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
v.add_qualif(ConstQualif::NOT_CONST);
v.promotable = false;
}
}
}
@ -676,9 +440,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
&mut CheckCrateVisitor {
tcx: tcx,
mode: Mode::Var,
qualif: ConstQualif::NOT_CONST,
rvalue_borrows: NodeMap(),
in_fn: false,
promotable: false,
mut_rvalue_borrows: NodeSet(),
param_env: tcx.empty_parameter_environment(),
}.as_deep_visitor());
tcx.sess.abort_if_errors();
}
@ -687,24 +452,9 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
fn consume(&mut self,
_consume_id: ast::NodeId,
_consume_span: Span,
cmt: mc::cmt,
_mode: euv::ConsumeMode) {
let mut cur = &cmt;
loop {
match cur.cat {
Categorization::StaticItem => {
break;
}
Categorization::Deref(ref cmt, ..) |
Categorization::Downcast(ref cmt, _) |
Categorization::Interior(ref cmt, _) => cur = cmt,
_cmt: mc::cmt,
_mode: euv::ConsumeMode) {}
Categorization::Rvalue(..) |
Categorization::Upvar(..) |
Categorization::Local(..) => break,
}
}
}
fn borrow(&mut self,
borrow_id: ast::NodeId,
_borrow_span: Span,
@ -731,21 +481,9 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
// Ignore the dummy immutable borrow created by EUV.
break;
}
let mutbl = bk.to_mutbl_lossy();
if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
// Mutable slices are the only `&mut` allowed in
// globals, but only in `static mut`, nowhere else.
// FIXME: This exception is really weird... there isn't
// any fundamental reason to restrict this based on
// type of the expression. `&mut [1]` has exactly the
// same representation as &mut 1.
match cmt.ty.sty {
ty::TyArray(..) |
ty::TySlice(_) => break,
_ => {}
}
if bk.to_mutbl_lossy() == hir::MutMutable {
self.mut_rvalue_borrows.insert(borrow_id);
}
self.record_borrow(borrow_id, mutbl);
break;
}
Categorization::StaticItem => {

View file

@ -115,6 +115,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
self.visit_item(nested_item)
}
fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id);
self.visit_trait_item(nested_trait_item)
}
fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
self.visit_impl_item(nested_impl_item)
@ -172,7 +177,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn visit_fn(&mut self,
fk: hir_visit::FnKind<'v>,
fd: &'v hir::FnDecl,
b: hir::ExprId,
b: hir::BodyId,
s: Span,
id: NodeId) {
self.record("FnDecl", Id::None, fd);

View file

@ -84,7 +84,7 @@ impl<'a, 'ast> Visitor<'ast> for CheckLoopVisitor<'a, 'ast> {
self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
}
hir::ExprClosure(.., b, _) => {
self.with_context(Closure, |v| v.visit_body(b));
self.with_context(Closure, |v| v.visit_nested_body(b));
}
hir::ExprBreak(label, ref opt_expr) => {
if opt_expr.is_some() {

View file

@ -39,7 +39,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
fn visit_fn(&mut self,
fk: intravisit::FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
b: hir::ExprId,
b: hir::BodyId,
s: Span,
fn_id: ast::NodeId) {
// FIXME (@jroesch) change this to be an inference context
@ -50,9 +50,9 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
tcx: infcx.tcx,
param_env: &param_env
};
let body = infcx.tcx.map.expr(b);
let body = infcx.tcx.map.body(b);
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
euv.walk_fn(fd, body);
euv.consume_body(body);
});
intravisit::walk_fn(self, fk, fd, b, s, fn_id)
}

View file

@ -30,7 +30,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
// variant definitions with the discriminant expression that applies to
// each one. If the variant uses the default values (starting from `0`),
// then `None` is stored.
discriminant_map: NodeMap<Option<&'ast hir::Expr>>,
discriminant_map: NodeMap<Option<hir::BodyId>>,
detected_recursive_ids: NodeSet,
}
@ -66,7 +66,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
match ti.node {
hir::ConstTraitItem(_, ref default) => {
hir::TraitItemKind::Const(_, ref default) => {
if let Some(_) = *default {
let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span);
recursion_visitor.visit_trait_item(ti);
@ -108,7 +108,7 @@ struct CheckItemRecursionVisitor<'a, 'b: 'a, 'ast: 'b> {
root_span: &'b Span,
sess: &'b Session,
ast_map: &'b ast_map::Map<'ast>,
discriminant_map: &'a mut NodeMap<Option<&'ast hir::Expr>>,
discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
idstack: Vec<ast::NodeId>,
detected_recursive_ids: &'a mut NodeSet,
}
@ -189,7 +189,7 @@ impl<'a, 'b: 'a, 'ast: 'b> CheckItemRecursionVisitor<'a, 'b, 'ast> {
variant_stack.push(variant.node.data.id());
// When we find an expression, every variant currently on the stack
// is affected by that expression.
if let Some(ref expr) = variant.node.disr_expr {
if let Some(expr) = variant.node.disr_expr {
for id in &variant_stack {
self.discriminant_map.insert(*id, Some(expr));
}
@ -226,19 +226,15 @@ impl<'a, 'b: 'a, 'ast: 'b> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'b, '
_: &'ast hir::Generics,
_: ast::NodeId) {
let variant_id = variant.node.data.id();
let maybe_expr;
if let Some(get_expr) = self.discriminant_map.get(&variant_id) {
// This is necessary because we need to let the `discriminant_map`
// borrow fall out of scope, so that we can reborrow farther down.
maybe_expr = (*get_expr).clone();
} else {
let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| {
span_bug!(variant.span,
"`check_static_recursion` attempted to visit \
variant with unknown discriminant")
}
});
// If `maybe_expr` is `None`, that's because no discriminant is
// specified that affects this variant. Thus, no risk of recursion.
if let Some(expr) = maybe_expr {
let expr = &self.ast_map.body(expr).value;
self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span);
}
}

View file

@ -33,6 +33,9 @@ impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -160,21 +160,19 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
}
hir::ItemImpl(.., None, _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
if impl_item.vis == hir::Public {
self.update(impl_item.id, item_level);
if impl_item_ref.vis == hir::Public {
self.update(impl_item_ref.id.node_id, item_level);
}
}
}
hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
self.update(impl_item.id, item_level);
self.update(impl_item_ref.id.node_id, item_level);
}
}
hir::ItemTrait(.., ref trait_items) => {
for trait_item in trait_items {
self.update(trait_item.id, item_level);
hir::ItemTrait(.., ref trait_item_refs) => {
for trait_item_ref in trait_item_refs {
self.update(trait_item_ref.id.node_id, item_level);
}
}
hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => {
@ -214,15 +212,16 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
self.reach(item.id).generics().predicates().item_type();
}
}
hir::ItemTrait(.., ref trait_items) => {
hir::ItemTrait(.., ref trait_item_refs) => {
if item_level.is_some() {
self.reach(item.id).generics().predicates();
for trait_item in trait_items {
let mut reach = self.reach(trait_item.id);
for trait_item_ref in trait_item_refs {
let mut reach = self.reach(trait_item_ref.id.node_id);
reach.generics().predicates();
if let hir::TypeTraitItem(_, None) = trait_item.node {
if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
!trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
reach.item_type();
@ -231,12 +230,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
}
}
// Visit everything except for private impl items
hir::ItemImpl(.., ref trait_ref, _, ref impl_items) => {
hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
if item_level.is_some() {
self.reach(item.id).generics().predicates().impl_trait_ref();
for impl_item in impl_items {
let id = impl_item.id.node_id;
for impl_item_ref in impl_item_refs {
let id = impl_item_ref.id.node_id;
if trait_ref.is_some() || self.get(id).is_some() {
self.reach(id).generics().predicates().item_type();
}
@ -789,22 +788,19 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
hir::ImplItemKind::Const(..) => {
if self.item_is_public(&impl_item.id, &impl_item.vis) {
if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
match impl_item_ref.kind {
hir::AssociatedItemKind::Const => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
}
hir::ImplItemKind::Method(ref sig, _) => {
if !sig.decl.has_self() &&
self.item_is_public(&impl_item.id, &impl_item.vis) {
hir::AssociatedItemKind::Method { has_self: false } => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
_ => {}
}
_ => {}
}
}
if found_pub_static {
@ -1092,14 +1088,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
self.inner_visibility = item_visibility;
intravisit::walk_item(self, item);
}
hir::ItemTrait(.., ref trait_items) => {
hir::ItemTrait(.., ref trait_item_refs) => {
self.check(item.id, item_visibility).generics().predicates();
for trait_item in trait_items {
let mut check = self.check(trait_item.id, item_visibility);
for trait_item_ref in trait_item_refs {
let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
check.generics().predicates();
if let hir::TypeTraitItem(_, None) = trait_item.node {
if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
!trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
check.item_type();

View file

@ -571,6 +571,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
fn visit_ty(&mut self, ty: &'tcx Ty) {
if let TyKind::Path(ref qself, ref path) = ty.node {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
} else if let TyKind::ImplicitSelf = ty.node {
let self_ty = keywords::SelfType.ident();
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
.map_or(Def::Err, |d| d.def());
self.record_def(ty.id, PathResolution::new(def));
} else if let TyKind::Array(ref element, ref length) = ty.node {
self.visit_ty(element);
self.with_constant_rib(|this| {
this.visit_expr(length);
});
return;
}
visit::walk_ty(self, ty);
}
@ -741,6 +752,13 @@ impl<'a> LexicalScopeBinding<'a> {
_ => None,
}
}
fn def(self) -> Def {
match self {
LexicalScopeBinding::Item(binding) => binding.def(),
LexicalScopeBinding::Def(def) => def,
}
}
}
#[derive(Clone)]
@ -2721,6 +2739,13 @@ impl<'a> Resolver<'a> {
self.visit_ty(ty);
}
}
ExprKind::Repeat(ref element, ref count) => {
self.visit_expr(element);
self.with_constant_rib(|this| {
this.visit_expr(count);
});
}
ExprKind::Call(ref callee, ref arguments) => {
self.resolve_expr(callee, Some(&expr.node));
for argument in arguments {

View file

@ -349,7 +349,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
match item.node {
hir::ItemImpl(.., ref ty, _) => {
let mut result = String::from("<");
result.push_str(&rustc::hir::print::ty_to_string(&ty));
result.push_str(&self.tcx.map.node_to_pretty_string(ty.id));
let trait_id = self.tcx.trait_id_of_impl(impl_id);
let mut decl_id = None;

View file

@ -202,8 +202,6 @@ use rustc::mir::{self, Location};
use rustc::mir::visit as mir_visit;
use rustc::mir::visit::Visitor as MirVisitor;
use rustc_const_eval as const_eval;
use syntax::abi::Abi;
use syntax_pos::DUMMY_SP;
use base::custom_coerce_unsize_info;
@ -344,19 +342,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
recursion_depth_reset = None;
// Scan the MIR in order to find function calls, closures, and
// drop-glue
let mir = scx.tcx().item_mir(def_id);
let empty_substs = scx.empty_substs_for_def_id(def_id);
let visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
output: &mut neighbors,
param_substs: empty_substs
};
visit_mir_and_promoted(visitor, &mir);
collect_neighbours(scx, Instance::mono(scx, def_id), &mut neighbors);
}
TransItem::Fn(instance) => {
// Keep track of the monomorphization recursion depth
@ -365,18 +351,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
recursion_depths));
check_type_length_limit(scx.tcx(), instance);
// Scan the MIR in order to find function calls, closures, and
// drop-glue
let mir = scx.tcx().item_mir(instance.def);
let visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
output: &mut neighbors,
param_substs: instance.substs
};
visit_mir_and_promoted(visitor, &mir);
collect_neighbours(scx, instance, &mut neighbors);
}
}
@ -563,33 +538,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
// This is not a callee, but we still have to look for
// references to `const` items
if let mir::Literal::Item { def_id, substs } = constant.literal {
let tcx = self.scx.tcx();
let substs = monomorphize::apply_param_substs(self.scx,
self.param_substs,
&substs);
// If the constant referred to here is an associated
// item of a trait, we need to resolve it to the actual
// constant in the corresponding impl. Luckily
// const_eval::lookup_const_by_id() does that for us.
if let Some((expr, _)) = const_eval::lookup_const_by_id(tcx,
def_id,
Some(substs)) {
// The hir::Expr we get here is the initializer of
// the constant, what we really want is the item
// DefId.
let const_node_id = tcx.map.get_parent(expr.id);
let def_id = if tcx.map.is_inlined_node_id(const_node_id) {
tcx.sess.cstore.defid_for_inlined_node(const_node_id).unwrap()
} else {
tcx.map.local_def_id(const_node_id)
};
collect_const_item_neighbours(self.scx,
def_id,
substs,
self.output);
}
let instance = Instance::new(def_id, substs).resolve_const(self.scx);
collect_neighbours(self.scx, instance, self.output);
}
None
@ -1122,6 +1076,11 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
}
}
fn visit_trait_item(&mut self, _: &'v hir::TraitItem) {
// Even if there's a default body with no explicit generics,
// it's still generic over some `Self: Trait`, so not a root.
}
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Method(hir::MethodSig {
@ -1228,29 +1187,20 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
}
}
// There are no translation items for constants themselves but their
// initializers might still contain something that produces translation items,
// such as cast that introduce a new vtable.
fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
output: &mut Vec<TransItem<'tcx>>)
/// Scan the MIR in order to find function calls, closures, and drop-glue
fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
instance: Instance<'tcx>,
output: &mut Vec<TransItem<'tcx>>)
{
// Scan the MIR in order to find function calls, closures, and
// drop-glue
let mir = scx.tcx().item_mir(def_id);
let mir = scx.tcx().item_mir(instance.def);
let visitor = MirNeighborCollector {
let mut visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
output: output,
param_substs: substs
param_substs: instance.substs
};
visit_mir_and_promoted(visitor, &mir);
}
fn visit_mir_and_promoted<'tcx, V: MirVisitor<'tcx>>(mut visitor: V, mir: &mir::Mir<'tcx>) {
visitor.visit_mir(&mir);
for promoted in &mir.promoted {
visitor.visit_mir(promoted);

View file

@ -737,14 +737,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local().drop_glues
}
pub fn local_node_for_inlined_defid<'a>(&'a self, def_id: DefId) -> Option<ast::NodeId> {
self.sess().cstore.local_node_for_inlined_defid(def_id)
}
pub fn defid_for_inlined_node<'a>(&'a self, node_id: ast::NodeId) -> Option<DefId> {
self.sess().cstore.defid_for_inlined_node(node_id)
}
pub fn instances<'a>(&'a self) -> &'a RefCell<FxHashMap<Instance<'tcx>, ValueRef>> {
&self.local().instances
}

View file

@ -18,7 +18,6 @@ use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize;
use rustc::mir;
use rustc::mir::tcx::LvalueTy;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::subst::Substs;
@ -36,7 +35,7 @@ use type_::Type;
use value::Value;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::Span;
use std::fmt;
use std::ptr;
@ -238,24 +237,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
}
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
mut instance: Instance<'tcx>,
instance: Instance<'tcx>,
args: IndexVec<mir::Local, Const<'tcx>>)
-> Result<Const<'tcx>, ConstEvalErr> {
// Try to resolve associated constants.
if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
let trait_ref = ty::Binder(trait_ref);
let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
if let traits::VtableImpl(vtable_impl) = vtable {
let name = ccx.tcx().item_name(instance.def);
let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id)
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
if let Some(ac) = ac {
instance = Instance::new(ac.def_id, vtable_impl.substs);
}
}
}
let instance = instance.resolve_const(ccx.shared());
let mir = ccx.tcx().item_mir(instance.def);
MirConstContext::new(ccx, &mir, instance.substs, args).trans()
}

View file

@ -11,11 +11,15 @@
use common::*;
use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize;
use rustc::traits;
use rustc::ty::fold::{TypeFolder, TypeFoldable};
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::ppaux;
use rustc::util::common::MemoizationMap;
use syntax::codemap::DUMMY_SP;
use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -30,15 +34,35 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
}
}
impl<'tcx> Instance<'tcx> {
impl<'a, 'tcx> Instance<'tcx> {
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Instance<'tcx> {
assert!(substs.regions().all(|&r| r == ty::ReErased));
Instance { def: def_id, substs: substs }
}
pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
pub fn mono(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
Instance::new(def_id, scx.empty_substs_for_def_id(def_id))
}
/// For associated constants from traits, return the impl definition.
pub fn resolve_const(&self, scx: &SharedCrateContext<'a, 'tcx>) -> Self {
if let Some(trait_id) = scx.tcx().trait_of_item(self.def) {
let trait_ref = ty::TraitRef::new(trait_id, self.substs);
let trait_ref = ty::Binder(trait_ref);
let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
if let traits::VtableImpl(vtable_impl) = vtable {
let name = scx.tcx().item_name(self.def);
let ac = scx.tcx().associated_items(vtable_impl.impl_def_id)
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
if let Some(ac) = ac {
return Instance::new(ac.def_id, vtable_impl.substs);
}
}
}
*self
}
}
/// Monomorphizes a type from the AST by first applying the in-scope

View file

@ -50,10 +50,9 @@
use rustc_const_eval::eval_length;
use rustc_data_structures::accumulate_vec::AccumulateVec;
use hir::{self, SelfKind};
use hir;
use hir::def::Def;
use hir::def_id::DefId;
use hir::print as pprust;
use middle::resolve_lifetime as rl;
use rustc::lint;
use rustc::ty::subst::{Kind, Subst, Substs};
@ -227,6 +226,7 @@ pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
}
fn report_elision_failure(
tcx: TyCtxt,
db: &mut DiagnosticBuilder,
params: Vec<ElisionFailureInfo>)
{
@ -241,13 +241,14 @@ fn report_elision_failure(
for (i, info) in elided_params.into_iter().enumerate() {
let ElisionFailureInfo {
name, lifetime_count: n, have_bound_regions
parent, index, lifetime_count: n, have_bound_regions
} = info;
let help_name = if name.is_empty() {
format!("argument {}", i + 1)
let help_name = if let Some(body) = parent {
let arg = &tcx.map.body(body).arguments[index];
format!("`{}`", tcx.map.node_to_pretty_string(arg.pat.id))
} else {
format!("`{}`", name)
format!("argument {}", index + 1)
};
m.push_str(&(if n == 1 {
@ -315,7 +316,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
err.span_label(ampersand_span, &format!("expected lifetime parameter"));
if let Some(params) = params {
report_elision_failure(&mut err, params);
report_elision_failure(self.tcx(), &mut err, params);
}
err.emit();
ty::ReStatic
@ -540,15 +541,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
/// corresponding to each input type/pattern.
fn find_implied_output_region<I>(&self,
input_tys: &[Ty<'tcx>],
input_pats: I) -> ElidedLifetime
where I: Iterator<Item=String>
parent: Option<hir::BodyId>,
input_indices: I) -> ElidedLifetime
where I: Iterator<Item=usize>
{
let tcx = self.tcx();
let mut lifetimes_for_params = Vec::with_capacity(input_tys.len());
let mut possible_implied_output_region = None;
let mut lifetimes = 0;
for input_type in input_tys.iter() {
for (input_type, index) in input_tys.iter().zip(input_indices) {
let mut regions = FxHashSet();
let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
@ -564,11 +566,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
possible_implied_output_region = regions.iter().cloned().next();
}
// Use a placeholder for `name` because computing it can be
// expensive and we don't want to do it until we know it's
// necessary.
lifetimes_for_params.push(ElisionFailureInfo {
name: String::new(),
parent: parent,
index: index,
lifetime_count: regions.len(),
have_bound_regions: have_bound_regions
});
@ -577,11 +577,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
if lifetimes == 1 {
Ok(*possible_implied_output_region.unwrap())
} else {
// Fill in the expensive `name` fields now that we know they're
// needed.
for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats) {
info.name = input_pat;
}
Err(Some(lifetimes_for_params))
}
}
@ -618,8 +613,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
}));
let input_params = iter::repeat(String::new()).take(inputs.len());
let implied_output_region = self.find_implied_output_region(&inputs, input_params);
let input_params = 0..inputs.len();
let implied_output_region = self.find_implied_output_region(&inputs, None, input_params);
let (output, output_span) = match data.output {
Some(ref output_ty) => {
@ -689,7 +684,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
}
_ => {
span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
path);
self.tcx().map.node_to_pretty_string(trait_ref.ref_id));
}
}
}
@ -976,7 +971,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let mut err = struct_span_err!(tcx.sess, ty.span, E0178,
"expected a path on the left-hand side \
of `+`, not `{}`",
pprust::ty_to_string(ty));
tcx.map.node_to_pretty_string(ty.id));
err.span_label(ty.span, &format!("expected a path"));
let hi = bounds.iter().map(|x| match *x {
hir::TraitTyParamBound(ref tr, _) => tr.span.hi,
@ -988,22 +983,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
expn_id: ty.span.expn_id,
});
match (&ty.node, full_span) {
(&hir::TyRptr(None, ref mut_ty), Some(full_span)) => {
let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
(&hir::TyRptr(ref lifetime, ref mut_ty), Some(full_span)) => {
let ty_str = hir::print::to_string(&tcx.map, |s| {
use syntax::print::pp::word;
use syntax::print::pprust::PrintState;
word(&mut s.s, "&")?;
s.print_opt_lifetime(lifetime)?;
s.print_mutability(mut_ty.mutbl)?;
s.popen()?;
s.print_type(&mut_ty.ty)?;
s.print_bounds(" +", bounds)?;
s.pclose()
});
err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
format!("&{}({} +{})",
mutbl_str,
pprust::ty_to_string(&mut_ty.ty),
pprust::bounds_to_string(bounds)));
}
(&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
format!("&{} {}({} +{})",
pprust::lifetime_to_string(lt),
mutbl_str,
pprust::ty_to_string(&mut_ty.ty),
pprust::bounds_to_string(bounds)));
ty_str);
}
_ => {
@ -1572,6 +1566,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
bf.abi,
None,
&bf.decl,
None,
anon_scope,
anon_scope);
@ -1664,8 +1659,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
};
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
}
hir::TyArray(ref ty, ref e) => {
if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
hir::TyArray(ref ty, length) => {
let e = &tcx.map.body(length).value;
if let Ok(length) = eval_length(tcx.global_tcx(), e, "array length") {
tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
} else {
self.tcx().types.err
@ -1695,26 +1691,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
pub fn ty_of_arg(&self,
rscope: &RegionScope,
a: &hir::Arg,
ty: &hir::Ty,
expected_ty: Option<Ty<'tcx>>)
-> Ty<'tcx>
{
match a.ty.node {
match ty.node {
hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
hir::TyInfer => self.ty_infer(a.ty.span),
_ => self.ast_ty_to_ty(rscope, &a.ty),
hir::TyInfer => self.ty_infer(ty.span),
_ => self.ast_ty_to_ty(rscope, ty),
}
}
pub fn ty_of_method(&self,
sig: &hir::MethodSig,
untransformed_self_ty: Ty<'tcx>,
opt_self_value_ty: Option<Ty<'tcx>>,
body: Option<hir::BodyId>,
anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx> {
self.ty_of_method_or_bare_fn(sig.unsafety,
sig.abi,
Some(untransformed_self_ty),
opt_self_value_ty,
&sig.decl,
body,
None,
anon_scope)
}
@ -1723,16 +1721,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
unsafety: hir::Unsafety,
abi: abi::Abi,
decl: &hir::FnDecl,
body: hir::BodyId,
anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx> {
self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope)
self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, Some(body), None, anon_scope)
}
fn ty_of_method_or_bare_fn(&self,
unsafety: hir::Unsafety,
abi: abi::Abi,
opt_untransformed_self_ty: Option<Ty<'tcx>>,
opt_self_value_ty: Option<Ty<'tcx>>,
decl: &hir::FnDecl,
body: Option<hir::BodyId>,
arg_anon_scope: Option<AnonTypeScope>,
ret_anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx>
@ -1743,38 +1743,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
// declaration are bound to that function type.
let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope);
// `implied_output_region` is the region that will be assumed for any
// region parameters in the return type. In accordance with the rules for
// lifetime elision, we can determine it in two ways. First (determined
// here), if self is by-reference, then the implied output region is the
// region of the self parameter.
let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) {
(Some(untransformed_self_ty), Some(explicit_self)) => {
let self_type = self.determine_self_type(&rb, untransformed_self_ty,
&explicit_self);
(Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type)))
}
_ => (None, None),
};
let input_tys: Vec<Ty> =
decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
// HACK(eddyb) replace the fake self type in the AST with the actual type.
let arg_params = if self_ty.is_some() {
&decl.inputs[1..]
} else {
&decl.inputs[..]
};
let arg_tys: Vec<Ty> =
arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
let has_self = opt_self_value_ty.is_some();
let explicit_self = opt_self_value_ty.map(|self_value_ty| {
ExplicitSelf::determine(self_value_ty, input_tys[0])
});
// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
let implied_output_region = match explicit_self {
// `implied_output_region` is the region that will be assumed for any
// region parameters in the return type. In accordance with the rules for
// lifetime elision, we can determine it in two ways. First (determined
// here), if self is by-reference, then the implied output region is the
// region of the self parameter.
Some(ExplicitSelf::ByReference(region, _)) => Ok(*region),
// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
_ => {
self.find_implied_output_region(&arg_tys,
arg_params.iter()
.map(|a| pprust::pat_to_string(&a.pat)))
let arg_tys = &input_tys[has_self as usize..];
let arg_params = has_self as usize..input_tys.len();
self.find_implied_output_region(arg_tys, body, arg_params)
}
};
@ -1793,37 +1784,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
unsafety: unsafety,
abi: abi,
sig: ty::Binder(self.tcx().mk_fn_sig(
self_ty.into_iter().chain(arg_tys),
input_tys.into_iter(),
output_ty,
decl.variadic
)),
})
}
fn determine_self_type<'a>(&self,
rscope: &RegionScope,
untransformed_self_ty: Ty<'tcx>,
explicit_self: &hir::ExplicitSelf)
-> Ty<'tcx>
{
match explicit_self.node {
SelfKind::Value(..) => untransformed_self_ty,
SelfKind::Region(ref lifetime, mutability) => {
let region =
self.opt_ast_region_to_region(
rscope,
explicit_self.span,
lifetime);
self.tcx().mk_ref(region,
ty::TypeAndMut {
ty: untransformed_self_ty,
mutbl: mutability
})
}
SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type)
}
}
pub fn ty_of_closure(&self,
unsafety: hir::Unsafety,
decl: &hir::FnDecl,

View file

@ -527,7 +527,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let report_unexpected_def = |def: Def| {
span_err!(tcx.sess, pat.span, E0533,
"expected unit struct/variant or constant, found {} `{}`",
def.kind_name(), qpath);
def.kind_name(),
hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
};
// Resolve the path and check the definition for errors.
@ -568,7 +569,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};
let report_unexpected_def = |def: Def| {
let msg = format!("expected tuple struct/variant, found {} `{}`",
def.kind_name(), qpath);
def.kind_name(),
hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
.span_label(pat.span, &format!("not a tuple variant or struct")).emit();
on_error();

View file

@ -13,7 +13,6 @@ use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
use CrateCtxt;
use hir::def::Def;
use hir::def_id::{DefId, LOCAL_CRATE};
use hir::print;
use rustc::{infer, traits};
use rustc::ty::{self, LvaluePreference, Ty};
use syntax::symbol::Symbol;
@ -203,7 +202,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let &ty::TyAdt(adt_def, ..) = t {
if adt_def.is_enum() {
if let hir::ExprCall(ref expr, _) = call_expr.node {
unit_variant = Some(print::expr_to_string(expr))
unit_variant = Some(self.tcx.map.node_to_pretty_string(expr.id))
}
}
}

View file

@ -25,7 +25,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr: &hir::Expr,
_capture: hir::CaptureClause,
decl: &'gcx hir::FnDecl,
body_id: hir::ExprId,
body_id: hir::BodyId,
expected: Expectation<'tcx>)
-> Ty<'tcx> {
debug!("check_expr_closure(expr={:?},expected={:?})",
@ -39,7 +39,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Some(ty) => self.deduce_expectations_from_expected_type(ty),
None => (None, None),
};
let body = self.tcx.map.expr(body_id);
let body = self.tcx.map.body(body_id);
self.check_closure(expr, expected_kind, decl, body, expected_sig)
}
@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr: &hir::Expr,
opt_kind: Option<ty::ClosureKind>,
decl: &'gcx hir::FnDecl,
body: &'gcx hir::Expr,
body: &'gcx hir::Body,
expected_sig: Option<ty::FnSig<'tcx>>)
-> Ty<'tcx> {
debug!("check_closure opt_kind={:?} expected_sig={:?}",
@ -73,10 +73,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
let fn_sig = self.tcx
.liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
&fn_ty.sig);
let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
let fn_sig = self.tcx.liberate_late_bound_regions(extent, &fn_ty.sig);
let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
body.value.id, &fn_sig);
check_fn(self,
hir::Unsafety::Normal,
@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
&fn_sig,
decl,
expr.id,
&body);
body);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.

View file

@ -8,14 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::hir;
use rustc::hir::{self, ImplItemKind, TraitItemKind};
use rustc::infer::{self, InferOk};
use rustc::middle::free_region::FreeRegionMap;
use rustc::ty;
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, Substs};
use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
use rustc::util::common::ErrorReported;
use syntax::ast;
@ -450,37 +449,24 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
TypeError::Mutability => {
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
TraitItemKind::Method(ref trait_m_sig, _) => {
trait_m_sig.decl.inputs.iter()
}
_ => bug!("{:?} is not a MethodTraitItem", trait_m),
_ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
};
impl_m_iter.zip(trait_m_iter)
.find(|&(ref impl_arg, ref trait_arg)| {
match (&impl_arg.ty.node, &trait_arg.ty.node) {
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
impl_mt.mutbl != trait_mt.mutbl
}
_ => false,
}
})
.map(|(ref impl_arg, ref trait_arg)| {
match (impl_arg.to_self(), trait_arg.to_self()) {
(Some(impl_self), Some(trait_self)) => {
(impl_self.span, Some(trait_self.span))
}
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
_ => {
bug!("impl and trait fns have different first args, impl: \
{:?}, trait: {:?}",
impl_arg,
trait_arg)
}
}
})
.unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
match (&impl_arg.node, &trait_arg.node) {
(&hir::TyRptr(_, ref impl_mt), &hir::TyRptr(_, ref trait_mt)) |
(&hir::TyPtr(ref impl_mt), &hir::TyPtr(ref trait_mt)) => {
impl_mt.mutbl != trait_mt.mutbl
}
_ => false,
}
}).map(|(ref impl_arg, ref trait_arg)| {
(impl_arg.span, Some(trait_arg.span))
})
.unwrap_or_else(|| (cause.span, tcx.map.span_if_local(trait_m.def_id)))
} else {
(cause.span, tcx.map.span_if_local(trait_m.def_id))
}
@ -489,10 +475,10 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let (trait_m_output, trait_m_iter) =
match tcx.map.expect_trait_item(trait_m_node_id).node {
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
TraitItemKind::Method(ref trait_m_sig, _) => {
(&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
}
_ => bug!("{:?} is not a MethodTraitItem", trait_m),
_ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
};
let impl_iter = impl_sig.inputs().iter();
@ -503,7 +489,7 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
Ok(_) => None,
Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
}
})
.next()
@ -688,13 +674,13 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
let trait_span = if let Some(trait_id) = trait_m_node_id {
match tcx.map.expect_trait_item(trait_id).node {
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
TraitItemKind::Method(ref trait_m_sig, _) => {
if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
trait_number_args - 1
} else {
0
}) {
Some(arg.pat.span)
Some(arg.span)
} else {
trait_item_span
}
@ -712,7 +698,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
} else {
0
}) {
arg.pat.span
arg.span
} else {
impl_m_span
}
@ -839,7 +825,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
// Add a label to the Span containing just the type of the item
let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
TraitItemKind::Const(ref ty, _) => ty.span,
_ => bug!("{:?} is not a trait const", trait_c),
};

View file

@ -48,7 +48,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let i_n_tps = tcx.item_generics(def_id).types.len();
if i_n_tps != n_tps {
let span = match it.node {
hir::ForeignItemFn(_, ref generics) => generics.span,
hir::ForeignItemFn(_, _, ref generics) => generics.span,
hir::ForeignItemStatic(..) => it.span
};

View file

@ -26,7 +26,6 @@ use syntax::ast;
use errors::DiagnosticBuilder;
use syntax_pos::Span;
use rustc::hir::print as pprust;
use rustc::hir;
use rustc::infer::type_variable::TypeVariableOrigin;
@ -266,7 +265,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let msg = if let Some(callee) = rcvr_expr {
format!("{}; use overloaded call notation instead (e.g., `{}()`)",
msg,
pprust::expr_to_string(callee))
self.tcx.map.node_to_pretty_string(callee.id))
} else {
msg
};
@ -463,6 +462,9 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -122,7 +122,6 @@ use syntax_pos::{self, BytePos, Span, DUMMY_SP};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
use rustc::middle::lang_items;
use rustc_back::slice;
use rustc_const_eval::eval_length;
@ -550,14 +549,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
match t.node {
hir::TyArray(_, ref expr) => {
check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
hir::TyArray(_, length) => {
check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
}
_ => {}
}
intravisit::walk_ty(self, t);
}
fn visit_expr(&mut self, e: &'tcx hir::Expr) {
match e.node {
hir::ExprRepeat(_, count) => {
check_const_with_type(self.ccx, count, self.ccx.tcx.types.usize, count.node_id);
}
_ => {}
}
intravisit::walk_expr(self, e);
}
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
@ -565,6 +575,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
check_item_body(self.ccx, i);
}
fn visit_trait_item(&mut self, _item: &'tcx hir::TraitItem) {
// done as part of `visit_item` above
}
fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) {
// done as part of `visit_item` above
}
@ -635,28 +649,28 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
decl: &'tcx hir::FnDecl,
body_id: hir::ExprId,
body_id: hir::BodyId,
fn_id: ast::NodeId,
span: Span) {
let body = ccx.tcx.map.expr(body_id);
let body = ccx.tcx.map.body(body_id);
let raw_fty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(fn_id));
let fn_ty = match raw_fty.sty {
ty::TyFnDef(.., f) => f,
_ => span_bug!(body.span, "check_bare_fn: function type expected")
_ => span_bug!(body.value.span, "check_bare_fn: function type expected")
};
check_abi(ccx, span, fn_ty.abi);
ccx.inherited(fn_id).enter(|inh| {
// Compute the fty from point of view of inside fn.
let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id());
let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
let fn_sig =
fn_ty.sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
let fn_sig =
inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
let fn_sig =
inh.normalize_associated_types_in(body.span, body_id.node_id(), &fn_sig);
inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
@ -666,8 +680,8 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
fcx.regionck_fn(fn_id, decl, body_id);
fcx.resolve_type_vars_in_fn(decl, body, fn_id);
fcx.regionck_fn(fn_id, body);
fcx.resolve_type_vars_in_body(body, fn_id);
});
}
@ -736,32 +750,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
intravisit::walk_pat(self, p);
}
fn visit_block(&mut self, b: &'gcx hir::Block) {
// non-obvious: the `blk` variable maps to region lb, so
// we have to keep this up-to-date. This
// is... unfortunate. It'd be nice to not need this.
intravisit::walk_block(self, b);
}
// Since an expr occurs as part of the type fixed size arrays we
// need to record the type for that node
fn visit_ty(&mut self, t: &'gcx hir::Ty) {
match t.node {
hir::TyArray(ref ty, ref count_expr) => {
self.visit_ty(&ty);
self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
}
hir::TyBareFn(ref function_declaration) => {
intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
}
_ => intravisit::walk_ty(self, t)
}
}
// Don't descend into the bodies of nested closures
fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
_: hir::ExprId, _: Span, _: ast::NodeId) { }
_: hir::BodyId, _: Span, _: ast::NodeId) { }
}
/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
@ -776,7 +767,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
fn_sig: &ty::FnSig<'tcx>,
decl: &'gcx hir::FnDecl,
fn_id: ast::NodeId,
body: &'gcx hir::Expr)
body: &'gcx hir::Body)
-> FnCtxt<'a, 'gcx, 'tcx>
{
let mut fn_sig = fn_sig.clone();
@ -785,7 +776,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
let mut fcx = FnCtxt::new(inherited, None, body.id);
let mut fcx = FnCtxt::new(inherited, None, body.value.id);
let ret_ty = fn_sig.output();
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
@ -794,36 +785,26 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
fn_sig.variadic);
{
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
// Add formal parameters.
for (arg_ty, input) in fn_sig.inputs().iter().zip(&decl.inputs) {
// The type of the argument must be well-formed.
//
// NB -- this is now checked in wfcheck, but that
// currently only results in warnings, so we issue an
// old-style WF obligation here so that we still get the
// errors that we used to get.
fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
// Add formal parameters.
for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
// The type of the argument must be well-formed.
//
// NB -- this is now checked in wfcheck, but that
// currently only results in warnings, so we issue an
// old-style WF obligation here so that we still get the
// errors that we used to get.
fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation);
// Create type variables for each argument.
input.pat.each_binding(|_bm, pat_id, sp, _path| {
let var_ty = visit.assign(sp, pat_id, None);
fcx.require_type_is_sized(var_ty, sp, traits::VariableType(pat_id));
});
// Check the pattern.
fcx.check_pat(&input.pat, arg_ty);
fcx.write_ty(input.id, arg_ty);
}
visit.visit_expr(body);
// Check the pattern.
fcx.check_pat(&arg.pat, arg_ty);
fcx.write_ty(arg.id, arg_ty);
}
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap());
fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap());
fcx
}
@ -848,8 +829,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
let _indenter = indenter();
match it.node {
// Consts can play a role in type-checking, so they are included here.
hir::ItemStatic(.., ref e) |
hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
hir::ItemStatic(.., e) |
hir::ItemConst(_, e) => check_const(ccx, e, it.id),
hir::ItemEnum(ref enum_definition, _) => {
check_enum_variants(ccx,
it.span,
@ -908,7 +889,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
err.emit();
}
if let hir::ForeignItemFn(ref fn_decl, _) = item.node {
if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
}
}
@ -933,8 +914,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
for impl_item_ref in impl_item_refs {
let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
hir::ImplItemKind::Const(_, ref expr) => {
check_const(ccx, &expr, impl_item.id)
hir::ImplItemKind::Const(_, expr) => {
check_const(ccx, expr, impl_item.id)
}
hir::ImplItemKind::Method(ref sig, body_id) => {
check_bare_fn(ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
@ -945,18 +926,19 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
}
}
}
hir::ItemTrait(.., ref trait_items) => {
for trait_item in trait_items {
hir::ItemTrait(.., ref trait_item_refs) => {
for trait_item_ref in trait_item_refs {
let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
match trait_item.node {
hir::ConstTraitItem(_, Some(ref expr)) => {
check_const(ccx, &expr, trait_item.id)
hir::TraitItemKind::Const(_, Some(expr)) => {
check_const(ccx, expr, trait_item.id)
}
hir::MethodTraitItem(ref sig, Some(body_id)) => {
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
check_bare_fn(ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
}
hir::MethodTraitItem(_, None) |
hir::ConstTraitItem(_, None) |
hir::TypeTraitItem(..) => {
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
hir::TraitItemKind::Const(_, None) |
hir::TraitItemKind::Type(..) => {
// Nothing to do.
}
}
@ -1122,7 +1104,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
compare_impl_method(ccx,
&ty_impl_item,
impl_item.span,
body_id.node_id(),
body_id.node_id,
&ty_trait_item,
impl_trait_ref,
trait_span,
@ -1132,7 +1114,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
compare_impl_method(ccx,
&ty_impl_item,
impl_item.span,
body_id.node_id(),
body_id.node_id,
&ty_trait_item,
impl_trait_ref,
trait_span,
@ -1243,37 +1225,38 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
/// Checks a constant with a given type.
fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr,
body: hir::BodyId,
expected_type: Ty<'tcx>,
id: ast::NodeId) {
let body = ccx.tcx.map.body(body);
ccx.inherited(id).enter(|inh| {
let fcx = FnCtxt::new(&inh, None, expr.id);
fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
let fcx = FnCtxt::new(&inh, None, body.value.id);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
// This is technically unnecessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly
// emit an error.
GatherLocalsVisitor { fcx: &fcx }.visit_expr(expr);
GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
fcx.check_expr_coercable_to_type(expr, expected_type);
fcx.check_expr_coercable_to_type(&body.value, expected_type);
fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze(expr);
fcx.closure_analyze(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error();
fcx.regionck_expr(expr);
fcx.resolve_type_vars_in_expr(expr, id);
fcx.regionck_expr(body);
fcx.resolve_type_vars_in_body(body, id);
});
}
fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
expr: &'tcx hir::Expr,
body: hir::BodyId,
id: ast::NodeId) {
let decl_ty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(id));
check_const_with_type(ccx, expr, decl_ty, id);
check_const_with_type(ccx, body, decl_ty, id);
}
/// Checks whether a type can be represented in memory. In particular, it
@ -1348,8 +1331,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
for v in vs {
if let Some(ref e) = v.node.disr_expr {
check_const_with_type(ccx, e, repr_type_ty, e.id);
if let Some(e) = v.node.disr_expr {
check_const_with_type(ccx, e, repr_type_ty, e.node_id);
}
}
@ -1365,11 +1348,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
let variant_i = ccx.tcx.map.expect_variant(variant_i_node_id);
let i_span = match variant_i.node.disr_expr {
Some(ref expr) => expr.span,
Some(expr) => ccx.tcx.map.span(expr.node_id),
None => ccx.tcx.map.span(variant_i_node_id)
};
let span = match v.node.disr_expr {
Some(ref expr) => expr.span,
Some(expr) => ccx.tcx.map.span(expr.node_id),
None => v.span
};
struct_span_err!(ccx.tcx.sess, span, E0081,
@ -1643,12 +1626,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
match self.locals.borrow().get(&nid) {
Some(&t) => t,
None => {
struct_span_err!(self.tcx.sess, span, E0513,
"no type for local variable {}",
self.tcx.map.node_to_string(nid))
.span_label(span, &"no type for variable")
.emit();
self.tcx.types.err
span_bug!(span, "no type for local variable {}",
self.tcx.map.node_to_string(nid));
}
}
}
@ -3065,7 +3044,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
ty::TyRawPtr(..) => {
err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
`(*{0}).{1}`", pprust::expr_to_string(base), field.node));
`(*{0}).{1}`",
self.tcx.map.node_to_pretty_string(base.id),
field.node));
}
_ => {}
}
@ -3479,11 +3460,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.diverges.set(self.diverges.get() | old_diverges);
self.has_errors.set(self.has_errors.get() | old_has_errors);
debug!("type of expr({}) {} is...", expr.id,
pprust::expr_to_string(expr));
debug!("... {:?}, expected is {:?}",
ty,
expected);
debug!("type of {} is...", self.tcx.map.node_to_string(expr.id));
debug!("... {:?}, expected is {:?}", ty, expected);
// Add adjustments to !-expressions
if ty.is_never() {
@ -3821,10 +3799,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.check_method_call(expr, name, args, &tps[..], expected, lvalue_pref)
}
hir::ExprCast(ref e, ref t) => {
if let hir::TyArray(_, ref count_expr) = t.node {
self.check_expr_with_hint(&count_expr, tcx.types.usize);
}
// Find the type of `e`. Supply hints based on the type we are casting to,
// if appropriate.
let t_cast = self.to_ty(t);
@ -3886,9 +3860,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
tcx.mk_array(unified, args.len())
}
hir::ExprRepeat(ref element, ref count_expr) => {
self.check_expr_has_type(&count_expr, tcx.types.usize);
let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
hir::ExprRepeat(ref element, count) => {
let count_expr = &tcx.map.body(count).value;
let count = eval_length(self.tcx.global_tcx(), count_expr, "repeat count")
.unwrap_or(0);
let uty = match expected {

View file

@ -113,12 +113,13 @@ macro_rules! ignore_err {
// PUBLIC ENTRY POINTS
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn regionck_expr(&self, e: &'gcx hir::Expr) {
let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
pub fn regionck_expr(&self, body: &'gcx hir::Body) {
let id = body.value.id;
let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(id));
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_expr(e);
rcx.visit_region_obligations(e.id);
rcx.visit_body(body);
rcx.visit_region_obligations(id);
}
rcx.resolve_regions_and_report_errors();
}
@ -140,15 +141,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn regionck_fn(&self,
fn_id: ast::NodeId,
decl: &hir::FnDecl,
body_id: hir::ExprId) {
body: &'gcx hir::Body) {
debug!("regionck_fn(id={})", fn_id);
let node_id = body_id.node_id();
let node_id = body.value.id;
let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(fn_id));
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_fn_body(fn_id, decl, body_id, self.tcx.map.span(fn_id));
rcx.visit_fn_body(fn_id, body, self.tcx.map.span(fn_id));
}
rcx.free_region_map.relate_free_regions_from_predicates(
@ -267,15 +267,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
fn visit_fn_body(&mut self,
id: ast::NodeId, // the id of the fn itself
fn_decl: &hir::FnDecl,
body_id: hir::ExprId,
body: &'gcx hir::Body,
span: Span)
{
// When we enter a function, we can derive
debug!("visit_fn_body(id={})", id);
let body_id = body.id();
let call_site = self.tcx.region_maps.lookup_code_extent(
region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
let old_call_site_scope = self.set_call_site_scope(Some(call_site));
let fn_sig = {
@ -298,20 +299,18 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
let fn_sig_tys: Vec<_> =
fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
let old_body_id = self.set_body_id(body_id.node_id());
self.relate_free_regions(&fn_sig_tys[..], body_id.node_id(), span);
self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id()),
&fn_decl.inputs[..]);
let body = self.tcx.map.expr(body_id);
self.visit_expr(body);
self.visit_region_obligations(body_id.node_id());
let old_body_id = self.set_body_id(body_id.node_id);
self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id), &body.arguments);
self.visit_body(body);
self.visit_region_obligations(body_id.node_id);
let call_site_scope = self.call_site_scope.unwrap();
debug!("visit_fn_body body.id {} call_site_scope: {:?}",
body.id, call_site_scope);
debug!("visit_fn_body body.id {:?} call_site_scope: {:?}",
body.id(), call_site_scope);
let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
self.type_of_node_must_outlive(infer::CallReturn(span),
body_id.node_id(),
body_id.node_id,
call_site_region);
self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
@ -478,12 +477,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
// regions, until regionck, as described in #3238.
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
NestedVisitorMap::OnlyBodies(&self.tcx.map)
NestedVisitorMap::None
}
fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, fd: &'gcx hir::FnDecl,
b: hir::ExprId, span: Span, id: ast::NodeId) {
self.visit_fn_body(id, fd, b, span)
fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
b: hir::BodyId, span: Span, id: ast::NodeId) {
let body = self.tcx.map.body(b);
self.visit_fn_body(id, body, span)
}
//visit_pat: visit_pat, // (..) see above
@ -826,8 +826,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
fn check_expr_fn_block(&mut self,
expr: &'gcx hir::Expr,
body_id: hir::ExprId) {
let repeating_scope = self.set_repeating_scope(body_id.node_id());
body_id: hir::BodyId) {
let repeating_scope = self.set_repeating_scope(body_id.node_id);
intravisit::walk_expr(self, expr);
self.set_repeating_scope(repeating_scope);
}
@ -1113,7 +1113,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
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.ty.span, re_scope, arg_ty);
let arg_cmt = mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty);
debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
arg_ty,
arg_cmt,

View file

@ -57,12 +57,12 @@ use rustc::util::nodemap::NodeMap;
// PUBLIC ENTRY POINTS
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn closure_analyze(&self, body: &'gcx hir::Expr) {
pub fn closure_analyze(&self, body: &'gcx hir::Body) {
let mut seed = SeedBorrowKind::new(self);
seed.visit_expr(body);
seed.visit_body(body);
let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
adjust.visit_expr(body);
adjust.visit_body(body);
// it's our job to process these.
assert!(self.deferred_call_resolutions.borrow().is_empty());
@ -79,13 +79,15 @@ struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
NestedVisitorMap::None
}
fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
match expr.node {
hir::ExprClosure(cc, _, body_id, _) => {
self.check_closure(expr, cc, body_id);
let body = self.fcx.tcx.map.body(body_id);
self.visit_body(body);
self.check_closure(expr, cc);
}
_ => { }
@ -102,8 +104,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
fn check_closure(&mut self,
expr: &hir::Expr,
capture_clause: hir::CaptureClause,
_body_id: hir::ExprId)
capture_clause: hir::CaptureClause)
{
let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
@ -156,23 +157,21 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
fn analyze_closure(&mut self,
id: ast::NodeId,
span: Span,
decl: &hir::FnDecl,
body_id: hir::ExprId) {
body: &hir::Body) {
/*!
* Analysis starting point.
*/
debug!("analyze_closure(id={:?}, body.id={:?})", id, body_id);
debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
{
let body = self.fcx.tcx.map.expr(body_id);
let mut euv =
euv::ExprUseVisitor::with_options(self,
self.fcx,
mc::MemCategorizationOptions {
during_closure_kind_inference: true
});
euv.walk_fn(decl, body);
euv.consume_body(body);
}
// Now that we've analyzed the closure, we know how each
@ -491,18 +490,21 @@ 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::OnlyBodies(&self.fcx.tcx.map)
NestedVisitorMap::None
}
fn visit_fn(&mut self,
fn_kind: intravisit::FnKind<'gcx>,
decl: &'gcx hir::FnDecl,
body: hir::ExprId,
body: hir::BodyId,
span: Span,
id: ast::NodeId)
{
intravisit::walk_fn(self, fn_kind, decl, body, span, id);
self.analyze_closure(id, span, decl, body);
let body = self.fcx.tcx.map.body(body);
self.visit_body(body);
self.analyze_closure(id, span, body);
}
}

View file

@ -159,10 +159,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
}
}
fn check_trait_or_impl_item(&mut self,
item_id: ast::NodeId,
span: Span,
sig_if_method: Option<&hir::MethodSig>) {
fn check_associated_item(&mut self,
item_id: ast::NodeId,
span: Span,
sig_if_method: Option<&hir::MethodSig>) {
let code = self.code.clone();
self.for_id(item_id, span).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
@ -337,7 +337,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
fn check_item_fn(&mut self,
item: &hir::Item,
body_id: hir::ExprId)
body_id: hir::BodyId)
{
self.for_item(item).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
@ -354,7 +354,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
let mut implied_bounds = vec![];
let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id());
let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id);
this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
free_id_outlive, &mut implied_bounds);
implied_bounds
@ -478,7 +478,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
return;
}
let span = method_sig.decl.inputs[0].pat.span;
let span = method_sig.decl.inputs[0].span;
let free_substs = &fcx.parameter_environment.free_substs;
let method_ty = fcx.tcx.item_type(method.def_id);
@ -607,10 +607,10 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
debug!("visit_trait_item: {:?}", trait_item);
let method_sig = match trait_item.node {
hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig),
hir::TraitItemKind::Method(ref sig, _) => Some(sig),
_ => None
};
self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig);
self.check_associated_item(trait_item.id, trait_item.span, method_sig);
intravisit::walk_trait_item(self, trait_item)
}
@ -620,7 +620,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
hir::ImplItemKind::Method(ref sig, _) => Some(sig),
_ => None
};
self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig);
self.check_associated_item(impl_item.id, impl_item.span, method_sig);
intravisit::walk_impl_item(self, impl_item)
}
}

View file

@ -26,42 +26,22 @@ use std::cell::Cell;
use syntax::ast;
use syntax_pos::Span;
use rustc::hir::print::pat_to_string;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::{self, PatKind};
use rustc::hir;
///////////////////////////////////////////////////////////////////////////
// Entry point functions
// Entry point
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn resolve_type_vars_in_expr(&self, e: &'gcx hir::Expr, item_id: ast::NodeId) {
pub fn resolve_type_vars_in_body(&self,
body: &'gcx hir::Body,
item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false);
let mut wbcx = WritebackCx::new(self);
wbcx.visit_expr(e);
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
wbcx.visit_deferred_obligations(item_id);
wbcx.visit_type_nodes();
}
pub fn resolve_type_vars_in_fn(&self,
decl: &'gcx hir::FnDecl,
body: &'gcx hir::Expr,
item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false);
let mut wbcx = WritebackCx::new(self);
wbcx.visit_expr(body);
for arg in &decl.inputs {
for arg in &body.arguments {
wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
wbcx.visit_pat(&arg.pat);
// Privacy needs the type for the whole pattern, not just each binding
if let PatKind::Binding(..) = arg.pat.node {} else {
wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id);
}
}
wbcx.visit_body(body);
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
@ -188,7 +168,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
NestedVisitorMap::None
}
fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
@ -211,10 +191,13 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
self.visit_method_map_entry(ResolvingExpr(e.span),
MethodCall::expr(e.id));
if let hir::ExprClosure(_, ref decl, ..) = e.node {
for input in &decl.inputs {
self.visit_node_id(ResolvingExpr(e.span), input.id);
if let hir::ExprClosure(_, _, body, _) = e.node {
let body = self.fcx.tcx.map.body(body);
for arg in &body.arguments {
self.visit_node_id(ResolvingExpr(e.span), arg.id);
}
self.visit_body(body);
}
intravisit::walk_expr(self, e);
@ -237,7 +220,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
self.visit_node_id(ResolvingPattern(p.span), p.id);
debug!("Type for pattern binding {} (id {}) resolved to {:?}",
pat_to_string(p),
self.tcx().map.node_to_pretty_string(p.id),
p.id,
self.tcx().tables().node_id_to_type(p.id));
@ -254,20 +237,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
self.write_ty_to_tcx(l.id, var_ty);
intravisit::walk_local(self, l);
}
fn visit_ty(&mut self, t: &'gcx hir::Ty) {
match t.node {
hir::TyArray(ref ty, ref count_expr) => {
self.visit_ty(&ty);
self.write_ty_to_tcx(count_expr.id, self.tcx().types.usize);
}
hir::TyBareFn(ref function_declaration) => {
intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
}
_ => intravisit::walk_ty(self, t)
}
}
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {

View file

@ -50,6 +50,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -58,6 +58,9 @@ impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx,
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -67,13 +67,15 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
}
}
}
}
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
/// Checks exactly one impl for orphan rules and other such
/// restrictions. In this fn, it can happen that multiple errors
/// apply to a specific impl, so just return after reporting one
/// to prevent inundating the user with a bunch of similar error
/// reports.
fn check_item(&self, item: &hir::Item) {
fn visit_item(&mut self, item: &hir::Item) {
let def_id = self.tcx.map.local_def_id(item.id);
match item.node {
hir::ItemImpl(.., None, ref ty, _) => {
@ -368,7 +370,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
the crate they're defined in; define a new trait instead")
.span_label(item_trait_ref.path.span,
&format!("`{}` trait not defined in this crate",
item_trait_ref.path))
self.tcx.map.node_to_pretty_string(item_trait_ref.ref_id)))
.emit();
return;
}
@ -378,11 +380,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
}
}
}
}
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
self.check_item(item);
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {

View file

@ -205,6 +205,9 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -107,6 +107,9 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -82,7 +82,7 @@ use syntax::{abi, ast, attr};
use syntax::symbol::{Symbol, keywords};
use syntax_pos::Span;
use rustc::hir::{self, map as hir_map, print as pprust};
use rustc::hir::{self, map as hir_map};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
@ -204,6 +204,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
intravisit::walk_ty(self, ty);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
self.with_collect_item_sig(trait_item.id, || {
convert_trait_item(self.ccx, trait_item)
});
intravisit::walk_trait_item(self, trait_item);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.with_collect_item_sig(impl_item.id, || {
convert_impl_item(self.ccx, impl_item)
@ -633,7 +640,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
id: ast::NodeId,
sig: &hir::MethodSig,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
body: Option<hir::BodyId>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
let def_id = ccx.tcx.map.local_def_id(id);
let ty_generics = generics_of_def_id(ccx, def_id);
@ -644,8 +652,14 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
TraitContainer(_) => None
};
let assoc_item = ccx.tcx.associated_item(def_id);
let self_value_ty = if assoc_item.method_has_self_argument {
Some(untransformed_rcvr_ty)
} else {
None
};
let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
sig, untransformed_rcvr_ty, anon_scope);
sig, self_value_ty, body, anon_scope);
let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
ccx.tcx.map.span(id), def_id);
@ -785,56 +799,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
},
hir::ItemTrait(.., ref trait_items) => {
hir::ItemTrait(..) => {
generics_of_def_id(ccx, def_id);
trait_def_of_item(ccx, it);
let _: Result<(), ErrorReported> = // any error is already reported, can ignore
ccx.ensure_super_predicates(it.span, def_id);
convert_trait_predicates(ccx, it);
let trait_predicates = tcx.item_predicates(def_id);
debug!("convert: trait_bounds={:?}", trait_predicates);
// FIXME: is the ordering here important? I think it is.
let container = TraitContainer(def_id);
// Convert all the associated constants.
for trait_item in trait_items {
if let hir::ConstTraitItem(ref ty, _) = trait_item.node {
let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
generics_of_def_id(ccx, const_def_id);
let ty = ccx.icx(&trait_predicates)
.to_ty(&ExplicitRscope, ty);
tcx.item_types.borrow_mut().insert(const_def_id, ty);
convert_associated_const(ccx, container, trait_item.id, ty)
}
}
// Convert all the associated types.
for trait_item in trait_items {
if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node {
let type_def_id = ccx.tcx.map.local_def_id(trait_item.id);
generics_of_def_id(ccx, type_def_id);
let typ = opt_ty.as_ref().map({
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
});
convert_associated_type(ccx, container, trait_item.id, typ);
}
}
// Convert all the methods
for trait_item in trait_items {
if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
convert_method(ccx,
container,
trait_item.id,
sig,
tcx.mk_self_type(),
&trait_predicates);
}
}
},
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
@ -866,6 +836,48 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
}
}
fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
let tcx = ccx.tcx;
// we can lookup details about the trait because items are visited
// before trait-items
let trait_def_id = tcx.map.get_parent_did(trait_item.id);
let trait_predicates = tcx.item_predicates(trait_def_id);
match trait_item.node {
hir::TraitItemKind::Const(ref ty, _) => {
let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
generics_of_def_id(ccx, const_def_id);
let ty = ccx.icx(&trait_predicates)
.to_ty(&ExplicitRscope, &ty);
tcx.item_types.borrow_mut().insert(const_def_id, ty);
convert_associated_const(ccx, TraitContainer(trait_def_id),
trait_item.id, ty);
}
hir::TraitItemKind::Type(_, ref opt_ty) => {
let type_def_id = ccx.tcx.map.local_def_id(trait_item.id);
generics_of_def_id(ccx, type_def_id);
let typ = opt_ty.as_ref().map({
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
});
convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
}
hir::TraitItemKind::Method(ref sig, ref method) => {
let body = match *method {
hir::TraitMethod::Required(_) => None,
hir::TraitMethod::Provided(body) => Some(body)
};
convert_method(ccx, TraitContainer(trait_def_id),
trait_item.id, sig, tcx.mk_self_type(),
body, &trait_predicates);
}
}
}
fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
let tcx = ccx.tcx;
@ -901,10 +913,10 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
}
hir::ImplItemKind::Method(ref sig, _) => {
hir::ImplItemKind::Method(ref sig, body) => {
convert_method(ccx, ImplContainer(impl_def_id),
impl_item.id, sig, impl_self_ty,
&impl_predicates);
Some(body), &impl_predicates);
}
}
}
@ -1029,7 +1041,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
-> Option<ty::Disr> {
debug!("disr expr, checking {}", pprust::expr_to_string(e));
debug!("disr expr, checking {}", ccx.tcx.map.node_to_pretty_string(e.id));
let ty_hint = repr_ty.to_ty(ccx.tcx);
let print_err = |cv: ConstVal| {
@ -1088,7 +1100,8 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let mut prev_disr = None::<ty::Disr>;
let variants = def.variants.iter().map(|v| {
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
let disr = if let Some(ref e) = v.node.disr_expr {
let disr = if let Some(e) = v.node.disr_expr {
let e = &tcx.map.body(e).value;
evaluate_disr_expr(ccx, repr_type, e)
} else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
Some(disr)
@ -1290,12 +1303,13 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item)
ast_generics: &hir::Generics,
trait_predicates: &ty::GenericPredicates<'tcx>,
self_trait_ref: ty::TraitRef<'tcx>,
trait_items: &[hir::TraitItem])
trait_item_refs: &[hir::TraitItemRef])
-> Vec<ty::Predicate<'tcx>>
{
trait_items.iter().flat_map(|trait_item| {
trait_item_refs.iter().flat_map(|trait_item_ref| {
let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
let bounds = match trait_item.node {
hir::TypeTraitItem(ref bounds, _) => bounds,
hir::TraitItemKind::Type(ref bounds, _) => bounds,
_ => {
return vec![].into_iter();
}
@ -1363,7 +1377,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let ast_generics = match node {
NodeTraitItem(item) => {
match item.node {
MethodTraitItem(ref sig, _) => &sig.generics,
TraitItemKind::Method(ref sig, _) => &sig.generics,
_ => &no_generics
}
}
@ -1420,7 +1434,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
NodeForeignItem(item) => {
match item.node {
ForeignItemStatic(..) => &no_generics,
ForeignItemFn(_, ref generics) => generics
ForeignItemFn(_, _, ref generics) => generics
}
}
@ -1521,9 +1535,9 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t)
}
ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
ItemFn(ref decl, unsafety, _, abi, ref generics, body) => {
let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
Some(AnonTypeScope::new(def_id)));
body, Some(AnonTypeScope::new(def_id)));
let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
ccx.tcx.mk_fn_def(def_id, substs, tofd)
}
@ -1563,7 +1577,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let abi = ccx.tcx.map.get_foreign_abi(node_id);
match foreign_item.node {
ForeignItemFn(ref fn_decl, ref generics) => {
ForeignItemFn(ref fn_decl, _, ref generics) => {
compute_type_of_foreign_fn_decl(
ccx, ccx.tcx.map.local_def_id(foreign_item.id),
fn_decl, generics, abi)
@ -1628,7 +1642,7 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let no_generics = hir::Generics::empty();
let generics = match it.node {
hir::ForeignItemFn(_, ref generics) => generics,
hir::ForeignItemFn(_, _, ref generics) => generics,
hir::ForeignItemStatic(..) => &no_generics
};
@ -2058,13 +2072,13 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
ccx.tcx.sess.struct_span_err(ast_ty.span,
&format!("use of SIMD type `{}` in FFI is highly experimental and \
may result in invalid code",
pprust::ty_to_string(ast_ty)))
ccx.tcx.map.node_to_pretty_string(ast_ty.id)))
.help("add #![feature(simd_ffi)] to the crate attributes to enable")
.emit();
}
};
for (input, ty) in decl.inputs.iter().zip(&input_tys) {
check(&input.ty, ty)
check(&input, ty)
}
if let hir::Return(ref ty) = decl.output {
check(&ty, output)

View file

@ -3866,45 +3866,6 @@ extern "platform-intrinsic" {
```
"##,
E0513: r##"
The type of the variable couldn't be found out.
Erroneous code example:
```compile_fail,E0513
use std::mem;
unsafe {
let size = mem::size_of::<u32>();
mem::transmute_copy::<u32, [u8; size]>(&8_8);
// error: no type for local variable
}
```
To fix this error, please use a constant size instead of `size`. To make
this error more obvious, you could run:
```compile_fail,E0080
use std::mem;
unsafe {
mem::transmute_copy::<u32, [u8; mem::size_of::<u32>()]>(&8_8);
// error: constant evaluation error
}
```
So now, you can fix your code by setting the size directly:
```
use std::mem;
unsafe {
mem::transmute_copy::<u32, [u8; 4]>(&8_8);
// `u32` is 4 bytes so we replace the `mem::size_of` call with its size
}
```
"##,
E0516: r##"
The `typeof` keyword is currently reserved but unimplemented.
Erroneous code example:

View file

@ -87,6 +87,8 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) { }
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
}

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::ty::subst::Substs;
@ -19,7 +20,10 @@ use syntax_pos::Span;
#[derive(Clone)]
pub struct ElisionFailureInfo {
pub name: String,
/// Where we can find the argument pattern.
pub parent: Option<hir::BodyId>,
/// The index of the argument in the original definition.
pub index: usize,
pub lifetime_count: usize,
pub have_bound_regions: bool
}

View file

@ -120,6 +120,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -258,6 +258,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View file

@ -10,6 +10,8 @@
//! Support for inlining external documentation into the current AST.
use std::collections::BTreeMap;
use std::io;
use std::iter::once;
use syntax::ast;
@ -17,12 +19,9 @@ use rustc::hir;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::hir::print as pprust;
use rustc::ty;
use rustc::util::nodemap::FxHashSet;
use rustc_const_eval::lookup_const_by_id;
use core::{DocContext, DocAccessLevels};
use doctree;
use clean::{self, GetDefId};
@ -345,8 +344,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
match item.kind {
ty::AssociatedKind::Const => {
let default = if item.defaultness.has_value() {
Some(pprust::expr_to_string(
lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
Some(print_inlined_const(cx, item.def_id))
} else {
None
};
@ -476,17 +474,33 @@ fn build_module(cx: &DocContext, did: DefId) -> clean::Module {
}
}
fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
let (expr, ty) = lookup_const_by_id(cx.tcx, did, None).unwrap_or_else(|| {
panic!("expected lookup_const_by_id to succeed for {:?}", did);
});
debug!("converting constant expr {:?} to snippet", expr);
let sn = pprust::expr_to_string(expr);
debug!("got snippet {}", sn);
struct InlinedConst {
nested_bodies: BTreeMap<hir::BodyId, hir::Body>
}
impl hir::print::PpAnn for InlinedConst {
fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested)
-> io::Result<()> {
if let hir::print::Nested::Body(body) = nested {
state.print_expr(&self.nested_bodies[&body].value)
} else {
Ok(())
}
}
}
fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap();
let inlined = InlinedConst {
nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did)
};
hir::print::to_string(&inlined, |s| s.print_expr(&body.value))
}
fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
clean::Constant {
type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| cx.tcx.item_type(did).clean(cx)),
expr: sn
type_: cx.tcx.item_type(did).clean(cx),
expr: print_inlined_const(cx, did)
}
}

View file

@ -32,7 +32,6 @@ use rustc::middle::resolve_lifetime::DefRegion::*;
use rustc::middle::lang_items;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::print as pprust;
use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind};
use rustc::middle::stability;
@ -1030,22 +1029,14 @@ pub struct Method {
pub abi: Abi,
}
impl Clean<Method> for hir::MethodSig {
impl<'a> Clean<Method> for (&'a hir::MethodSig, hir::BodyId) {
fn clean(&self, cx: &DocContext) -> Method {
let decl = FnDecl {
inputs: Arguments {
values: self.decl.inputs.clean(cx),
},
output: self.decl.output.clean(cx),
variadic: false,
attrs: Attributes::default()
};
Method {
generics: self.generics.clean(cx),
unsafety: self.unsafety,
constness: self.constness,
decl: decl,
abi: self.abi
generics: self.0.generics.clean(cx),
unsafety: self.0.unsafety,
constness: self.0.constness,
decl: (&*self.0.decl, self.1).clean(cx),
abi: self.0.abi
}
}
}
@ -1058,25 +1049,6 @@ pub struct TyMethod {
pub abi: Abi,
}
impl Clean<TyMethod> for hir::MethodSig {
fn clean(&self, cx: &DocContext) -> TyMethod {
let decl = FnDecl {
inputs: Arguments {
values: self.decl.inputs.clean(cx),
},
output: self.decl.output.clean(cx),
variadic: false,
attrs: Attributes::default()
};
TyMethod {
unsafety: self.unsafety.clone(),
decl: decl,
generics: self.generics.clean(cx),
abi: self.abi
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Function {
pub decl: FnDecl,
@ -1097,7 +1069,7 @@ impl Clean<Item> for doctree::Function {
deprecation: self.depr.clean(cx),
def_id: cx.tcx.map.local_def_id(self.id),
inner: FunctionItem(Function {
decl: self.decl.clean(cx),
decl: (&self.decl, self.body).clean(cx),
generics: self.generics.clean(cx),
unsafety: self.unsafety,
constness: self.constness,
@ -1130,14 +1102,47 @@ pub struct Arguments {
pub values: Vec<Argument>,
}
impl Clean<FnDecl> for hir::FnDecl {
impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
fn clean(&self, cx: &DocContext) -> Arguments {
Arguments {
values: self.0.iter().enumerate().map(|(i, ty)| {
let mut name = self.1.get(i).map(|n| n.node.to_string())
.unwrap_or(String::new());
if name.is_empty() {
name = "_".to_string();
}
Argument {
name: name,
type_: ty.clean(cx),
}
}).collect()
}
}
}
impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
fn clean(&self, cx: &DocContext) -> Arguments {
let body = cx.tcx.map.body(self.1);
Arguments {
values: self.0.iter().enumerate().map(|(i, ty)| {
Argument {
name: name_from_pat(&body.arguments[i].pat),
type_: ty.clean(cx),
}
}).collect()
}
}
}
impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
where (&'a [P<hir::Ty>], A): Clean<Arguments>
{
fn clean(&self, cx: &DocContext) -> FnDecl {
FnDecl {
inputs: Arguments {
values: self.inputs.clean(cx),
},
output: self.output.clean(cx),
variadic: self.variadic,
inputs: (&self.0.inputs[..], self.1).clean(cx),
output: self.0.output.clean(cx),
variadic: self.0.variadic,
attrs: Attributes::default()
}
}
@ -1159,7 +1164,6 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
values: sig.skip_binder().inputs().iter().map(|t| {
Argument {
type_: t.clean(cx),
id: ast::CRATE_NODE_ID,
name: names.next().map_or("".to_string(), |name| name.to_string()),
}
}).collect(),
@ -1172,7 +1176,6 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
pub struct Argument {
pub type_: Type,
pub name: String,
pub id: ast::NodeId,
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
@ -1184,26 +1187,17 @@ pub enum SelfTy {
impl Argument {
pub fn to_self(&self) -> Option<SelfTy> {
if self.name == "self" {
match self.type_ {
Infer => Some(SelfValue),
BorrowedRef{ref lifetime, mutability, ref type_} if **type_ == Infer => {
Some(SelfBorrowed(lifetime.clone(), mutability))
}
_ => Some(SelfExplicit(self.type_.clone()))
}
} else {
None
if self.name != "self" {
return None;
}
}
}
impl Clean<Argument> for hir::Arg {
fn clean(&self, cx: &DocContext) -> Argument {
Argument {
name: name_from_pat(&*self.pat),
type_: (self.ty.clean(cx)),
id: self.id
if self.type_.is_self_type() {
return Some(SelfValue);
}
match self.type_ {
BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
Some(SelfBorrowed(lifetime.clone(), mutability))
}
_ => Some(SelfExplicit(self.type_.clone()))
}
}
}
@ -1269,17 +1263,22 @@ impl Clean<PolyTrait> for hir::PolyTraitRef {
impl Clean<Item> for hir::TraitItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
hir::ConstTraitItem(ref ty, ref default) => {
hir::TraitItemKind::Const(ref ty, default) => {
AssociatedConstItem(ty.clean(cx),
default.as_ref().map(|e| pprust::expr_to_string(&e)))
default.map(|e| print_const_expr(cx, e)))
}
hir::MethodTraitItem(ref sig, Some(_)) => {
MethodItem(sig.clean(cx))
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
MethodItem((sig, body).clean(cx))
}
hir::MethodTraitItem(ref sig, None) => {
TyMethodItem(sig.clean(cx))
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
TyMethodItem(TyMethod {
unsafety: sig.unsafety.clone(),
decl: (&*sig.decl, &names[..]).clean(cx),
generics: sig.generics.clean(cx),
abi: sig.abi
})
}
hir::TypeTraitItem(ref bounds, ref default) => {
hir::TraitItemKind::Type(ref bounds, ref default) => {
AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
}
};
@ -1299,12 +1298,12 @@ impl Clean<Item> for hir::TraitItem {
impl Clean<Item> for hir::ImplItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
hir::ImplItemKind::Const(ref ty, ref expr) => {
hir::ImplItemKind::Const(ref ty, expr) => {
AssociatedConstItem(ty.clean(cx),
Some(pprust::expr_to_string(expr)))
Some(print_const_expr(cx, expr)))
}
hir::ImplItemKind::Method(ref sig, _) => {
MethodItem(sig.clean(cx))
hir::ImplItemKind::Method(ref sig, body) => {
MethodItem((sig, body).clean(cx))
}
hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
type_: ty.clean(cx),
@ -1353,11 +1352,13 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
};
let self_arg_ty = *fty.sig.input(0).skip_binder();
if self_arg_ty == self_ty {
decl.inputs.values[0].type_ = Infer;
decl.inputs.values[0].type_ = Generic(String::from("Self"));
} else if let ty::TyRef(_, mt) = self_arg_ty.sty {
if mt.ty == self_ty {
match decl.inputs.values[0].type_ {
BorrowedRef{ref mut type_, ..} => **type_ = Infer,
BorrowedRef{ref mut type_, ..} => {
**type_ = Generic(String::from("Self"))
}
_ => unreachable!(),
}
}
@ -1568,6 +1569,13 @@ impl Type {
_ => false,
}
}
pub fn is_self_type(&self) -> bool {
match *self {
Generic(ref name) => name == "Self",
_ => false
}
}
}
impl GetDefId for Type {
@ -1677,11 +1685,12 @@ impl Clean<Type> for hir::Ty {
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)},
TySlice(ref ty) => Vector(box ty.clean(cx)),
TyArray(ref ty, ref e) => {
TyArray(ref ty, e) => {
use rustc_const_math::{ConstInt, ConstUsize};
use rustc_const_eval::eval_const_expr;
use rustc::middle::const_val::ConstVal;
let e = &cx.tcx.map.body(e).value;
let n = match eval_const_expr(cx.tcx, e) {
ConstVal::Integral(ConstInt::Usize(u)) => match u {
ConstUsize::Us16(u) => u.to_string(),
@ -2332,7 +2341,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
type_params: Vec::new(),
where_predicates: Vec::new()
},
decl: self.decl.clean(cx),
decl: (&*self.decl, &[][..]).clean(cx),
abi: self.abi,
}
}
@ -2362,7 +2371,7 @@ impl Clean<Item> for doctree::Static {
inner: StaticItem(Static {
type_: self.type_.clean(cx),
mutability: self.mutability.clean(cx),
expr: pprust::expr_to_string(&self.expr),
expr: print_const_expr(cx, self.expr),
}),
}
}
@ -2386,7 +2395,7 @@ impl Clean<Item> for doctree::Constant {
deprecation: self.depr.clean(cx),
inner: ConstantItem(Constant {
type_: self.type_.clean(cx),
expr: pprust::expr_to_string(&self.expr),
expr: print_const_expr(cx, self.expr),
}),
}
}
@ -2630,9 +2639,9 @@ impl Clean<Vec<Item>> for hir::ForeignMod {
impl Clean<Item> for hir::ForeignItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
hir::ForeignItemFn(ref decl, ref generics) => {
hir::ForeignItemFn(ref decl, ref names, ref generics) => {
ForeignFunctionItem(Function {
decl: decl.clean(cx),
decl: (&**decl, &names[..]).clean(cx),
generics: generics.clean(cx),
unsafety: hir::Unsafety::Unsafe,
abi: Abi::Rust,
@ -2714,6 +2723,10 @@ fn name_from_pat(p: &hir::Pat) -> String {
}
}
fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
cx.tcx.map.node_to_pretty_string(body.node_id)
}
/// Given a type Path, resolve it to a Type using the TyCtxt
fn resolve_type(cx: &DocContext,
path: Path,

Some files were not shown because too many files have changed in this diff Show more