Skip to content

Commit fbb1bd5

Browse files
committed
Re-enable controlflow outside loop diagnostic
1 parent 0e71179 commit fbb1bd5

File tree

8 files changed

+75
-31
lines changed

8 files changed

+75
-31
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,12 @@ pub enum InferenceDiagnostic {
189189
/// Contains the type the field resolves to
190190
field_with_same_name: Option<Ty>,
191191
},
192+
// FIXME: This should be emitted in body lowering
193+
BreakOutsideOfLoop {
194+
expr: ExprId,
195+
is_break: bool,
196+
bad_value_break: bool,
197+
},
192198
MismatchedArgCount {
193199
call_expr: ExprId,
194200
expected: usize,
@@ -490,6 +496,16 @@ fn find_breakable<'c>(
490496
}
491497
}
492498

499+
fn find_continuable<'c>(
500+
ctxs: &'c mut [BreakableContext],
501+
label: Option<LabelId>,
502+
) -> Option<&'c mut BreakableContext> {
503+
match label {
504+
Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
505+
None => find_breakable(ctxs, label),
506+
}
507+
}
508+
493509
impl<'a> InferenceContext<'a> {
494510
fn new(
495511
db: &'a dyn HirDatabase,

crates/hir-ty/src/infer/expr.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ use syntax::ast::RangeOp;
2525
use crate::{
2626
autoderef::{builtin_deref, deref_by_trait, Autoderef},
2727
consteval,
28-
infer::{coerce::CoerceMany, pat::contains_explicit_ref_binding, BreakableKind},
28+
infer::{
29+
coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind,
30+
},
2931
lang_items::lang_items_for_bin_op,
3032
lower::{
3133
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
@@ -457,13 +459,29 @@ impl<'a> InferenceContext<'a> {
457459
self.resolver.reset_to_guard(g);
458460
ty
459461
}
460-
Expr::Continue { .. } => self.result.standard_types.never.clone(),
462+
&Expr::Continue { label } => {
463+
if let None = find_continuable(&mut self.breakables, label) {
464+
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
465+
expr: tgt_expr,
466+
is_break: false,
467+
bad_value_break: false,
468+
});
469+
};
470+
self.result.standard_types.never.clone()
471+
}
461472
&Expr::Break { expr, label } => {
462473
let val_ty = if let Some(expr) = expr {
463474
let opt_coerce_to = match find_breakable(&mut self.breakables, label) {
464475
Some(ctxt) => match &ctxt.coerce {
465476
Some(coerce) => coerce.expected_ty(),
466-
None => self.err_ty(),
477+
None => {
478+
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
479+
expr: tgt_expr,
480+
is_break: true,
481+
bad_value_break: true,
482+
});
483+
self.err_ty()
484+
}
467485
},
468486
None => self.err_ty(),
469487
};
@@ -485,7 +503,13 @@ impl<'a> InferenceContext<'a> {
485503
}
486504
None => ctxt.may_break = true,
487505
},
488-
None => {}
506+
None => {
507+
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
508+
expr: tgt_expr,
509+
is_break: true,
510+
bad_value_break: false,
511+
});
512+
}
489513
}
490514
self.result.standard_types.never.clone()
491515
}

crates/hir/src/diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ macro_rules! diagnostics {
3232
}
3333

3434
diagnostics![
35+
BreakOutsideOfLoop,
3536
ExpectedFunction,
3637
InactiveCode,
3738
IncorrectCase,
@@ -62,6 +63,13 @@ diagnostics![
6263
UnusedMut,
6364
];
6465

66+
#[derive(Debug)]
67+
pub struct BreakOutsideOfLoop {
68+
pub expr: InFile<AstPtr<ast::Expr>>,
69+
pub is_break: bool,
70+
pub bad_value_break: bool,
71+
}
72+
6573
#[derive(Debug)]
6674
pub struct UnresolvedModule {
6775
pub decl: InFile<AstPtr<ast::Module>>,

crates/hir/src/lib.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ use crate::db::{DefDatabase, HirDatabase};
8585
pub use crate::{
8686
attrs::{HasAttrs, Namespace},
8787
diagnostics::{
88-
AnyDiagnostic, ExpectedFunction, InactiveCode, IncoherentImpl, IncorrectCase,
89-
InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
90-
MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
91-
ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel, UnimplementedBuiltinMacro,
92-
UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport,
93-
UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro,
94-
UnusedMut,
88+
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
89+
IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
90+
MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
91+
PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel,
92+
UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
93+
UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
94+
UnresolvedProcMacro, UnusedMut,
9595
},
9696
has_source::HasSource,
9797
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
@@ -1483,6 +1483,14 @@ impl DefWithBody {
14831483
.into(),
14841484
)
14851485
}
1486+
&hir_ty::InferenceDiagnostic::BreakOutsideOfLoop {
1487+
expr,
1488+
is_break,
1489+
bad_value_break,
1490+
} => {
1491+
let expr = expr_syntax(expr);
1492+
acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into())
1493+
}
14861494
}
14871495
}
14881496
for (pat_or_expr, mismatch) in infer.type_mismatches() {

crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,8 @@ mod tests {
3131
fn foo() {
3232
break;
3333
//^^^^^ error: break outside of loop
34-
break 'a;
35-
//^^^^^^^^ error: break outside of loop
3634
continue;
3735
//^^^^^^^^ error: continue outside of loop
38-
continue 'a;
39-
//^^^^^^^^^^^ error: continue outside of loop
4036
}
4137
"#,
4238
);
@@ -51,12 +47,8 @@ fn foo() {
5147
async {
5248
break;
5349
//^^^^^ error: break outside of loop
54-
break 'a;
55-
//^^^^^^^^ error: break outside of loop
5650
continue;
5751
//^^^^^^^^ error: continue outside of loop
58-
continue 'a;
59-
//^^^^^^^^^^^ error: continue outside of loop
6052
};
6153
}
6254
}
@@ -73,12 +65,8 @@ fn foo() {
7365
|| {
7466
break;
7567
//^^^^^ error: break outside of loop
76-
break 'a;
77-
//^^^^^^^^ error: break outside of loop
7868
continue;
7969
//^^^^^^^^ error: continue outside of loop
80-
continue 'a;
81-
//^^^^^^^^^^^ error: continue outside of loop
8270
};
8371
}
8472
}
@@ -94,9 +82,7 @@ fn foo() {
9482
'a: loop {
9583
{
9684
break;
97-
break 'a;
9885
continue;
99-
continue 'a;
10086
}
10187
}
10288
}
@@ -112,9 +98,7 @@ fn foo() {
11298
'a: loop {
11399
try {
114100
break;
115-
break 'a;
116101
continue;
117-
continue 'a;
118102
};
119103
}
120104
}
@@ -130,11 +114,8 @@ fn foo() {
130114
'a: {
131115
break;
132116
//^^^^^ error: break outside of loop
133-
break 'a;
134117
continue;
135118
//^^^^^^^^ error: continue outside of loop
136-
continue 'a;
137-
//^^^^^^^^^^^ error: continue outside of loop
138119
}
139120
}
140121
"#,

crates/ide-diagnostics/src/handlers/undeclared_label.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ mod tests {
2323
r#"
2424
fn foo() {
2525
break 'a;
26+
//^^^^^^^^ error: break outside of loop
2627
//^^ error: use of undeclared label `'a`
2728
continue 'a;
29+
//^^^^^^^^^^^ error: continue outside of loop
2830
//^^ error: use of undeclared label `'a`
2931
}
3032
"#,

crates/ide-diagnostics/src/handlers/unreachable_label.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ fn foo() {
2525
'a: loop {
2626
async {
2727
break 'a;
28+
//^^^^^^^^ error: break outside of loop
2829
// ^^ error: use of unreachable label `'a`
2930
continue 'a;
31+
//^^^^^^^^^^^ error: continue outside of loop
3032
// ^^ error: use of unreachable label `'a`
3133
};
3234
}
@@ -43,8 +45,10 @@ fn foo() {
4345
'a: loop {
4446
|| {
4547
break 'a;
48+
//^^^^^^^^ error: break outside of loop
4649
// ^^ error: use of unreachable label `'a`
4750
continue 'a;
51+
//^^^^^^^^^^^ error: continue outside of loop
4852
// ^^ error: use of unreachable label `'a`
4953
};
5054
}

crates/ide-diagnostics/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
2727

2828
mod handlers {
29+
pub(crate) mod break_outside_of_loop;
2930
pub(crate) mod expected_function;
3031
pub(crate) mod inactive_code;
3132
pub(crate) mod incoherent_impl;
@@ -285,7 +286,7 @@ pub fn diagnostics(
285286
AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
286287
AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
287288
AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d),
288-
289+
AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
289290
};
290291
res.push(d)
291292
}

0 commit comments

Comments
 (0)