Skip to content

Commit d0129c4

Browse files
committed
Add diagnostic for break outside of loop
1 parent f8bf94a commit d0129c4

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

crates/ra_hir_ty/src/diagnostics.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,31 @@ impl AstDiagnostic for MissingOkInTailExpr {
131131
ast::Expr::cast(node).unwrap()
132132
}
133133
}
134+
135+
#[derive(Debug)]
136+
pub struct BreakOutsideOfLoop {
137+
pub file: HirFileId,
138+
pub expr: AstPtr<ast::Expr>,
139+
}
140+
141+
impl Diagnostic for BreakOutsideOfLoop {
142+
fn message(&self) -> String {
143+
"break outside of loop".to_string()
144+
}
145+
fn source(&self) -> InFile<SyntaxNodePtr> {
146+
InFile { file_id: self.file, value: self.expr.clone().into() }
147+
}
148+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
149+
self
150+
}
151+
}
152+
153+
impl AstDiagnostic for BreakOutsideOfLoop {
154+
type AST = ast::Expr;
155+
156+
fn ast(&self, db: &impl AstDatabase) -> Self::AST {
157+
let root = db.parse_or_expand(self.file).unwrap();
158+
let node = self.source().value.to_node(&root);
159+
ast::Expr::cast(node).unwrap()
160+
}
161+
}

crates/ra_hir_ty/src/infer.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,11 +717,15 @@ mod diagnostics {
717717
use hir_def::{expr::ExprId, FunctionId};
718718
use hir_expand::diagnostics::DiagnosticSink;
719719

720-
use crate::{db::HirDatabase, diagnostics::NoSuchField};
720+
use crate::{
721+
db::HirDatabase,
722+
diagnostics::{BreakOutsideOfLoop, NoSuchField},
723+
};
721724

722725
#[derive(Debug, PartialEq, Eq, Clone)]
723726
pub(super) enum InferenceDiagnostic {
724727
NoSuchField { expr: ExprId, field: usize },
728+
BreakOutsideOfLoop { expr: ExprId },
725729
}
726730

727731
impl InferenceDiagnostic {
@@ -737,6 +741,13 @@ mod diagnostics {
737741
let field = source_map.field_syntax(*expr, *field);
738742
sink.push(NoSuchField { file: field.file_id, field: field.value })
739743
}
744+
InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
745+
let (_, source_map) = db.body_with_source_map(owner.into());
746+
let ptr = source_map
747+
.expr_syntax(*expr)
748+
.expect("break outside of loop in synthetic syntax");
749+
sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
750+
}
740751
}
741752
}
742753
}

crates/ra_hir_ty/src/infer/expr.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ impl<'a> InferenceContext<'a> {
235235
}
236236
if let Some(ctxt) = self.breakables.last_mut() {
237237
ctxt.may_break = true;
238+
} else {
239+
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
240+
expr: tgt_expr,
241+
});
238242
}
239243
Ty::simple(TypeCtor::Never)
240244
}

crates/ra_hir_ty/src/tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,21 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
518518

519519
assert_snapshot!(diagnostics, @"");
520520
}
521+
522+
#[test]
523+
fn break_outside_of_loop() {
524+
let diagnostics = TestDB::with_files(
525+
r"
526+
//- /lib.rs
527+
fn foo() {
528+
break;
529+
}
530+
",
531+
)
532+
.diagnostics()
533+
.0;
534+
535+
assert_snapshot!(diagnostics, @r###""break": break outside of loop
536+
"###
537+
);
538+
}

0 commit comments

Comments
 (0)