Skip to content

Commit 254f201

Browse files
committed
Auto merge of #61988 - Centril:there-is-only-loop, r=matthewjasper
[let_chains, 3/6] And then there was only Loop Here we remove `hir::ExprKind::While`. Instead, we desugar: `'label: while $cond $body` into: ```rust 'label: loop { match DropTemps($cond) { true => $body, _ => break, } } ``` Per #53667 (comment). This is a follow up to #59288 which did the same for `if` expressions. r? @matthewjasper
2 parents b820c76 + 9b1d513 commit 254f201

Some content is hidden

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

52 files changed

+409
-487
lines changed

src/librustc/cfg/construct.rs

-42
Original file line numberDiff line numberDiff line change
@@ -165,48 +165,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
165165
self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
166166
}
167167

168-
hir::ExprKind::While(ref cond, ref body, _) => {
169-
//
170-
// [pred]
171-
// |
172-
// v 1
173-
// [loopback] <--+ 5
174-
// | |
175-
// v 2 |
176-
// +-----[cond] |
177-
// | | |
178-
// | v 4 |
179-
// | [body] -----+
180-
// v 3
181-
// [expr]
182-
//
183-
// Note that `break` and `continue` statements
184-
// may cause additional edges.
185-
186-
let loopback = self.add_dummy_node(&[pred]); // 1
187-
188-
// Create expr_exit without pred (cond_exit)
189-
let expr_exit = self.add_ast_node(expr.hir_id.local_id, &[]); // 3
190-
191-
// The LoopScope needs to be on the loop_scopes stack while evaluating the
192-
// condition and the body of the loop (both can break out of the loop)
193-
self.loop_scopes.push(LoopScope {
194-
loop_id: expr.hir_id.local_id,
195-
continue_index: loopback,
196-
break_index: expr_exit
197-
});
198-
199-
let cond_exit = self.expr(&cond, loopback); // 2
200-
201-
// Add pred (cond_exit) to expr_exit
202-
self.add_contained_edge(cond_exit, expr_exit);
203-
204-
let body_exit = self.block(&body, cond_exit); // 4
205-
self.add_contained_edge(body_exit, loopback); // 5
206-
self.loop_scopes.pop();
207-
expr_exit
208-
}
209-
210168
hir::ExprKind::Loop(ref body, _, _) => {
211169
//
212170
// [pred]

src/librustc/hir/intravisit.rs

-5
Original file line numberDiff line numberDiff line change
@@ -1026,11 +1026,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
10261026
ExprKind::DropTemps(ref subexpression) => {
10271027
visitor.visit_expr(subexpression);
10281028
}
1029-
ExprKind::While(ref subexpression, ref block, ref opt_label) => {
1030-
walk_list!(visitor, visit_label, opt_label);
1031-
visitor.visit_expr(subexpression);
1032-
visitor.visit_block(block);
1033-
}
10341029
ExprKind::Loop(ref block, ref opt_label, _) => {
10351030
walk_list!(visitor, visit_label, opt_label);
10361031
visitor.visit_block(block);

src/librustc/hir/lowering.rs

+72-66
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use syntax::errors;
6363
use syntax::ext::hygiene::{Mark, SyntaxContext};
6464
use syntax::print::pprust;
6565
use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned};
66-
use syntax::source_map::CompilerDesugaringKind::IfTemporary;
66+
use syntax::source_map::CompilerDesugaringKind::CondTemporary;
6767
use syntax::std_inject;
6868
use syntax::symbol::{kw, sym, Symbol};
6969
use syntax::tokenstream::{TokenStream, TokenTree};
@@ -4394,21 +4394,18 @@ impl<'a> LoweringContext<'a> {
43944394
let then_blk = self.lower_block(then, false);
43954395
let then_expr = self.expr_block(then_blk, ThinVec::new());
43964396
let (then_pats, scrutinee, desugar) = match cond.node {
4397-
// `<pat> => <then>`
4397+
// `<pat> => <then>`:
43984398
ExprKind::Let(ref pats, ref scrutinee) => {
43994399
let scrutinee = self.lower_expr(scrutinee);
44004400
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
44014401
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
44024402
(pats, scrutinee, desugar)
44034403
}
4404-
// `true => then`:
4404+
// `true => <then>`:
44054405
_ => {
44064406
// Lower condition:
44074407
let cond = self.lower_expr(cond);
4408-
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4409-
// to preserve drop semantics since `if cond { ... }`
4410-
// don't let temporaries live outside of `cond`.
4411-
let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
4408+
let span_block = self.mark_span_with_reason(CondTemporary, cond.span, None);
44124409
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
44134410
// to preserve drop semantics since `if cond { ... }` does not
44144411
// let temporaries live outside of `cond`.
@@ -4424,69 +4421,78 @@ impl<'a> LoweringContext<'a> {
44244421
hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
44254422
}
44264423
// FIXME(#53667): handle lowering of && and parens.
4427-
ExprKind::While(ref cond, ref body, opt_label) => {
4428-
// Desugar `ExprWhileLet`
4429-
// from: `[opt_ident]: while let <pat> = <sub_expr> <body>`
4430-
if let ExprKind::Let(ref pats, ref sub_expr) = cond.node {
4431-
// to:
4432-
//
4433-
// [opt_ident]: loop {
4434-
// match <sub_expr> {
4435-
// <pat> => <body>,
4436-
// _ => break
4437-
// }
4438-
// }
4439-
4440-
// Note that the block AND the condition are evaluated in the loop scope.
4441-
// This is done to allow `break` from inside the condition of the loop.
4442-
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
4443-
(
4444-
this.lower_block(body, false),
4445-
this.expr_break(e.span, ThinVec::new()),
4446-
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
4447-
)
4448-
});
4424+
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
4425+
// Note that the block AND the condition are evaluated in the loop scope.
4426+
// This is done to allow `break` from inside the condition of the loop.
44494427

4450-
// `<pat> => <body>`
4451-
let pat_arm = {
4452-
let body_expr = P(self.expr_block(body, ThinVec::new()));
4453-
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
4454-
self.arm(pats, body_expr)
4455-
};
4428+
// `_ => break`:
4429+
let else_arm = {
4430+
let else_pat = this.pat_wild(e.span);
4431+
let else_expr = this.expr_break(e.span, ThinVec::new());
4432+
this.arm(hir_vec![else_pat], else_expr)
4433+
};
44564434

4457-
// `_ => break`
4458-
let break_arm = {
4459-
let pat_under = self.pat_wild(e.span);
4460-
self.arm(hir_vec![pat_under], break_expr)
4461-
};
4435+
// Handle then + scrutinee:
4436+
let then_blk = this.lower_block(body, false);
4437+
let then_expr = this.expr_block(then_blk, ThinVec::new());
4438+
let (then_pats, scrutinee, desugar, source) = match cond.node {
4439+
ExprKind::Let(ref pats, ref scrutinee) => {
4440+
// to:
4441+
//
4442+
// [opt_ident]: loop {
4443+
// match <sub_expr> {
4444+
// <pat> => <body>,
4445+
// _ => break
4446+
// }
4447+
// }
4448+
let scrutinee = this.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
4449+
let pats = pats.iter().map(|pat| this.lower_pat(pat)).collect();
4450+
let desugar = hir::MatchSource::WhileLetDesugar;
4451+
(pats, scrutinee, desugar, hir::LoopSource::WhileLet)
4452+
}
4453+
_ => {
4454+
// We desugar: `'label: while $cond $body` into:
4455+
//
4456+
// ```
4457+
// 'label: loop {
4458+
// match DropTemps($cond) {
4459+
// true => $body,
4460+
// _ => break,
4461+
// }
4462+
// }
4463+
// ```
44624464

4463-
// `match <sub_expr> { ... }`
4464-
let arms = hir_vec![pat_arm, break_arm];
4465-
let match_expr = self.expr(
4466-
sub_expr.span,
4467-
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
4468-
ThinVec::new(),
4469-
);
4465+
// Lower condition:
4466+
let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond));
4467+
let span_block = this.mark_span_with_reason(CondTemporary, cond.span, None);
4468+
// Wrap in a construct equivalent to `{ let _t = $cond; _t }`
4469+
// to preserve drop semantics since `while cond { ... }` does not
4470+
// let temporaries live outside of `cond`.
4471+
let cond = this.expr_drop_temps(span_block, P(cond), ThinVec::new());
44704472

4471-
// `[opt_ident]: loop { ... }`
4472-
let loop_block = P(self.block_expr(P(match_expr)));
4473-
let loop_expr = hir::ExprKind::Loop(
4474-
loop_block,
4475-
self.lower_label(opt_label),
4476-
hir::LoopSource::WhileLet,
4477-
);
4478-
// Add attributes to the outer returned expr node.
4479-
loop_expr
4480-
} else {
4481-
self.with_loop_scope(e.id, |this| {
4482-
hir::ExprKind::While(
4483-
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
4484-
this.lower_block(body, false),
4485-
this.lower_label(opt_label),
4486-
)
4487-
})
4488-
}
4489-
}
4473+
let desugar = hir::MatchSource::WhileDesugar;
4474+
// `true => <then>`:
4475+
let pats = hir_vec![this.pat_bool(e.span, true)];
4476+
(pats, cond, desugar, hir::LoopSource::While)
4477+
}
4478+
};
4479+
let then_arm = this.arm(then_pats, P(then_expr));
4480+
4481+
// `match <scrutinee> { ... }`
4482+
let match_expr = this.expr_match(
4483+
scrutinee.span,
4484+
P(scrutinee),
4485+
hir_vec![then_arm, else_arm],
4486+
desugar,
4487+
);
4488+
4489+
// `[opt_ident]: loop { ... }`
4490+
hir::ExprKind::Loop(
4491+
P(this.block_expr(P(match_expr))),
4492+
this.lower_label(opt_label),
4493+
source
4494+
)
4495+
}),
44904496
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
44914497
hir::ExprKind::Loop(
44924498
this.lower_block(body, false),

src/librustc/hir/map/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ impl<'hir> Map<'hir> {
731731
match *node {
732732
Node::Expr(ref expr) => {
733733
match expr.node {
734-
ExprKind::While(..) | ExprKind::Loop(..) | ExprKind::Ret(..) => true,
734+
ExprKind::Loop(..) | ExprKind::Ret(..) => true,
735735
_ => false,
736736
}
737737
}

src/librustc/hir/mod.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,6 @@ impl Expr {
14051405
ExprKind::Lit(_) => ExprPrecedence::Lit,
14061406
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
14071407
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
1408-
ExprKind::While(..) => ExprPrecedence::While,
14091408
ExprKind::Loop(..) => ExprPrecedence::Loop,
14101409
ExprKind::Match(..) => ExprPrecedence::Match,
14111410
ExprKind::Closure(..) => ExprPrecedence::Closure,
@@ -1464,7 +1463,6 @@ impl Expr {
14641463
ExprKind::Break(..) |
14651464
ExprKind::Continue(..) |
14661465
ExprKind::Ret(..) |
1467-
ExprKind::While(..) |
14681466
ExprKind::Loop(..) |
14691467
ExprKind::Assign(..) |
14701468
ExprKind::InlineAsm(..) |
@@ -1532,10 +1530,6 @@ pub enum ExprKind {
15321530
/// This construct only exists to tweak the drop order in HIR lowering.
15331531
/// An example of that is the desugaring of `for` loops.
15341532
DropTemps(P<Expr>),
1535-
/// A while loop, with an optional label
1536-
///
1537-
/// I.e., `'label: while expr { <block> }`.
1538-
While(P<Expr>, P<Block>, Option<Label>),
15391533
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
15401534
///
15411535
/// I.e., `'label: loop { <block> }`.
@@ -1653,6 +1647,8 @@ pub enum MatchSource {
16531647
IfLetDesugar {
16541648
contains_else_clause: bool,
16551649
},
1650+
/// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
1651+
WhileDesugar,
16561652
/// A `while let _ = _ { .. }` (which was desugared to a
16571653
/// `loop { match _ { .. } }`).
16581654
WhileLetDesugar,
@@ -1669,12 +1665,25 @@ pub enum MatchSource {
16691665
pub enum LoopSource {
16701666
/// A `loop { .. }` loop.
16711667
Loop,
1668+
/// A `while _ { .. }` loop.
1669+
While,
16721670
/// A `while let _ = _ { .. }` loop.
16731671
WhileLet,
16741672
/// A `for _ in _ { .. }` loop.
16751673
ForLoop,
16761674
}
16771675

1676+
impl LoopSource {
1677+
pub fn name(self) -> &'static str {
1678+
match self {
1679+
LoopSource::Loop => "loop",
1680+
LoopSource::While => "while",
1681+
LoopSource::WhileLet => "while let",
1682+
LoopSource::ForLoop => "for",
1683+
}
1684+
}
1685+
}
1686+
16781687
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
16791688
pub enum LoopIdError {
16801689
OutsideLoopScope,

src/librustc/hir/print.rs

-11
Original file line numberDiff line numberDiff line change
@@ -1299,16 +1299,6 @@ impl<'a> State<'a> {
12991299
// Print `}`:
13001300
self.bclose_maybe_open(expr.span, indent_unit, true);
13011301
}
1302-
hir::ExprKind::While(ref test, ref blk, opt_label) => {
1303-
if let Some(label) = opt_label {
1304-
self.print_ident(label.ident);
1305-
self.word_space(":");
1306-
}
1307-
self.head("while");
1308-
self.print_expr_as_cond(&test);
1309-
self.s.space();
1310-
self.print_block(&blk);
1311-
}
13121302
hir::ExprKind::Loop(ref blk, opt_label, _) => {
13131303
if let Some(label) = opt_label {
13141304
self.print_ident(label.ident);
@@ -2289,7 +2279,6 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
22892279
match e.node {
22902280
hir::ExprKind::Match(..) |
22912281
hir::ExprKind::Block(..) |
2292-
hir::ExprKind::While(..) |
22932282
hir::ExprKind::Loop(..) => false,
22942283
_ => true,
22952284
}

src/librustc/ich/impls_syntax.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
415415
});
416416

417417
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
418-
IfTemporary,
418+
CondTemporary,
419419
Async,
420420
Await,
421421
QuestionMark,

src/librustc/middle/expr_use_visitor.rs

-5
Original file line numberDiff line numberDiff line change
@@ -487,11 +487,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
487487
self.walk_block(&blk);
488488
}
489489

490-
hir::ExprKind::While(ref cond_expr, ref blk, _) => {
491-
self.consume_expr(&cond_expr);
492-
self.walk_block(&blk);
493-
}
494-
495490
hir::ExprKind::Unary(_, ref lhs) => {
496491
self.consume_expr(&lhs);
497492
}

0 commit comments

Comments
 (0)