about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-04 07:26:18 +0000
committerbors <bors@rust-lang.org>2023-08-04 07:26:18 +0000
commite37ec7262c095e38069671a175e5b2bf4fbbbff2 (patch)
treead5cb35932a03e36b7326024e4405c102592de62
parentd398ad3326780598bbf1480014f4c59fbf6461a7 (diff)
parent92a97c292a95688d4d8973193e59b6443560f363 (diff)
downloadrust-e37ec7262c095e38069671a175e5b2bf4fbbbff2.tar.gz
rust-e37ec7262c095e38069671a175e5b2bf4fbbbff2.zip
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.
-rw-r--r--crates/hir-def/src/body/lower.rs11
-rw-r--r--crates/hir-def/src/body/pretty.rs8
-rw-r--r--crates/hir-def/src/body/scope.rs5
-rw-r--r--crates/hir-def/src/hir.rs9
-rw-r--r--crates/hir-ty/src/infer/closure.rs4
-rw-r--r--crates/hir-ty/src/infer/expr.rs13
-rw-r--r--crates/hir-ty/src/infer/mutability.rs4
-rw-r--r--crates/hir-ty/src/mir/lower.rs30
-rw-r--r--crates/hir-ty/src/tests/macros.rs4
-rw-r--r--crates/hir-ty/src/tests/never_type.rs6
-rw-r--r--crates/hir-ty/src/tests/regression.rs2
11 files changed, 21 insertions, 75 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 152c02743f7..c8d1ca4fa70 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -314,11 +314,18 @@ impl ExprCollector<'_> {
                 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) => {
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index eeaed87164d..5d71abe37cc 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -178,14 +178,6 @@ impl Printer<'_> {
                 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, "(");
diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs
index 69741c445fb..2a90a09f25e 100644
--- a/crates/hir-def/src/body/scope.rs
+++ b/crates/hir-def/src/body/scope.rs
@@ -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);
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index 8a140a1ec18..6591c92ac62 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -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 @@ impl Expr {
                 }
             }
             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);
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 972e5321a47..1781f6c58f1 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -488,10 +488,6 @@ impl InferenceContext<'_> {
                     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());
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 501c0b4bd77..8cbdae62526 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -198,19 +198,6 @@ impl InferenceContext<'_> {
                     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());
 
diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs
index f517bc2c09f..396ca0044ff 100644
--- a/crates/hir-ty/src/infer/mutability.rs
+++ b/crates/hir-ty/src/infer/mutability.rs
@@ -69,10 +69,6 @@ impl InferenceContext<'_> {
                     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)));
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index e5e89094818..718df8331e2 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -582,36 +582,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     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(
diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs
index b71c457f015..1e6e946a13f 100644
--- a/crates/hir-ty/src/tests/macros.rs
+++ b/crates/hir-ty/src/tests/macros.rs
@@ -209,6 +209,8 @@ fn expr_macro_def_expanded_in_various_places() {
             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 expr_macro_rules_expanded_in_various_places() {
             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!()': !
diff --git a/crates/hir-ty/src/tests/never_type.rs b/crates/hir-ty/src/tests/never_type.rs
index 59046c0435a..5d809b82392 100644
--- a/crates/hir-ty/src/tests/never_type.rs
+++ b/crates/hir-ty/src/tests/never_type.rs
@@ -412,17 +412,23 @@ fn diverging_expression_3_break() {
             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; }': ()
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 375014d6c7f..6ea059065e9 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -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