about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-26 17:02:57 +0000
committerbors <bors@rust-lang.org>2023-08-26 17:02:57 +0000
commit029baaad2269b03ea73fe1a651dbcf2e173de087 (patch)
treea64745e7cfe161d6d03bd61e7c30741e9ce16f0a
parent0a0bb777b19234d6169496c2c383f5dca202f858 (diff)
parent204bc2cb60c83814e1fbd85fbbc64ecfe846a5e8 (diff)
downloadrust-029baaad2269b03ea73fe1a651dbcf2e173de087.tar.gz
rust-029baaad2269b03ea73fe1a651dbcf2e173de087.zip
Auto merge of #15517 - xffxff:label_in_condition, r=lnicola
fix: diagnostics for 'while let' loop with label in condition

fix #15516
-rw-r--r--crates/hir-def/src/body/lower.rs22
-rw-r--r--crates/ide-diagnostics/src/handlers/undeclared_label.rs19
2 files changed, 40 insertions, 1 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 7071fcb9394..6a2ac15465f 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -744,7 +744,27 @@ impl ExprCollector<'_> {
     fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
         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());
+
+        // Labels can also be used in the condition expression, like this:
+        // ```
+        // fn main() {
+        //     let mut optional = Some(0);
+        //     'my_label: while let Some(a) = match optional {
+        //         None => break 'my_label,
+        //         Some(val) => Some(val),
+        //     } {
+        //         println!("{}", a);
+        //         optional = None;
+        //     }
+        // }
+        // ```
+        let condition = match label {
+            Some(label) => {
+                self.with_labeled_rib(label, |this| this.collect_expr_opt(e.condition()))
+            }
+            None => self.collect_expr_opt(e.condition()),
+        };
+
         let break_expr =
             self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone());
         let if_expr = self.alloc_expr(
diff --git a/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index 7de9a9a323e..495ea748776 100644
--- a/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -35,6 +35,25 @@ fn foo() {
     }
 
     #[test]
+    fn while_let_loop_with_label_in_condition() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    let mut optional = Some(0);
+
+    'my_label: while let Some(a) = match optional {
+        None => break 'my_label,
+        Some(val) => Some(val),
+    } {
+        optional = None;
+        continue 'my_label;
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn for_loop() {
         check_diagnostics(
             r#"