aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs28
-rw-r--r--crates/ra_hir_ty/src/infer.rs13
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs4
-rw-r--r--crates/ra_hir_ty/src/tests.rs18
4 files changed, 62 insertions, 1 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index c8fd54861..41ac70272 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -131,3 +131,31 @@ impl AstDiagnostic for MissingOkInTailExpr {
131 ast::Expr::cast(node).unwrap() 131 ast::Expr::cast(node).unwrap()
132 } 132 }
133} 133}
134
135#[derive(Debug)]
136pub struct BreakOutsideOfLoop {
137 pub file: HirFileId,
138 pub expr: AstPtr<ast::Expr>,
139}
140
141impl 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
153impl 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}
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 413904518..a21ad8d86 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -717,11 +717,15 @@ mod diagnostics {
717 use hir_def::{expr::ExprId, FunctionId}; 717 use hir_def::{expr::ExprId, FunctionId};
718 use hir_expand::diagnostics::DiagnosticSink; 718 use hir_expand::diagnostics::DiagnosticSink;
719 719
720 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 720 use crate::{
721 db::HirDatabase,
722 diagnostics::{BreakOutsideOfLoop, NoSuchField},
723 };
721 724
722 #[derive(Debug, PartialEq, Eq, Clone)] 725 #[derive(Debug, PartialEq, Eq, Clone)]
723 pub(super) enum InferenceDiagnostic { 726 pub(super) enum InferenceDiagnostic {
724 NoSuchField { expr: ExprId, field: usize }, 727 NoSuchField { expr: ExprId, field: usize },
728 BreakOutsideOfLoop { expr: ExprId },
725 } 729 }
726 730
727 impl InferenceDiagnostic { 731 impl InferenceDiagnostic {
@@ -737,6 +741,13 @@ mod diagnostics {
737 let field = source_map.field_syntax(*expr, *field); 741 let field = source_map.field_syntax(*expr, *field);
738 sink.push(NoSuchField { file: field.file_id, field: field.value }) 742 sink.push(NoSuchField { file: field.file_id, field: field.value })
739 } 743 }
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 }
740 } 751 }
741 } 752 }
742 } 753 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 9cac0c787..0b67d216a 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -235,6 +235,10 @@ impl<'a> InferenceContext<'a> {
235 } 235 }
236 if let Some(ctxt) = self.breakables.last_mut() { 236 if let Some(ctxt) = self.breakables.last_mut() {
237 ctxt.may_break = true; 237 ctxt.may_break = true;
238 } else {
239 self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
240 expr: tgt_expr,
241 });
238 } 242 }
239 Ty::simple(TypeCtor::Never) 243 Ty::simple(TypeCtor::Never)
240 } 244 }
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index d60732e19..5af88b368 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -518,3 +518,21 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
518 518
519 assert_snapshot!(diagnostics, @""); 519 assert_snapshot!(diagnostics, @"");
520} 520}
521
522#[test]
523fn 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}