Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15517 - xffxff:label_in_condition, r=lnicola
fix: diagnostics for 'while let' loop with label in condition fix #15516
bors 2023-08-27
parent 0a0bb77 · parent 204bc2c · commit 029baaa
-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 7071fcb939..6a2ac15465 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 7de9a9a323..495ea74877 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#"