ra_ap_ide_diagnostics/handlers/
undeclared_label.rs

1use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
2
3// Diagnostic: undeclared-label
4pub(crate) fn undeclared_label(
5    ctx: &DiagnosticsContext<'_>,
6    d: &hir::UndeclaredLabel,
7) -> Diagnostic {
8    let name = &d.name;
9    Diagnostic::new_with_syntax_node_ptr(
10        ctx,
11        DiagnosticCode::RustcHardError("undeclared-label"),
12        format!("use of undeclared label `{}`", name.display(ctx.sema.db, ctx.edition)),
13        d.node.map(|it| it.into()),
14    )
15    .stable()
16}
17
18#[cfg(test)]
19mod tests {
20    use crate::tests::check_diagnostics;
21
22    #[test]
23    fn smoke_test() {
24        check_diagnostics(
25            r#"
26fn foo() {
27    break 'a;
28  //^^^^^^^^ error: break outside of loop
29        //^^ error: use of undeclared label `'a`
30    continue 'a;
31  //^^^^^^^^^^^ error: continue outside of loop
32           //^^ error: use of undeclared label `'a`
33}
34"#,
35        );
36    }
37
38    #[test]
39    fn while_let_loop_with_label_in_condition() {
40        check_diagnostics(
41            r#"
42//- minicore: option
43
44fn foo() {
45    let mut optional = Some(0);
46
47    'my_label: while let Some(_) = match optional {
48        None => break 'my_label,
49        Some(val) => Some(val),
50    } {
51        optional = None;
52        continue 'my_label;
53    }
54}
55"#,
56        );
57    }
58
59    #[test]
60    fn for_loop() {
61        check_diagnostics(
62            r#"
63//- minicore: iterator
64fn foo() {
65    'xxx: for _ in [] {
66        'yyy: for _ in [] {
67            break 'xxx;
68            continue 'yyy;
69            break 'zzz;
70                //^^^^ error: use of undeclared label `'zzz`
71        }
72        continue 'xxx;
73        continue 'yyy;
74               //^^^^ error: use of undeclared label `'yyy`
75        break 'xxx;
76        break 'yyy;
77            //^^^^ error: use of undeclared label `'yyy`
78    }
79}
80"#,
81        );
82    }
83
84    #[test]
85    fn try_operator_desugar_works() {
86        check_diagnostics(
87            r#"
88//- minicore: option, try
89fn foo() {
90    None?;
91}
92"#,
93        );
94        check_diagnostics(
95            r#"
96//- minicore: option, try, future
97async fn foo() {
98    None?;
99}
100"#,
101        );
102        check_diagnostics(
103            r#"
104//- minicore: option, try, future, fn
105async fn foo() {
106    || None?;
107}
108"#,
109        );
110    }
111
112    #[test]
113    fn macro_expansion_can_refer_label_defined_before_macro_definition() {
114        check_diagnostics(
115            r#"
116fn foo() {
117    'bar: loop {
118        macro_rules! m {
119            () => { break 'bar };
120        }
121        m!();
122    }
123}
124"#,
125        );
126        check_diagnostics(
127            r#"
128fn foo() {
129    'bar: loop {
130        macro_rules! m {
131            () => { break 'bar };
132        }
133        'bar: loop {
134            m!();
135        }
136    }
137}
138"#,
139        );
140    }
141}