rustc: use an Expr instead of a Block for function bodies.

This commit is contained in:
Eduard Burtescu 2016-10-26 02:27:14 +03:00
parent 49772fbf5d
commit ff0830d749
43 changed files with 169 additions and 372 deletions

View File

@ -33,16 +33,16 @@ struct LoopScope {
}
pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
blk: &hir::Block) -> CFG {
body: &hir::Expr) -> CFG {
let mut graph = graph::Graph::new();
let entry = graph.add_node(CFGNodeData::Entry);
// `fn_exit` is target of return exprs, which lies somewhere
// outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
// outside input `body`. (Distinguishing `fn_exit` and `body_exit`
// also resolves chicken-and-egg problem that arises if you try to
// have return exprs jump to `block_exit` during construction.)
// have return exprs jump to `body_exit` during construction.)
let fn_exit = graph.add_node(CFGNodeData::Exit);
let block_exit;
let body_exit;
let mut cfg_builder = CFGBuilder {
graph: graph,
@ -50,8 +50,8 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx: tcx,
loop_scopes: Vec::new()
};
block_exit = cfg_builder.block(blk, entry);
cfg_builder.add_contained_edge(block_exit, fn_exit);
body_exit = cfg_builder.expr(body, entry);
cfg_builder.add_contained_edge(body_exit, fn_exit);
let CFGBuilder {graph, ..} = cfg_builder;
CFG {graph: graph,
entry: entry,

View File

@ -59,8 +59,8 @@ pub type CFGEdge = graph::Edge<CFGEdgeData>;
impl CFG {
pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
blk: &hir::Block) -> CFG {
construct::construct(tcx, blk)
body: &hir::Expr) -> CFG {
construct::construct(tcx, body)
}
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {

View File

@ -672,120 +672,6 @@ extern "C" {
```
"##,
E0269: r##"
A returned value was expected but not all control paths return one.
Erroneous code example:
```compile_fail,E0269
fn abracada_FAIL() -> String {
"this won't work".to_string();
// error: not all control paths return a value
}
```
In the previous code, the function is supposed to return a `String`, however,
the code returns nothing (because of the ';'). Another erroneous code would be:
```compile_fail
fn abracada_FAIL(b: bool) -> u32 {
if b {
0
} else {
"a" // It fails because an `u32` was expected and something else is
// returned.
}
}
```
It is advisable to find out what the unhandled cases are and check for them,
returning an appropriate value or panicking if necessary. Check if you need
to remove a semicolon from the last expression, like in the first erroneous
code example.
"##,
E0270: r##"
Rust lets you define functions which are known to never return, i.e. are
'diverging', by marking its return type as `!`.
For example, the following functions never return:
```no_run
fn foo() -> ! {
loop {}
}
fn bar() -> ! {
foo() // foo() is diverging, so this will diverge too
}
fn baz() -> ! {
panic!(); // this macro internally expands to a call to a diverging function
}
```
Such functions can be used in a place where a value is expected without
returning a value of that type, for instance:
```no_run
fn foo() -> ! {
loop {}
}
let x = 3;
let y = match x {
1 => 1,
2 => 4,
_ => foo() // diverging function called here
};
println!("{}", y)
```
If the third arm of the match block is reached, since `foo()` doesn't ever
return control to the match block, it is fine to use it in a place where an
integer was expected. The `match` block will never finish executing, and any
point where `y` (like the print statement) is needed will not be reached.
However, if we had a diverging function that actually does finish execution:
```ignore
fn foo() -> ! {
loop {break;}
}
```
Then we would have an unknown value for `y` in the following code:
```no_run
fn foo() -> ! {
loop {}
}
let x = 3;
let y = match x {
1 => 1,
2 => 4,
_ => foo()
};
println!("{}", y);
```
In the previous example, the print statement was never reached when the
wildcard match arm was hit, so we were okay with `foo()` not returning an
integer that we could set to `y`. But in this example, `foo()` actually does
return control, so the print statement will be executed with an uninitialized
value.
Obviously we cannot have functions which are allowed to be used in such
positions and yet can return control. So, if you are defining a function that
returns `!`, make sure that there is no way for it to actually finish
executing.
"##,
E0271: r##"
This is because of a type mismatch between the associated type of some
trait (e.g. `T::Bar`, where `T` implements `trait Quux { type Bar; }`)

View File

@ -138,7 +138,7 @@ pub trait Visitor<'v> : Sized {
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
walk_where_predicate(self, predicate)
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) {
walk_fn(self, fk, fd, b, s, id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
@ -635,13 +635,13 @@ 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,
function_body: &'v Block,
function_body: &'v Expr,
_span: Span,
id: NodeId) {
visitor.visit_id(id);
walk_fn_decl(visitor, function_declaration);
walk_fn_kind(visitor, function_kind);
visitor.visit_block(function_body)
visitor.visit_expr(function_body)
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
@ -925,7 +925,7 @@ impl<'v> Visitor<'v> for IdRangeComputingVisitor {
/// Computes the id range for a single fn body, ignoring nested items.
pub fn compute_id_range_for_fn_body(fk: FnKind,
decl: &FnDecl,
body: &Block,
body: &Expr,
sp: Span,
id: NodeId)
-> IdRange {

View File

@ -595,12 +595,13 @@ impl<'a> LoweringContext<'a> {
hir::ItemConst(self.lower_ty(t), self.lower_expr(e))
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
let body = self.lower_block(body);
hir::ItemFn(self.lower_fn_decl(decl),
self.lower_unsafety(unsafety),
self.lower_constness(constness),
abi,
self.lower_generics(generics),
self.lower_block(body))
self.expr_block(body, ThinVec::new()))
}
ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
@ -665,7 +666,10 @@ impl<'a> LoweringContext<'a> {
}
TraitItemKind::Method(ref sig, ref body) => {
hir::MethodTraitItem(this.lower_method_sig(sig),
body.as_ref().map(|x| this.lower_block(x)))
body.as_ref().map(|x| {
let body = this.lower_block(x);
this.expr_block(body, ThinVec::new())
}))
}
TraitItemKind::Type(ref bounds, ref default) => {
hir::TypeTraitItem(this.lower_bounds(bounds),
@ -691,8 +695,9 @@ impl<'a> LoweringContext<'a> {
hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr))
}
ImplItemKind::Method(ref sig, ref body) => {
let body = this.lower_block(body);
hir::ImplItemKind::Method(this.lower_method_sig(sig),
this.lower_block(body))
this.expr_block(body, ThinVec::new()))
}
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@ -1110,7 +1115,7 @@ impl<'a> LoweringContext<'a> {
self.with_parent_def(e.id, |this| {
hir::ExprClosure(this.lower_capture_clause(capture_clause),
this.lower_fn_decl(decl),
this.lower_block(body),
this.lower_expr(body),
fn_decl_span)
})
}

View File

@ -21,11 +21,9 @@
//! nested within a uniquely determined `FnLike`), and users can ask
//! for the `Code` associated with a particular NodeId.
pub use self::Code::*;
use hir as ast;
use hir::map::{self, Node};
use hir::{Block, FnDecl};
use hir::{Expr, FnDecl};
use hir::intravisit::FnKind;
use syntax::abi;
use syntax::ast::{Attribute, Name, NodeId};
@ -50,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: &'a Block,
pub body: &'a Expr,
pub kind: FnKind<'a>,
pub span: Span,
pub id: NodeId,
@ -77,29 +75,32 @@ impl MaybeFnLike for ast::Expr {
}
}
/// Carries either an FnLikeNode or a Block, as these are the two
/// Carries either an FnLikeNode or a Expr, as these are the two
/// constructs that correspond to "code" (as in, something from which
/// we can construct a control-flow graph).
#[derive(Copy, Clone)]
pub enum Code<'a> {
FnLikeCode(FnLikeNode<'a>),
BlockCode(&'a Block),
FnLike(FnLikeNode<'a>),
Expr(&'a Expr),
}
impl<'a> Code<'a> {
pub fn id(&self) -> NodeId {
match *self {
FnLikeCode(node) => node.id(),
BlockCode(block) => block.id,
Code::FnLike(node) => node.id(),
Code::Expr(block) => block.id,
}
}
/// Attempts to construct a Code from presumed FnLike or Block node input.
pub fn from_node(node: Node) -> Option<Code> {
if let map::NodeBlock(block) = node {
Some(BlockCode(block))
} else {
FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like))
/// Attempts to construct a Code from presumed FnLike or Expr node input.
pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option<Code<'a>> {
match map.get(id) {
map::NodeBlock(_) => {
// Use the parent, hopefully an expression node.
Code::from_node(map, map.get_parent_node(id))
}
map::NodeExpr(expr) => Some(Code::Expr(expr)),
node => FnLikeNode::from_node(node).map(Code::FnLike)
}
}
}
@ -114,7 +115,7 @@ struct ItemFnParts<'a> {
abi: abi::Abi,
vis: &'a ast::Visibility,
generics: &'a ast::Generics,
body: &'a Block,
body: &'a Expr,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
@ -124,14 +125,14 @@ struct ItemFnParts<'a> {
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
decl: &'a FnDecl,
body: &'a Block,
body: &'a Expr,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
}
impl<'a> ClosureParts<'a> {
fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
fn new(d: &'a FnDecl, b: &'a Expr, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
ClosureParts {
decl: d,
body: b,
@ -171,9 +172,9 @@ impl<'a> FnLikeNode<'a> {
}
}
pub fn body(self) -> &'a Block {
pub fn body(self) -> &'a Expr {
self.handle(|i: ItemFnParts<'a>| &*i.body,
|_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _, _| body,
|_, _, _: &'a ast::MethodSig, _, body: &'a ast::Expr, _, _| body,
|c: ClosureParts<'a>| c.body)
}
@ -214,7 +215,7 @@ impl<'a> FnLikeNode<'a> {
Name,
&'a ast::MethodSig,
Option<&'a ast::Visibility>,
&'a ast::Block,
&'a ast::Expr,
Span,
&'a [Attribute])
-> A,

View File

@ -211,7 +211,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
}
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
b: &'ast Block, s: Span, id: NodeId) {
b: &'ast Expr, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
intravisit::walk_fn(self, fk, fd, b, s, id);
}

View File

@ -904,7 +904,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>, P<Block>, Span),
ExprClosure(CaptureClause, P<FnDecl>, P<Expr>, Span),
/// A block (`{ ... }`)
ExprBlock(P<Block>),
@ -1035,7 +1035,7 @@ pub enum TraitItem_ {
/// must contain a value)
ConstTraitItem(P<Ty>, Option<P<Expr>>),
/// A method with an optional body
MethodTraitItem(MethodSig, Option<P<Block>>),
MethodTraitItem(MethodSig, Option<P<Expr>>),
/// An associated type with (possibly empty) bounds and optional concrete
/// type
TypeTraitItem(TyParamBounds, Option<P<Ty>>),
@ -1060,7 +1060,7 @@ pub enum ImplItemKind {
/// of the expression
Const(P<Ty>, P<Expr>),
/// A method implementation with the given signature and body
Method(MethodSig, P<Block>),
Method(MethodSig, P<Expr>),
/// An associated type
Type(P<Ty>),
}
@ -1501,7 +1501,7 @@ pub enum Item_ {
/// A `const` item
ItemConst(P<Ty>, P<Expr>),
/// A function declaration
ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>),
ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Expr>),
/// A module
ItemMod(Mod),
/// An external module

View File

@ -713,7 +713,9 @@ impl<'a> State<'a> {
typarams,
&item.vis)?;
word(&mut self.s, " ")?;
self.print_block_with_attrs(&body, &item.attrs)?;
self.end()?; // need to close a box
self.end()?; // need to close a box
self.print_expr(&body)?;
}
hir::ItemMod(ref _mod) => {
self.head(&visibility_qualified(&item.vis, "mod"))?;
@ -1002,7 +1004,9 @@ impl<'a> State<'a> {
self.print_method_sig(ti.name, sig, &hir::Inherited)?;
if let Some(ref body) = *body {
self.nbsp()?;
self.print_block_with_attrs(body, &ti.attrs)?;
self.end()?; // need to close a box
self.end()?; // need to close a box
self.print_expr(body)?;
} else {
word(&mut self.s, ";")?;
}
@ -1034,7 +1038,9 @@ impl<'a> State<'a> {
self.head("")?;
self.print_method_sig(ii.name, sig, &ii.vis)?;
self.nbsp()?;
self.print_block_with_attrs(body, &ii.attrs)?;
self.end()?; // need to close a box
self.end()?; // need to close a box
self.print_expr(body)?;
}
hir::ImplItemKind::Type(ref ty) => {
self.print_associated_type(ii.name, None, Some(ty))?;
@ -1402,26 +1408,10 @@ impl<'a> State<'a> {
self.print_fn_block_args(&decl)?;
space(&mut self.s)?;
let default_return = match decl.output {
hir::DefaultReturn(..) => true,
_ => false,
};
// this is a bare expression
self.print_expr(body)?;
self.end()?; // need to close a box
if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
self.print_block_unclosed(&body)?;
} else {
// we extract the block, so as not to create another set of boxes
match body.expr.as_ref().unwrap().node {
hir::ExprBlock(ref blk) => {
self.print_block_unclosed(&blk)?;
}
_ => {
// this is a bare expression
self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap())?;
self.end()?; // need to close a box
}
}
}
// a box will be closed by print_expr, but we didn't want an overall
// wrapper so we closed the corresponding opening. so create an
// empty box to satisfy the close.

View File

@ -838,7 +838,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
body: &'v hir::Block, span: Span, id: ast::NodeId) {
body: &'v hir::Expr, span: Span, id: ast::NodeId) {
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
hir_visit::walk_fn(self, fk, decl, body, span, id);
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);

View File

@ -151,9 +151,9 @@ pub trait LateLintPass: LintPass {
fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { }
fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { }
fn check_fn(&mut self, _: &LateContext,
_: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { }
_: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { }
fn check_fn_post(&mut self, _: &LateContext,
_: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { }
_: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { }
fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { }
fn check_trait_item_post(&mut self, _: &LateContext, _: &hir::TraitItem) { }
fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { }

View File

@ -498,7 +498,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, blk: &hir::Block) {
pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) {
//! Performs the data flow analysis.
if self.bits_per_id == 0 {
@ -524,17 +524,17 @@ 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, blk).unwrap();
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>,
blk: &hir::Block) -> io::Result<()> {
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_block(blk)?;
ps.print_expr(body)?;
pp::eof(&mut ps.s)
}
}

View File

@ -567,7 +567,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.name, "method");
}
intravisit::walk_block(self, body)
intravisit::walk_expr(self, body)
}
hir::ImplItemKind::Type(..) => {}
}
@ -576,11 +576,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
// Overwrite so that we don't warn the trait item itself.
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
match trait_item.node {
hir::ConstTraitItem(_, Some(ref expr)) => {
intravisit::walk_expr(self, expr)
}
hir::ConstTraitItem(_, Some(ref body))|
hir::MethodTraitItem(_, Some(ref body)) => {
intravisit::walk_block(self, body)
intravisit::walk_expr(self, body)
}
hir::ConstTraitItem(_, None) |
hir::MethodTraitItem(_, None) |

View File

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

View File

@ -290,14 +290,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
pub fn walk_fn(&mut self,
decl: &hir::FnDecl,
body: &hir::Block) {
body: &hir::Expr) {
self.walk_arg_patterns(decl, body);
self.walk_block(body);
self.consume_expr(body);
}
fn walk_arg_patterns(&mut self,
decl: &hir::FnDecl,
body: &hir::Block) {
body: &hir::Expr) {
for arg in &decl.inputs {
let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));

View File

@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, id: ast::NodeId) {
b: &'v hir::Expr, s: Span, id: ast::NodeId) {
if let FnKind::Closure(..) = fk {
span_bug!(s, "intrinsicck: closure outside of function")
}

View File

@ -123,10 +123,9 @@ use std::io::prelude::*;
use std::io;
use std::rc::Rc;
use syntax::ast::{self, NodeId};
use syntax::codemap::original_sp;
use syntax::parse::token::keywords;
use syntax::ptr::P;
use syntax_pos::{BytePos, Span};
use syntax_pos::Span;
use hir::Expr;
use hir;
@ -187,7 +186,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt) -> String {
impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, id: NodeId) {
b: &'v hir::Expr, s: Span, id: NodeId) {
visit_fn(self, fk, fd, b, s, id);
}
fn visit_local(&mut self, l: &hir::Local) { visit_local(self, l); }
@ -352,9 +351,9 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
}
impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, n: NodeId) {
check_fn(self, fk, fd, b, s, n);
fn visit_fn(&mut self, _: FnKind<'v>, _: &'v hir::FnDecl,
_: &'v hir::Expr, _: Span, _: NodeId) {
// do not check contents of nested fns
}
fn visit_local(&mut self, l: &hir::Local) {
check_local(self, l);
@ -370,7 +369,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> {
fn visit_fn(ir: &mut IrMaps,
fk: FnKind,
decl: &hir::FnDecl,
body: &hir::Block,
body: &hir::Expr,
sp: Span,
id: ast::NodeId) {
debug!("visit_fn");
@ -405,10 +404,10 @@ fn visit_fn(ir: &mut IrMaps,
// compute liveness
let mut lsets = Liveness::new(&mut fn_maps, specials);
let entry_ln = lsets.compute(decl, body);
let entry_ln = lsets.compute(body);
// check for various error conditions
lsets.visit_block(body);
lsets.visit_expr(body);
lsets.check_ret(id, sp, fk, entry_ln, body);
lsets.warn_about_unused_args(decl, entry_ln);
}
@ -821,17 +820,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// _______________________________________________________________________
fn compute(&mut self, decl: &hir::FnDecl, body: &hir::Block) -> LiveNode {
fn compute(&mut self, body: &hir::Expr) -> LiveNode {
// if there is a `break` or `again` at the top level, then it's
// effectively a return---this only occurs in `for` loops,
// where the body is really a closure.
debug!("compute: using id for block, {}", block_to_string(body));
debug!("compute: using id for body, {}", expr_to_string(body));
let exit_ln = self.s.exit_ln;
let entry_ln: LiveNode =
self.with_loop_nodes(body.id, exit_ln, exit_ln,
|this| this.propagate_through_fn_block(decl, body));
let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| {
// the fallthrough exit is only for those cases where we do not
// explicitly return:
let s = this.s;
this.init_from_succ(s.fallthrough_ln, s.exit_ln);
this.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ);
this.propagate_through_expr(body, s.fallthrough_ln)
});
// hack to skip the loop unless debug! is enabled:
debug!("^^ liveness computation results for body {} (entry={:?})",
@ -846,20 +851,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
entry_ln
}
fn propagate_through_fn_block(&mut self, _: &hir::FnDecl, blk: &hir::Block)
-> LiveNode {
// the fallthrough exit is only for those cases where we do not
// explicitly return:
let s = self.s;
self.init_from_succ(s.fallthrough_ln, s.exit_ln);
if blk.expr.is_none() {
self.acc(s.fallthrough_ln, s.no_ret_var, ACC_READ)
}
self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ);
self.propagate_through_block(blk, s.fallthrough_ln)
}
fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
-> LiveNode {
let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
@ -1448,15 +1439,6 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
}
}
fn check_fn(_v: &Liveness,
_fk: FnKind,
_decl: &hir::FnDecl,
_body: &hir::Block,
_sp: Span,
_id: NodeId) {
// do not check contents of nested fns
}
impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::Binder<Ty<'tcx>> {
let fn_ty = self.ir.tcx.tables().node_id_to_type(id);
@ -1472,7 +1454,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
sp: Span,
_fk: FnKind,
entry_ln: LiveNode,
body: &hir::Block)
body: &hir::Expr)
{
// within the fn body, late-bound regions are liberated
// and must outlive the *call-site* of the function.
@ -1481,13 +1463,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.ir.tcx.region_maps.call_site_extent(id, body.id),
&self.fn_ret(id));
if fn_ret.is_never() {
// FIXME(durka) this rejects code like `fn foo(x: !) -> ! { x }`
if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() {
span_err!(self.ir.tcx.sess, sp, E0270,
"computation may converge in a function marked as diverging");
}
} else if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
@ -1498,32 +1474,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// for nil return types, it is ok to not return a value expl.
if !is_nil {
let ends_with_stmt = match body.expr {
None if !body.stmts.is_empty() =>
match body.stmts.last().unwrap().node {
hir::StmtSemi(ref e, _) => {
self.ir.tcx.tables().expr_ty(&e) == fn_ret
},
_ => false
},
_ => false
};
let mut err = struct_span_err!(self.ir.tcx.sess,
sp,
E0269,
"not all control paths return a value");
if ends_with_stmt {
let last_stmt = body.stmts.last().unwrap();
let original_span = original_sp(self.ir.tcx.sess.codemap(),
last_stmt.span, sp);
let span_semicolon = Span {
lo: original_span.hi - BytePos(1),
hi: original_span.hi,
expn_id: original_span.expn_id
};
err.span_help(span_semicolon, "consider removing this semicolon:");
}
err.emit();
span_bug!(sp, "not all control paths return a value");
}
}
}

View File

@ -248,9 +248,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
match *node {
ast_map::NodeItem(item) => {
match item.node {
hir::ItemFn(.., ref search_block) => {
hir::ItemFn(.., ref body) => {
if item_might_be_inlined(&item) {
intravisit::walk_block(self, &search_block)
self.visit_expr(body);
}
}
@ -278,11 +278,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
hir::MethodTraitItem(_, None) => {
// Keep going, nothing to get exported
}
hir::ConstTraitItem(_, Some(ref expr)) => {
self.visit_expr(&expr);
}
hir::ConstTraitItem(_, Some(ref body)) |
hir::MethodTraitItem(_, Some(ref body)) => {
intravisit::walk_block(self, body);
self.visit_expr(body);
}
hir::TypeTraitItem(..) => {}
}
@ -295,7 +293,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
hir::ImplItemKind::Method(ref sig, ref body) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, sig, impl_item, did) {
intravisit::walk_block(self, body)
self.visit_expr(body)
}
}
hir::ImplItemKind::Type(_) => {}

View File

@ -490,12 +490,7 @@ impl RegionMaps {
// if there's one. Static items, for instance, won't
// have an enclosing scope, hence no scope will be
// returned.
let expr_extent = self.node_extent(expr_id);
// For some reason, the expr's scope itself is skipped here.
let mut id = match scope_map[expr_extent.0 as usize].into_option() {
Some(i) => i,
_ => return None
};
let mut id = self.node_extent(expr_id);
while let Some(p) = scope_map[id.0 as usize].into_option() {
match code_extents[p.0 as usize] {
@ -1086,7 +1081,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) {
fn resolve_fn(visitor: &mut RegionResolutionVisitor,
kind: FnKind,
decl: &hir::FnDecl,
body: &hir::Block,
body: &hir::Expr,
sp: Span,
id: ast::NodeId) {
debug!("region::resolve_fn(id={:?}, \
@ -1128,7 +1123,7 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
parent: fn_decl_scope,
var_parent: fn_decl_scope
};
visitor.visit_block(body);
visitor.visit_expr(body);
// Restore context we had at the start.
visitor.cx = outer_cx;
@ -1191,7 +1186,7 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
b: &'v Block, s: Span, n: NodeId) {
b: &'v Expr, s: Span, n: NodeId) {
resolve_fn(self, fk, fd, b, s, n);
}
fn visit_arm(&mut self, a: &Arm) {

View File

@ -202,7 +202,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
self.visit_early_late(fn_id,decl, generics, |this| {
@ -403,7 +403,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::Block) {
fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) {
struct GatherLabels<'a> {
sess: &'a Session,
scope: Scope<'a>,
@ -415,7 +415,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) {
scope: ctxt.scope,
labels_in_fn: &mut ctxt.labels_in_fn,
};
gather.visit_block(b);
gather.visit_expr(b);
return;
impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
@ -493,7 +493,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn add_scope_and_walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
fb: &'b hir::Block,
fb: &'b hir::Expr,
_span: Span,
fn_id: ast::NodeId) {
@ -516,7 +516,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
extract_labels(self, fb);
self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope },
|_old_scope, this| this.visit_block(fb))
|_old_scope, this| this.visit_expr(fb))
}
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where

View File

@ -190,7 +190,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
all_loans: &[Loan<'tcx>],
fn_id: ast::NodeId,
decl: &hir::FnDecl,
body: &hir::Block) {
body: &hir::Expr) {
debug!("check_loans(body id={})", body.id);
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);

View File

@ -42,7 +42,7 @@ mod move_error;
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
fn_id: NodeId,
decl: &hir::FnDecl,
body: &hir::Block)
body: &hir::Expr)
-> (Vec<Loan<'tcx>>,
move_data::MoveData<'tcx>) {
let mut glcx = GatherLoanCtxt {

View File

@ -58,7 +58,7 @@ pub struct MoveDataParamEnv<'tcx> {
pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
fk: FnKind,
_decl: &hir::FnDecl,
body: &hir::Block,
body: &hir::Expr,
_sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {

View File

@ -47,9 +47,7 @@ use syntax_pos::{MultiSpan, Span};
use errors::DiagnosticBuilder;
use rustc::hir;
use rustc::hir::{FnDecl, Block};
use rustc::hir::intravisit;
use rustc::hir::intravisit::{Visitor, FnKind};
use rustc::hir::intravisit::{self, Visitor, FnKind};
pub mod check_loans;
@ -65,8 +63,8 @@ pub struct LoanDataFlowOperator;
pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
b: &'v Block, s: Span, id: ast::NodeId) {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Expr, s: Span, id: ast::NodeId) {
match fk {
FnKind::ItemFn(..) |
FnKind::Method(..) => {
@ -159,7 +157,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
fn borrowck_fn(this: &mut BorrowckCtxt,
fk: FnKind,
decl: &hir::FnDecl,
body: &hir::Block,
body: &hir::Expr,
sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
@ -200,7 +198,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
fk: FnKind,
decl: &hir::FnDecl,
cfg: &cfg::CFG,
body: &hir::Block,
body: &hir::Expr,
sp: Span,
id: ast::NodeId)
-> AnalysisData<'a, 'tcx>

View File

@ -656,7 +656,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
cfg: &cfg::CFG,
id_range: IdRange,
decl: &hir::FnDecl,
body: &hir::Block)
body: &hir::Expr)
-> FlowedMoveData<'a, 'tcx> {
let mut dfcx_moves =
DataFlowContext::new(tcx,

View File

@ -65,7 +65,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, id: ast::NodeId) {
b: &'v hir::Expr, s: Span, id: ast::NodeId) {
if let FnKind::Closure(..) = fk {
span_bug!(s, "check_match: closure outside of function")
}
@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, n: ast::NodeId) {
b: &'v hir::Expr, s: Span, n: ast::NodeId) {
intravisit::walk_fn(self, fk, fd, b, s, n);
for input in &fd.inputs {

View File

@ -857,11 +857,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
callee => signal!(e, CallOn(callee)),
};
let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
(fn_like.decl(), &fn_like.body().expr)
(fn_like.decl(), fn_like.body())
} else {
signal!(e, NonConstPath)
};
let result = result.as_ref().expect("const fn has no result expression");
assert_eq!(decl.inputs.len(), args.len());
let mut call_args = DefIdMap();

View File

@ -701,8 +701,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
mut out: W)
-> io::Result<()> {
let cfg = match code {
blocks::BlockCode(block) => cfg::CFG::new(tcx, &block),
blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &fn_like.body()),
blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
blocks::Code::FnLike(fn_like) => cfg::CFG::new(tcx, fn_like.body()),
};
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
let lcfg = LabelledCFG {
@ -717,12 +717,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
let r = dot::render(&lcfg, &mut out);
return expand_err_details(r);
}
blocks::BlockCode(_) => {
blocks::Code::Expr(_) => {
tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \
fn-like node id.");
return Ok(());
}
blocks::FnLikeCode(fn_like) => {
blocks::Code::FnLike(fn_like) => {
let (bccx, analysis_data) =
borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.to_fn_parts(), &cfg);
@ -990,8 +990,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid))
});
let code = blocks::Code::from_node(node);
match code {
match blocks::Code::from_node(&tcx.map, nodeid) {
Some(code) => {
let variants = gather_flowgraph_variants(tcx.sess);

View File

@ -250,7 +250,7 @@ impl LateLintPass for NonSnakeCase {
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
_: &hir::Expr,
span: Span,
id: ast::NodeId) {
match fk {

View File

@ -222,7 +222,7 @@ impl LateLintPass for UnsafeCode {
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
_: &hir::Expr,
span: Span,
_: ast::NodeId) {
match fk {
@ -812,7 +812,7 @@ impl LateLintPass for UnconditionalRecursion {
cx: &LateContext,
fn_kind: FnKind,
_: &hir::FnDecl,
blk: &hir::Block,
blk: &hir::Expr,
sp: Span,
id: ast::NodeId) {
let method = match fn_kind {

View File

@ -99,7 +99,7 @@ impl LateLintPass for UnusedMut {
cx: &LateContext,
_: FnKind,
decl: &hir::FnDecl,
_: &hir::Block,
_: &hir::Expr,
_: Span,
_: ast::NodeId) {
for a in &decl.inputs {

View File

@ -156,7 +156,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
arguments: A,
return_ty: Ty<'gcx>,
ast_block: &'gcx hir::Block)
ast_body: &'gcx hir::Expr)
-> (Mir<'tcx>, ScopeAuxiliaryVec)
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{
@ -166,7 +166,7 @@ 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_block.id;
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 });
@ -176,7 +176,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
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, return_ty, &arguments, arg_extent, ast_block)
builder.args_and_body(block, &arguments, arg_extent, ast_body)
}));
// Attribute epilogue to function's closing brace
let fn_end = Span { lo: span.hi, ..span };
@ -310,10 +310,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn args_and_body(&mut self,
mut block: BasicBlock,
return_ty: Ty<'tcx>,
arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
argument_extent: CodeExtent,
ast_block: &'gcx hir::Block)
ast_body: &'gcx hir::Expr)
-> BlockAnd<()>
{
// Allocate locals for the function arguments
@ -342,12 +341,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
if let Some(pattern) = pattern {
let pattern = Pattern::from_hir(self.hir.tcx(), pattern);
scope = self.declare_bindings(scope, ast_block.span, &pattern);
scope = self.declare_bindings(scope, ast_body.span, &pattern);
unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
}
// Make sure we drop (parts of) the argument even when not matched on.
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span),
argument_extent, &lvalue, ty);
}
@ -357,13 +356,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
self.visibility_scope = visibility_scope;
}
// FIXME(#32959): temporary hack for the issue at hand
let return_is_unit = return_ty.is_nil();
// start the first basic block and translate the body
unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER),
return_is_unit, block, ast_block));
block.unit()
let body = self.hir.mirror(ast_body);
self.into(&Lvalue::Local(RETURN_POINTER), block, body)
}
fn get_unit_temp(&mut self) -> Lvalue<'tcx> {

View File

@ -209,7 +209,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
fn visit_fn(&mut self,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Block,
body: &'tcx hir::Expr,
span: Span,
id: ast::NodeId) {
// fetch the fully liberated fn signature (that is, all bound

View File

@ -134,7 +134,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
fn fn_like(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
b: &hir::Block,
b: &hir::Expr,
s: Span,
fn_id: ast::NodeId)
-> ConstQualif {
@ -265,7 +265,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
fn visit_fn(&mut self,
fk: FnKind<'v>,
fd: &'v hir::FnDecl,
b: &'v hir::Block,
b: &'v hir::Expr,
s: Span,
fn_id: ast::NodeId) {
self.fn_like(fk, fd, b, s, fn_id);

View File

@ -164,7 +164,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: &'v hir::Block,
b: &'v hir::Expr,
s: Span,
id: NodeId) {
self.record("FnDecl", Id::None, fd);

View File

@ -54,7 +54,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
self.with_context(Loop, |v| v.visit_block(&b));
}
hir::ExprClosure(.., ref b, _) => {
self.with_context(Closure, |v| v.visit_block(&b));
self.with_context(Closure, |v| v.visit_expr(&b));
}
hir::ExprBreak(_) => self.require_loop("break", e.span),
hir::ExprAgain(_) => self.require_loop("continue", e.span),

View File

@ -35,7 +35,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
fn visit_fn(&mut self,
fk: intravisit::FnKind<'v>,
fd: &'v hir::FnDecl,
b: &'v hir::Block,
b: &'v hir::Expr,
s: Span,
fn_id: ast::NodeId) {
// FIXME (@jroesch) change this to be an inference context

View File

@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr: &hir::Expr,
_capture: hir::CaptureClause,
decl: &'gcx hir::FnDecl,
body: &'gcx hir::Block,
body: &'gcx hir::Expr,
expected: Expectation<'tcx>)
-> Ty<'tcx> {
debug!("check_expr_closure(expr={:?},expected={:?})",
@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr: &hir::Expr,
opt_kind: Option<ty::ClosureKind>,
decl: &'gcx hir::FnDecl,
body: &'gcx hir::Block,
body: &'gcx hir::Expr,
expected_sig: Option<ty::FnSig<'tcx>>)
-> Ty<'tcx> {
let expr_def_id = self.tcx.map.local_def_id(expr.id);

View File

@ -534,7 +534,7 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Block,
body: &'tcx hir::Expr,
fn_id: ast::NodeId,
span: Span) {
let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty;
@ -558,7 +558,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze_fn(body);
fcx.closure_analyze(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
@ -654,7 +654,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
// Don't descend into the bodies of nested closures
fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
_: &'gcx hir::Block, _: Span, _: ast::NodeId) { }
_: &'gcx hir::Expr, _: Span, _: ast::NodeId) { }
}
/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
@ -669,7 +669,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::Block)
body: &'gcx hir::Expr)
-> FnCtxt<'a, 'gcx, 'tcx>
{
let mut fn_sig = fn_sig.clone();
@ -709,18 +709,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
fcx.write_ty(input.id, arg_ty);
}
visit.visit_block(body);
visit.visit_expr(body);
}
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
// FIXME(aburka) do we need this special case? and should it be is_uninhabited?
let expected = if fcx.ret_ty.is_never() {
NoExpectation
} else {
ExpectHasType(fcx.ret_ty)
};
fcx.check_block_with_expected(body, expected);
fcx.check_expr_coercable_to_type(body, fcx.ret_ty);
fcx
}
@ -1198,7 +1192,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
fcx.check_expr_coercable_to_type(expr, expected_type);
fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze_const(expr);
fcx.closure_analyze(expr);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error();

View File

@ -142,13 +142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn regionck_fn(&self,
fn_id: ast::NodeId,
decl: &hir::FnDecl,
blk: &hir::Block) {
body: &hir::Expr) {
debug!("regionck_fn(id={})", fn_id);
let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id));
let mut rcx = RegionCtxt::new(self, RepeatingScope(body.id), body.id, Subject(fn_id));
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_fn_body(fn_id, decl, blk, self.tcx.map.span(fn_id));
rcx.visit_fn_body(fn_id, decl, body, self.tcx.map.span(fn_id));
}
rcx.free_region_map.relate_free_regions_from_predicates(
@ -268,7 +268,7 @@ 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: &hir::Block,
body: &hir::Expr,
span: Span)
{
// When we enter a function, we can derive
@ -305,7 +305,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
self.relate_free_regions(&fn_sig_tys[..], body.id, span);
self.link_fn_args(self.tcx.region_maps.node_extent(body.id),
&fn_decl.inputs[..]);
self.visit_block(body);
self.visit_expr(body);
self.visit_region_obligations(body.id);
let call_site_scope = self.call_site_scope.unwrap();
@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
// regions, until regionck, as described in #3238.
fn visit_fn(&mut self, _fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, span: Span, id: ast::NodeId) {
b: &'v hir::Expr, span: Span, id: ast::NodeId) {
self.visit_fn_body(id, fd, b, span)
}
@ -825,7 +825,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
fn check_expr_fn_block(&mut self,
expr: &hir::Expr,
body: &hir::Block) {
body: &hir::Expr) {
let repeating_scope = self.set_repeating_scope(body.id);
intravisit::walk_expr(self, expr);
self.set_repeating_scope(repeating_scope);

View File

@ -57,18 +57,7 @@ use rustc::util::nodemap::NodeMap;
// PUBLIC ENTRY POINTS
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn closure_analyze_fn(&self, body: &hir::Block) {
let mut seed = SeedBorrowKind::new(self);
seed.visit_block(body);
let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
adjust.visit_block(body);
// it's our job to process these.
assert!(self.deferred_call_resolutions.borrow().is_empty());
}
pub fn closure_analyze_const(&self, body: &hir::Expr) {
pub fn closure_analyze(&self, body: &hir::Expr) {
let mut seed = SeedBorrowKind::new(self);
seed.visit_expr(body);
@ -110,7 +99,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
fn check_closure(&mut self,
expr: &hir::Expr,
capture_clause: hir::CaptureClause,
_body: &hir::Block)
_body: &hir::Expr)
{
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) {
@ -164,7 +153,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
id: ast::NodeId,
span: Span,
decl: &hir::FnDecl,
body: &hir::Block) {
body: &hir::Expr) {
/*!
* Analysis starting point.
*/
@ -497,7 +486,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
fn visit_fn(&mut self,
fn_kind: intravisit::FnKind<'v>,
decl: &'v hir::FnDecl,
body: &'v hir::Block,
body: &'v hir::Expr,
span: Span,
id: ast::NodeId)
{

View File

@ -347,7 +347,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
fn check_item_fn(&mut self,
item: &hir::Item,
body: &hir::Block)
body: &hir::Expr)
{
self.for_item(item).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;

View File

@ -49,11 +49,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn resolve_type_vars_in_fn(&self,
decl: &hir::FnDecl,
blk: &hir::Block,
body: &hir::Expr,
item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false);
let mut wbcx = WritebackCx::new(self);
wbcx.visit_block(blk);
wbcx.visit_expr(body);
for arg in &decl.inputs {
wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
wbcx.visit_pat(&arg.pat);