Skip to content

Commit 368281a

Browse files
authored
Rollup merge of rust-lang#37412 - eddyb:lazy-6, r=nikomatsakis
[6/n] rustc: transition HIR function bodies from Block to Expr. _This is part of a series ([prev](rust-lang#37408) | [next](rust-lang#37676)) 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> The main change here is that functions and closures both use `Expr` instead of `Block` for their bodies. For closures this actually allows a honest representation of brace-less closure bodies, e.g. `|x| x + 1` is now distinguishable from `|x| { x + 1 }`, therefore this PR is `[syntax-breaking]` (cc @Manishearth). Using `Expr` allows more logic to be shared between constant bodies and function bodies, with some small such changes already part of this PR, and eventually easing rust-lang#35078 and per-body type tables. Incidentally, there used to be some corners cut here and there and as such I had to (re)write divergence tracking for type-checking so that it is capable of understanding basic structured control-flow: ``` rust fn a(x: bool) -> i32 { // match also works (as long as all arms diverge) if x { panic!("true") } else { return 1; } 0 // "unreachable expression" after this PR } ``` And since liveness' "not all control paths return a value" moved to type-checking we can have nice things: ``` rust // before & after: fn b() -> i32 { 0; } // help: consider removing this semicolon // only after this PR fn c() -> i32 { { 0; } } // help: consider removing this semicolon fn d() { let x: i32 = { 0; }; } // help: consider removing this semicolon fn e() { f({ 0; }); } // help: consider removing this semicolon ```
2 parents 8d4a350 + 8e9106c commit 368281a

File tree

109 files changed

+778
-829
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+778
-829
lines changed

src/libpanic_abort/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
5353
// now hopefully.
5454
#[no_mangle]
5555
pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
56-
return abort();
56+
abort();
5757

5858
#[cfg(unix)]
5959
unsafe fn abort() -> ! {

src/librustc/cfg/construct.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,25 @@ struct LoopScope {
3333
}
3434

3535
pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
36-
blk: &hir::Block) -> CFG {
36+
body: &hir::Expr) -> CFG {
3737
let mut graph = graph::Graph::new();
3838
let entry = graph.add_node(CFGNodeData::Entry);
3939

4040
// `fn_exit` is target of return exprs, which lies somewhere
41-
// outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
41+
// outside input `body`. (Distinguishing `fn_exit` and `body_exit`
4242
// also resolves chicken-and-egg problem that arises if you try to
43-
// have return exprs jump to `block_exit` during construction.)
43+
// have return exprs jump to `body_exit` during construction.)
4444
let fn_exit = graph.add_node(CFGNodeData::Exit);
45-
let block_exit;
45+
let body_exit;
4646

4747
let mut cfg_builder = CFGBuilder {
4848
graph: graph,
4949
fn_exit: fn_exit,
5050
tcx: tcx,
5151
loop_scopes: Vec::new()
5252
};
53-
block_exit = cfg_builder.block(blk, entry);
54-
cfg_builder.add_contained_edge(block_exit, fn_exit);
53+
body_exit = cfg_builder.expr(body, entry);
54+
cfg_builder.add_contained_edge(body_exit, fn_exit);
5555
let CFGBuilder {graph, ..} = cfg_builder;
5656
CFG {graph: graph,
5757
entry: entry,

src/librustc/cfg/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ pub type CFGEdge = graph::Edge<CFGEdgeData>;
5959

6060
impl CFG {
6161
pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
62-
blk: &hir::Block) -> CFG {
63-
construct::construct(tcx, blk)
62+
body: &hir::Expr) -> CFG {
63+
construct::construct(tcx, body)
6464
}
6565

6666
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {

src/librustc/diagnostics.rs

-114
Original file line numberDiff line numberDiff line change
@@ -672,120 +672,6 @@ extern "C" {
672672
```
673673
"##,
674674

675-
E0269: r##"
676-
A returned value was expected but not all control paths return one.
677-
678-
Erroneous code example:
679-
680-
```compile_fail,E0269
681-
fn abracada_FAIL() -> String {
682-
"this won't work".to_string();
683-
// error: not all control paths return a value
684-
}
685-
```
686-
687-
In the previous code, the function is supposed to return a `String`, however,
688-
the code returns nothing (because of the ';'). Another erroneous code would be:
689-
690-
```compile_fail
691-
fn abracada_FAIL(b: bool) -> u32 {
692-
if b {
693-
0
694-
} else {
695-
"a" // It fails because an `u32` was expected and something else is
696-
// returned.
697-
}
698-
}
699-
```
700-
701-
It is advisable to find out what the unhandled cases are and check for them,
702-
returning an appropriate value or panicking if necessary. Check if you need
703-
to remove a semicolon from the last expression, like in the first erroneous
704-
code example.
705-
"##,
706-
707-
E0270: r##"
708-
Rust lets you define functions which are known to never return, i.e. are
709-
'diverging', by marking its return type as `!`.
710-
711-
For example, the following functions never return:
712-
713-
```no_run
714-
fn foo() -> ! {
715-
loop {}
716-
}
717-
718-
fn bar() -> ! {
719-
foo() // foo() is diverging, so this will diverge too
720-
}
721-
722-
fn baz() -> ! {
723-
panic!(); // this macro internally expands to a call to a diverging function
724-
}
725-
```
726-
727-
Such functions can be used in a place where a value is expected without
728-
returning a value of that type, for instance:
729-
730-
```no_run
731-
fn foo() -> ! {
732-
loop {}
733-
}
734-
735-
let x = 3;
736-
737-
let y = match x {
738-
1 => 1,
739-
2 => 4,
740-
_ => foo() // diverging function called here
741-
};
742-
743-
println!("{}", y)
744-
```
745-
746-
If the third arm of the match block is reached, since `foo()` doesn't ever
747-
return control to the match block, it is fine to use it in a place where an
748-
integer was expected. The `match` block will never finish executing, and any
749-
point where `y` (like the print statement) is needed will not be reached.
750-
751-
However, if we had a diverging function that actually does finish execution:
752-
753-
```ignore
754-
fn foo() -> ! {
755-
loop {break;}
756-
}
757-
```
758-
759-
Then we would have an unknown value for `y` in the following code:
760-
761-
```no_run
762-
fn foo() -> ! {
763-
loop {}
764-
}
765-
766-
let x = 3;
767-
768-
let y = match x {
769-
1 => 1,
770-
2 => 4,
771-
_ => foo()
772-
};
773-
774-
println!("{}", y);
775-
```
776-
777-
In the previous example, the print statement was never reached when the
778-
wildcard match arm was hit, so we were okay with `foo()` not returning an
779-
integer that we could set to `y`. But in this example, `foo()` actually does
780-
return control, so the print statement will be executed with an uninitialized
781-
value.
782-
783-
Obviously we cannot have functions which are allowed to be used in such
784-
positions and yet can return control. So, if you are defining a function that
785-
returns `!`, make sure that there is no way for it to actually finish
786-
executing.
787-
"##,
788-
789675
E0271: r##"
790676
This is because of a type mismatch between the associated type of some
791677
trait (e.g. `T::Bar`, where `T` implements `trait Quux { type Bar; }`)

src/librustc/hir/intravisit.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ pub trait Visitor<'v> : Sized {
138138
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
139139
walk_where_predicate(self, predicate)
140140
}
141-
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) {
141+
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) {
142142
walk_fn(self, fk, fd, b, s, id)
143143
}
144144
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<'
635635
pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
636636
function_kind: FnKind<'v>,
637637
function_declaration: &'v FnDecl,
638-
function_body: &'v Block,
638+
function_body: &'v Expr,
639639
_span: Span,
640640
id: NodeId) {
641641
visitor.visit_id(id);
642642
walk_fn_decl(visitor, function_declaration);
643643
walk_fn_kind(visitor, function_kind);
644-
visitor.visit_block(function_body)
644+
visitor.visit_expr(function_body)
645645
}
646646

647647
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 {
925925
/// Computes the id range for a single fn body, ignoring nested items.
926926
pub fn compute_id_range_for_fn_body(fk: FnKind,
927927
decl: &FnDecl,
928-
body: &Block,
928+
body: &Expr,
929929
sp: Span,
930930
id: NodeId)
931931
-> IdRange {

src/librustc/hir/lowering.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -595,12 +595,13 @@ impl<'a> LoweringContext<'a> {
595595
hir::ItemConst(self.lower_ty(t), self.lower_expr(e))
596596
}
597597
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
598+
let body = self.lower_block(body);
598599
hir::ItemFn(self.lower_fn_decl(decl),
599600
self.lower_unsafety(unsafety),
600601
self.lower_constness(constness),
601602
abi,
602603
self.lower_generics(generics),
603-
self.lower_block(body))
604+
self.expr_block(body, ThinVec::new()))
604605
}
605606
ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
606607
ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
@@ -665,7 +666,10 @@ impl<'a> LoweringContext<'a> {
665666
}
666667
TraitItemKind::Method(ref sig, ref body) => {
667668
hir::MethodTraitItem(this.lower_method_sig(sig),
668-
body.as_ref().map(|x| this.lower_block(x)))
669+
body.as_ref().map(|x| {
670+
let body = this.lower_block(x);
671+
this.expr_block(body, ThinVec::new())
672+
}))
669673
}
670674
TraitItemKind::Type(ref bounds, ref default) => {
671675
hir::TypeTraitItem(this.lower_bounds(bounds),
@@ -691,8 +695,9 @@ impl<'a> LoweringContext<'a> {
691695
hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr))
692696
}
693697
ImplItemKind::Method(ref sig, ref body) => {
698+
let body = this.lower_block(body);
694699
hir::ImplItemKind::Method(this.lower_method_sig(sig),
695-
this.lower_block(body))
700+
this.expr_block(body, ThinVec::new()))
696701
}
697702
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
698703
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@@ -1110,7 +1115,7 @@ impl<'a> LoweringContext<'a> {
11101115
self.with_parent_def(e.id, |this| {
11111116
hir::ExprClosure(this.lower_capture_clause(capture_clause),
11121117
this.lower_fn_decl(decl),
1113-
this.lower_block(body),
1118+
this.lower_expr(body),
11141119
fn_decl_span)
11151120
})
11161121
}

src/librustc/hir/map/blocks.rs

+22-21
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@
2121
//! nested within a uniquely determined `FnLike`), and users can ask
2222
//! for the `Code` associated with a particular NodeId.
2323
24-
pub use self::Code::*;
25-
2624
use hir as ast;
2725
use hir::map::{self, Node};
28-
use hir::{Block, FnDecl};
26+
use hir::{Expr, FnDecl};
2927
use hir::intravisit::FnKind;
3028
use syntax::abi;
3129
use syntax::ast::{Attribute, Name, NodeId};
@@ -50,7 +48,7 @@ pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
5048
/// Components shared by fn-like things (fn items, methods, closures).
5149
pub struct FnParts<'a> {
5250
pub decl: &'a FnDecl,
53-
pub body: &'a Block,
51+
pub body: &'a Expr,
5452
pub kind: FnKind<'a>,
5553
pub span: Span,
5654
pub id: NodeId,
@@ -77,29 +75,32 @@ impl MaybeFnLike for ast::Expr {
7775
}
7876
}
7977

80-
/// Carries either an FnLikeNode or a Block, as these are the two
78+
/// Carries either an FnLikeNode or a Expr, as these are the two
8179
/// constructs that correspond to "code" (as in, something from which
8280
/// we can construct a control-flow graph).
8381
#[derive(Copy, Clone)]
8482
pub enum Code<'a> {
85-
FnLikeCode(FnLikeNode<'a>),
86-
BlockCode(&'a Block),
83+
FnLike(FnLikeNode<'a>),
84+
Expr(&'a Expr),
8785
}
8886

8987
impl<'a> Code<'a> {
9088
pub fn id(&self) -> NodeId {
9189
match *self {
92-
FnLikeCode(node) => node.id(),
93-
BlockCode(block) => block.id,
90+
Code::FnLike(node) => node.id(),
91+
Code::Expr(block) => block.id,
9492
}
9593
}
9694

97-
/// Attempts to construct a Code from presumed FnLike or Block node input.
98-
pub fn from_node(node: Node) -> Option<Code> {
99-
if let map::NodeBlock(block) = node {
100-
Some(BlockCode(block))
101-
} else {
102-
FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like))
95+
/// Attempts to construct a Code from presumed FnLike or Expr node input.
96+
pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option<Code<'a>> {
97+
match map.get(id) {
98+
map::NodeBlock(_) => {
99+
// Use the parent, hopefully an expression node.
100+
Code::from_node(map, map.get_parent_node(id))
101+
}
102+
map::NodeExpr(expr) => Some(Code::Expr(expr)),
103+
node => FnLikeNode::from_node(node).map(Code::FnLike)
103104
}
104105
}
105106
}
@@ -114,7 +115,7 @@ struct ItemFnParts<'a> {
114115
abi: abi::Abi,
115116
vis: &'a ast::Visibility,
116117
generics: &'a ast::Generics,
117-
body: &'a Block,
118+
body: &'a Expr,
118119
id: NodeId,
119120
span: Span,
120121
attrs: &'a [Attribute],
@@ -124,14 +125,14 @@ struct ItemFnParts<'a> {
124125
/// for use when implementing FnLikeNode operations.
125126
struct ClosureParts<'a> {
126127
decl: &'a FnDecl,
127-
body: &'a Block,
128+
body: &'a Expr,
128129
id: NodeId,
129130
span: Span,
130131
attrs: &'a [Attribute],
131132
}
132133

133134
impl<'a> ClosureParts<'a> {
134-
fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
135+
fn new(d: &'a FnDecl, b: &'a Expr, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
135136
ClosureParts {
136137
decl: d,
137138
body: b,
@@ -171,9 +172,9 @@ impl<'a> FnLikeNode<'a> {
171172
}
172173
}
173174

174-
pub fn body(self) -> &'a Block {
175+
pub fn body(self) -> &'a Expr {
175176
self.handle(|i: ItemFnParts<'a>| &*i.body,
176-
|_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _, _| body,
177+
|_, _, _: &'a ast::MethodSig, _, body: &'a ast::Expr, _, _| body,
177178
|c: ClosureParts<'a>| c.body)
178179
}
179180

@@ -214,7 +215,7 @@ impl<'a> FnLikeNode<'a> {
214215
Name,
215216
&'a ast::MethodSig,
216217
Option<&'a ast::Visibility>,
217-
&'a ast::Block,
218+
&'a ast::Expr,
218219
Span,
219220
&'a [Attribute])
220221
-> A,

src/librustc/hir/map/collector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
211211
}
212212

213213
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
214-
b: &'ast Block, s: Span, id: NodeId) {
214+
b: &'ast Expr, s: Span, id: NodeId) {
215215
assert_eq!(self.parent_node, id);
216216
intravisit::walk_fn(self, fk, fd, b, s, id);
217217
}

0 commit comments

Comments
 (0)