ide_diagnostics/handlers/
break_outside_of_loop.rs

1use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
2
3// Diagnostic: break-outside-of-loop
4//
5// This diagnostic is triggered if the `break` keyword is used outside of a loop.
6pub(crate) fn break_outside_of_loop(
7    ctx: &DiagnosticsContext<'_>,
8    d: &hir::BreakOutsideOfLoop,
9) -> Diagnostic {
10    let message = if d.bad_value_break {
11        "can't break with a value in this position".to_owned()
12    } else {
13        let construct = if d.is_break { "break" } else { "continue" };
14        format!("{construct} outside of loop")
15    };
16    Diagnostic::new_with_syntax_node_ptr(
17        ctx,
18        DiagnosticCode::RustcHardError("E0268"),
19        message,
20        d.expr.map(|it| it.into()),
21    )
22    .stable()
23}
24
25#[cfg(test)]
26mod tests {
27    use crate::tests::check_diagnostics;
28
29    #[test]
30    fn outside_of_loop() {
31        check_diagnostics(
32            r#"
33fn foo() {
34    break;
35  //^^^^^ error: break outside of loop
36    continue;
37  //^^^^^^^^ error: continue outside of loop
38}
39"#,
40        );
41    }
42
43    #[test]
44    fn async_blocks_are_borders() {
45        check_diagnostics(
46            r#"
47fn foo() {
48    'a: loop {
49        async {
50                break;
51              //^^^^^ error: break outside of loop
52                continue;
53              //^^^^^^^^ error: continue outside of loop
54        };
55    }
56}
57"#,
58        );
59    }
60
61    #[test]
62    fn closures_are_borders() {
63        check_diagnostics(
64            r#"
65fn foo() {
66    'a: loop {
67        || {
68                break;
69              //^^^^^ error: break outside of loop
70                continue;
71              //^^^^^^^^ error: continue outside of loop
72        };
73    }
74}
75"#,
76        );
77    }
78
79    #[test]
80    fn blocks_pass_through() {
81        check_diagnostics(
82            r#"
83fn foo() {
84    'a: loop {
85        {
86            break;
87            continue;
88        }
89    }
90}
91"#,
92        );
93    }
94
95    #[test]
96    fn try_blocks_pass_through() {
97        check_diagnostics(
98            r#"
99fn foo() {
100    'a: loop {
101        try {
102                break;
103                continue;
104        };
105    }
106}
107"#,
108        );
109    }
110
111    #[test]
112    fn label_blocks() {
113        check_diagnostics(
114            r#"
115fn foo() {
116    'a: {
117        break;
118      //^^^^^ error: break outside of loop
119        continue;
120      //^^^^^^^^ error: continue outside of loop
121    }
122}
123"#,
124        );
125    }
126
127    #[test]
128    fn value_break_in_for_loop() {
129        // FIXME: the error is correct, but the message is terrible
130        check_diagnostics(
131            r#"
132//- minicore: iterator
133fn test() {
134    for _ in [()] {
135        break 3;
136           // ^ error: expected (), found i32
137    }
138}
139"#,
140        );
141    }
142
143    #[test]
144    fn try_block_desugaring_inside_closure() {
145        // regression test for #14701
146        check_diagnostics(
147            r#"
148//- minicore: option, try
149fn test() {
150    try {
151        || {
152            let x = Some(2);
153            Some(x?)
154        };
155    };
156}
157"#,
158        );
159    }
160}