Auto merge of #15373 - tadeokondrak:desugar-while-to-loop, r=HKalbasi
internal: Desugar while to loop and break I was reading through rust-analyzer's code and was wondering why this wasn't desugared into a loop.
This commit is contained in:
commit
e37ec7262c
@ -314,11 +314,18 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
|
||||
self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
|
||||
}
|
||||
ast::Expr::WhileExpr(e) => {
|
||||
// Desugar `while <cond> { <body> }` to
|
||||
// `loop { if <cond> { <body> } else { break } }`
|
||||
let label = e.label().map(|label| self.collect_label(label));
|
||||
let body = self.collect_labelled_block_opt(label, e.loop_body());
|
||||
let condition = self.collect_expr_opt(e.condition());
|
||||
|
||||
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
|
||||
let break_expr =
|
||||
self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone());
|
||||
let if_expr = self.alloc_expr(
|
||||
Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },
|
||||
syntax_ptr.clone(),
|
||||
);
|
||||
self.alloc_expr(Expr::Loop { body: if_expr, label }, syntax_ptr)
|
||||
}
|
||||
ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
|
||||
ast::Expr::CallExpr(e) => {
|
||||
|
@ -178,14 +178,6 @@ fn print_expr(&mut self, expr: ExprId) {
|
||||
w!(self, "loop ");
|
||||
self.print_expr(*body);
|
||||
}
|
||||
Expr::While { condition, body, label } => {
|
||||
if let Some(lbl) = label {
|
||||
w!(self, "{}: ", self.body[*lbl].name.display(self.db));
|
||||
}
|
||||
w!(self, "while ");
|
||||
self.print_expr(*condition);
|
||||
self.print_expr(*body);
|
||||
}
|
||||
Expr::Call { callee, args, is_assignee_expr: _ } => {
|
||||
self.print_expr(*callee);
|
||||
w!(self, "(");
|
||||
|
@ -228,11 +228,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
|
||||
scopes.set_scope(expr, scope);
|
||||
compute_block_scopes(statements, *tail, body, scopes, &mut scope);
|
||||
}
|
||||
Expr::While { condition, body: body_expr, label } => {
|
||||
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||
compute_expr_scopes(*condition, body, scopes, &mut scope);
|
||||
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||
}
|
||||
Expr::Loop { body: body_expr, label } => {
|
||||
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||
|
@ -191,11 +191,6 @@ pub enum Expr {
|
||||
body: ExprId,
|
||||
label: Option<LabelId>,
|
||||
},
|
||||
While {
|
||||
condition: ExprId,
|
||||
body: ExprId,
|
||||
label: Option<LabelId>,
|
||||
},
|
||||
Call {
|
||||
callee: ExprId,
|
||||
args: Box<[ExprId]>,
|
||||
@ -379,10 +374,6 @@ pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
|
||||
}
|
||||
}
|
||||
Expr::Loop { body, .. } => f(*body),
|
||||
Expr::While { condition, body, .. } => {
|
||||
f(*condition);
|
||||
f(*body);
|
||||
}
|
||||
Expr::Call { callee, args, .. } => {
|
||||
f(*callee);
|
||||
args.iter().copied().for_each(f);
|
||||
|
@ -488,10 +488,6 @@ fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
|
||||
self.consume_expr(*tail);
|
||||
}
|
||||
}
|
||||
Expr::While { condition, body, label: _ } => {
|
||||
self.consume_expr(*condition);
|
||||
self.consume_expr(*body);
|
||||
}
|
||||
Expr::Call { callee, args, is_assignee_expr: _ } => {
|
||||
self.consume_expr(*callee);
|
||||
self.consume_exprs(args.iter().copied());
|
||||
|
@ -198,19 +198,6 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
None => self.result.standard_types.never.clone(),
|
||||
}
|
||||
}
|
||||
&Expr::While { condition, body, label } => {
|
||||
self.with_breakable_ctx(BreakableKind::Loop, None, label, |this| {
|
||||
this.infer_expr(
|
||||
condition,
|
||||
&Expectation::HasType(this.result.standard_types.bool_.clone()),
|
||||
);
|
||||
this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
|
||||
});
|
||||
|
||||
// the body may not run, so it diverging doesn't mean we diverge
|
||||
self.diverges = Diverges::Maybe;
|
||||
TyBuilder::unit()
|
||||
}
|
||||
Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => {
|
||||
assert_eq!(args.len(), arg_types.len());
|
||||
|
||||
|
@ -69,10 +69,6 @@ fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutabi
|
||||
self.infer_mut_expr(*tail, Mutability::Not);
|
||||
}
|
||||
}
|
||||
&Expr::While { condition: c, body, label: _ } => {
|
||||
self.infer_mut_expr(c, Mutability::Not);
|
||||
self.infer_mut_expr(body, Mutability::Not);
|
||||
}
|
||||
Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ }
|
||||
| Expr::Call { callee: it, args, is_assignee_expr: _ } => {
|
||||
self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it)));
|
||||
|
@ -582,36 +582,6 @@ fn lower_expr_to_place_without_adjust(
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
Expr::While { condition, body, label } => {
|
||||
self.lower_loop(current, place, *label, expr_id.into(), |this, begin| {
|
||||
let scope = this.push_drop_scope();
|
||||
let Some((discr, to_switch)) =
|
||||
this.lower_expr_to_some_operand(*condition, begin)?
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
let fail_cond = this.new_basic_block();
|
||||
let after_cond = this.new_basic_block();
|
||||
this.set_terminator(
|
||||
to_switch,
|
||||
TerminatorKind::SwitchInt {
|
||||
discr,
|
||||
targets: SwitchTargets::static_if(1, after_cond, fail_cond),
|
||||
},
|
||||
expr_id.into(),
|
||||
);
|
||||
let fail_cond = this.drop_until_scope(this.drop_scopes.len() - 1, fail_cond);
|
||||
let end = this.current_loop_end()?;
|
||||
this.set_goto(fail_cond, end, expr_id.into());
|
||||
if let Some((_, block)) = this.lower_expr_as_place(after_cond, *body, true)? {
|
||||
let block = scope.pop_and_drop(this, block);
|
||||
this.set_goto(block, begin, expr_id.into());
|
||||
} else {
|
||||
scope.pop_assume_dropped(this);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
Expr::Call { callee, args, .. } => {
|
||||
if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {
|
||||
let ty = chalk_ir::TyKind::FnDef(
|
||||
|
@ -209,6 +209,8 @@ fn spam() {
|
||||
104..105 '_': IntoIterator::Item<isize>
|
||||
117..119 '{}': ()
|
||||
124..134 '|| spam!()': impl Fn() -> isize
|
||||
140..156 'while ...!() {}': !
|
||||
140..156 'while ...!() {}': ()
|
||||
140..156 'while ...!() {}': ()
|
||||
154..156 '{}': ()
|
||||
161..174 'break spam!()': !
|
||||
@ -300,6 +302,8 @@ fn spam() {
|
||||
118..119 '_': IntoIterator::Item<isize>
|
||||
131..133 '{}': ()
|
||||
138..148 '|| spam!()': impl Fn() -> isize
|
||||
154..170 'while ...!() {}': !
|
||||
154..170 'while ...!() {}': ()
|
||||
154..170 'while ...!() {}': ()
|
||||
168..170 '{}': ()
|
||||
175..188 'break spam!()': !
|
||||
|
@ -412,17 +412,23 @@ fn test3() {
|
||||
355..654 '{ ...; }; }': ()
|
||||
398..399 'x': u32
|
||||
407..433 '{ whil...; }; }': u32
|
||||
409..430 'while ...eak; }': !
|
||||
409..430 'while ...eak; }': ()
|
||||
409..430 'while ...eak; }': ()
|
||||
415..419 'true': bool
|
||||
420..430 '{ break; }': ()
|
||||
422..427 'break': !
|
||||
537..538 'x': u32
|
||||
546..564 '{ whil... {}; }': u32
|
||||
548..561 'while true {}': !
|
||||
548..561 'while true {}': ()
|
||||
548..561 'while true {}': ()
|
||||
554..558 'true': bool
|
||||
559..561 '{}': ()
|
||||
615..616 'x': u32
|
||||
624..651 '{ whil...; }; }': u32
|
||||
626..648 'while ...urn; }': !
|
||||
626..648 'while ...urn; }': ()
|
||||
626..648 'while ...urn; }': ()
|
||||
632..636 'true': bool
|
||||
637..648 '{ return; }': ()
|
||||
|
@ -1267,6 +1267,8 @@ fn test() {
|
||||
"#,
|
||||
expect![[r#"
|
||||
10..59 '{ ... } }': ()
|
||||
16..57 'while ... }': !
|
||||
16..57 'while ... }': ()
|
||||
16..57 'while ... }': ()
|
||||
22..30 '{ true }': bool
|
||||
24..28 'true': bool
|
||||
|
Loading…
Reference in New Issue
Block a user