Add diagnostic for break outside of loop

This commit is contained in:
Florian Diebold 2020-05-08 19:48:03 +02:00
parent f8bf94a4b9
commit d0129c4ddb
4 changed files with 62 additions and 1 deletions

View file

@ -131,3 +131,31 @@ impl AstDiagnostic for MissingOkInTailExpr {
ast::Expr::cast(node).unwrap() ast::Expr::cast(node).unwrap()
} }
} }
#[derive(Debug)]
pub struct BreakOutsideOfLoop {
pub file: HirFileId,
pub expr: AstPtr<ast::Expr>,
}
impl Diagnostic for BreakOutsideOfLoop {
fn message(&self) -> String {
"break outside of loop".to_string()
}
fn source(&self) -> InFile<SyntaxNodePtr> {
InFile { file_id: self.file, value: self.expr.clone().into() }
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}
impl AstDiagnostic for BreakOutsideOfLoop {
type AST = ast::Expr;
fn ast(&self, db: &impl AstDatabase) -> Self::AST {
let root = db.parse_or_expand(self.file).unwrap();
let node = self.source().value.to_node(&root);
ast::Expr::cast(node).unwrap()
}
}

View file

@ -717,11 +717,15 @@ mod diagnostics {
use hir_def::{expr::ExprId, FunctionId}; use hir_def::{expr::ExprId, FunctionId};
use hir_expand::diagnostics::DiagnosticSink; use hir_expand::diagnostics::DiagnosticSink;
use crate::{db::HirDatabase, diagnostics::NoSuchField}; use crate::{
db::HirDatabase,
diagnostics::{BreakOutsideOfLoop, NoSuchField},
};
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub(super) enum InferenceDiagnostic { pub(super) enum InferenceDiagnostic {
NoSuchField { expr: ExprId, field: usize }, NoSuchField { expr: ExprId, field: usize },
BreakOutsideOfLoop { expr: ExprId },
} }
impl InferenceDiagnostic { impl InferenceDiagnostic {
@ -737,6 +741,13 @@ mod diagnostics {
let field = source_map.field_syntax(*expr, *field); let field = source_map.field_syntax(*expr, *field);
sink.push(NoSuchField { file: field.file_id, field: field.value }) sink.push(NoSuchField { file: field.file_id, field: field.value })
} }
InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
let (_, source_map) = db.body_with_source_map(owner.into());
let ptr = source_map
.expr_syntax(*expr)
.expect("break outside of loop in synthetic syntax");
sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
}
} }
} }
} }

View file

@ -235,6 +235,10 @@ impl<'a> InferenceContext<'a> {
} }
if let Some(ctxt) = self.breakables.last_mut() { if let Some(ctxt) = self.breakables.last_mut() {
ctxt.may_break = true; ctxt.may_break = true;
} else {
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
expr: tgt_expr,
});
} }
Ty::simple(TypeCtor::Never) Ty::simple(TypeCtor::Never)
} }

View file

@ -518,3 +518,21 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
assert_snapshot!(diagnostics, @""); assert_snapshot!(diagnostics, @"");
} }
#[test]
fn break_outside_of_loop() {
let diagnostics = TestDB::with_files(
r"
//- /lib.rs
fn foo() {
break;
}
",
)
.diagnostics()
.0;
assert_snapshot!(diagnostics, @r###""break": break outside of loop
"###
);
}