mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 13:33:31 +00:00
Re-enable controlflow outside loop diagnostic
This commit is contained in:
parent
0e7117900c
commit
fbb1bd5880
8 changed files with 75 additions and 31 deletions
|
@ -189,6 +189,12 @@ pub enum InferenceDiagnostic {
|
||||||
/// Contains the type the field resolves to
|
/// Contains the type the field resolves to
|
||||||
field_with_same_name: Option<Ty>,
|
field_with_same_name: Option<Ty>,
|
||||||
},
|
},
|
||||||
|
// FIXME: This should be emitted in body lowering
|
||||||
|
BreakOutsideOfLoop {
|
||||||
|
expr: ExprId,
|
||||||
|
is_break: bool,
|
||||||
|
bad_value_break: bool,
|
||||||
|
},
|
||||||
MismatchedArgCount {
|
MismatchedArgCount {
|
||||||
call_expr: ExprId,
|
call_expr: ExprId,
|
||||||
expected: usize,
|
expected: usize,
|
||||||
|
@ -490,6 +496,16 @@ fn find_breakable<'c>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_continuable<'c>(
|
||||||
|
ctxs: &'c mut [BreakableContext],
|
||||||
|
label: Option<LabelId>,
|
||||||
|
) -> Option<&'c mut BreakableContext> {
|
||||||
|
match label {
|
||||||
|
Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
|
||||||
|
None => find_breakable(ctxs, label),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> InferenceContext<'a> {
|
impl<'a> InferenceContext<'a> {
|
||||||
fn new(
|
fn new(
|
||||||
db: &'a dyn HirDatabase,
|
db: &'a dyn HirDatabase,
|
||||||
|
|
|
@ -25,7 +25,9 @@ use syntax::ast::RangeOp;
|
||||||
use crate::{
|
use crate::{
|
||||||
autoderef::{builtin_deref, deref_by_trait, Autoderef},
|
autoderef::{builtin_deref, deref_by_trait, Autoderef},
|
||||||
consteval,
|
consteval,
|
||||||
infer::{coerce::CoerceMany, pat::contains_explicit_ref_binding, BreakableKind},
|
infer::{
|
||||||
|
coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind,
|
||||||
|
},
|
||||||
lang_items::lang_items_for_bin_op,
|
lang_items::lang_items_for_bin_op,
|
||||||
lower::{
|
lower::{
|
||||||
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
|
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
|
||||||
|
@ -457,13 +459,29 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.resolver.reset_to_guard(g);
|
self.resolver.reset_to_guard(g);
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
Expr::Continue { .. } => self.result.standard_types.never.clone(),
|
&Expr::Continue { label } => {
|
||||||
|
if let None = find_continuable(&mut self.breakables, label) {
|
||||||
|
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
|
||||||
|
expr: tgt_expr,
|
||||||
|
is_break: false,
|
||||||
|
bad_value_break: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
self.result.standard_types.never.clone()
|
||||||
|
}
|
||||||
&Expr::Break { expr, label } => {
|
&Expr::Break { expr, label } => {
|
||||||
let val_ty = if let Some(expr) = expr {
|
let val_ty = if let Some(expr) = expr {
|
||||||
let opt_coerce_to = match find_breakable(&mut self.breakables, label) {
|
let opt_coerce_to = match find_breakable(&mut self.breakables, label) {
|
||||||
Some(ctxt) => match &ctxt.coerce {
|
Some(ctxt) => match &ctxt.coerce {
|
||||||
Some(coerce) => coerce.expected_ty(),
|
Some(coerce) => coerce.expected_ty(),
|
||||||
None => self.err_ty(),
|
None => {
|
||||||
|
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
|
||||||
|
expr: tgt_expr,
|
||||||
|
is_break: true,
|
||||||
|
bad_value_break: true,
|
||||||
|
});
|
||||||
|
self.err_ty()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => self.err_ty(),
|
None => self.err_ty(),
|
||||||
};
|
};
|
||||||
|
@ -485,7 +503,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
None => ctxt.may_break = true,
|
None => ctxt.may_break = true,
|
||||||
},
|
},
|
||||||
None => {}
|
None => {
|
||||||
|
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
|
||||||
|
expr: tgt_expr,
|
||||||
|
is_break: true,
|
||||||
|
bad_value_break: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.result.standard_types.never.clone()
|
self.result.standard_types.never.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ macro_rules! diagnostics {
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics![
|
diagnostics![
|
||||||
|
BreakOutsideOfLoop,
|
||||||
ExpectedFunction,
|
ExpectedFunction,
|
||||||
InactiveCode,
|
InactiveCode,
|
||||||
IncorrectCase,
|
IncorrectCase,
|
||||||
|
@ -62,6 +63,13 @@ diagnostics![
|
||||||
UnusedMut,
|
UnusedMut,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BreakOutsideOfLoop {
|
||||||
|
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||||
|
pub is_break: bool,
|
||||||
|
pub bad_value_break: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UnresolvedModule {
|
pub struct UnresolvedModule {
|
||||||
pub decl: InFile<AstPtr<ast::Module>>,
|
pub decl: InFile<AstPtr<ast::Module>>,
|
||||||
|
|
|
@ -85,13 +85,13 @@ use crate::db::{DefDatabase, HirDatabase};
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
attrs::{HasAttrs, Namespace},
|
attrs::{HasAttrs, Namespace},
|
||||||
diagnostics::{
|
diagnostics::{
|
||||||
AnyDiagnostic, ExpectedFunction, InactiveCode, IncoherentImpl, IncorrectCase,
|
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
|
||||||
InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
|
IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
|
||||||
MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
|
MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
|
||||||
ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel, UnimplementedBuiltinMacro,
|
PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel,
|
||||||
UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport,
|
UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
|
||||||
UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro,
|
UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
|
||||||
UnusedMut,
|
UnresolvedProcMacro, UnusedMut,
|
||||||
},
|
},
|
||||||
has_source::HasSource,
|
has_source::HasSource,
|
||||||
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
|
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
|
||||||
|
@ -1483,6 +1483,14 @@ impl DefWithBody {
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
&hir_ty::InferenceDiagnostic::BreakOutsideOfLoop {
|
||||||
|
expr,
|
||||||
|
is_break,
|
||||||
|
bad_value_break,
|
||||||
|
} => {
|
||||||
|
let expr = expr_syntax(expr);
|
||||||
|
acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (pat_or_expr, mismatch) in infer.type_mismatches() {
|
for (pat_or_expr, mismatch) in infer.type_mismatches() {
|
||||||
|
|
|
@ -31,12 +31,8 @@ mod tests {
|
||||||
fn foo() {
|
fn foo() {
|
||||||
break;
|
break;
|
||||||
//^^^^^ error: break outside of loop
|
//^^^^^ error: break outside of loop
|
||||||
break 'a;
|
|
||||||
//^^^^^^^^ error: break outside of loop
|
|
||||||
continue;
|
continue;
|
||||||
//^^^^^^^^ error: continue outside of loop
|
//^^^^^^^^ error: continue outside of loop
|
||||||
continue 'a;
|
|
||||||
//^^^^^^^^^^^ error: continue outside of loop
|
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -51,12 +47,8 @@ fn foo() {
|
||||||
async {
|
async {
|
||||||
break;
|
break;
|
||||||
//^^^^^ error: break outside of loop
|
//^^^^^ error: break outside of loop
|
||||||
break 'a;
|
|
||||||
//^^^^^^^^ error: break outside of loop
|
|
||||||
continue;
|
continue;
|
||||||
//^^^^^^^^ error: continue outside of loop
|
//^^^^^^^^ error: continue outside of loop
|
||||||
continue 'a;
|
|
||||||
//^^^^^^^^^^^ error: continue outside of loop
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,12 +65,8 @@ fn foo() {
|
||||||
|| {
|
|| {
|
||||||
break;
|
break;
|
||||||
//^^^^^ error: break outside of loop
|
//^^^^^ error: break outside of loop
|
||||||
break 'a;
|
|
||||||
//^^^^^^^^ error: break outside of loop
|
|
||||||
continue;
|
continue;
|
||||||
//^^^^^^^^ error: continue outside of loop
|
//^^^^^^^^ error: continue outside of loop
|
||||||
continue 'a;
|
|
||||||
//^^^^^^^^^^^ error: continue outside of loop
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,9 +82,7 @@ fn foo() {
|
||||||
'a: loop {
|
'a: loop {
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
break 'a;
|
|
||||||
continue;
|
continue;
|
||||||
continue 'a;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,9 +98,7 @@ fn foo() {
|
||||||
'a: loop {
|
'a: loop {
|
||||||
try {
|
try {
|
||||||
break;
|
break;
|
||||||
break 'a;
|
|
||||||
continue;
|
continue;
|
||||||
continue 'a;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,11 +114,8 @@ fn foo() {
|
||||||
'a: {
|
'a: {
|
||||||
break;
|
break;
|
||||||
//^^^^^ error: break outside of loop
|
//^^^^^ error: break outside of loop
|
||||||
break 'a;
|
|
||||||
continue;
|
continue;
|
||||||
//^^^^^^^^ error: continue outside of loop
|
//^^^^^^^^ error: continue outside of loop
|
||||||
continue 'a;
|
|
||||||
//^^^^^^^^^^^ error: continue outside of loop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
|
|
@ -23,8 +23,10 @@ mod tests {
|
||||||
r#"
|
r#"
|
||||||
fn foo() {
|
fn foo() {
|
||||||
break 'a;
|
break 'a;
|
||||||
|
//^^^^^^^^ error: break outside of loop
|
||||||
//^^ error: use of undeclared label `'a`
|
//^^ error: use of undeclared label `'a`
|
||||||
continue 'a;
|
continue 'a;
|
||||||
|
//^^^^^^^^^^^ error: continue outside of loop
|
||||||
//^^ error: use of undeclared label `'a`
|
//^^ error: use of undeclared label `'a`
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
|
|
@ -25,8 +25,10 @@ fn foo() {
|
||||||
'a: loop {
|
'a: loop {
|
||||||
async {
|
async {
|
||||||
break 'a;
|
break 'a;
|
||||||
|
//^^^^^^^^ error: break outside of loop
|
||||||
// ^^ error: use of unreachable label `'a`
|
// ^^ error: use of unreachable label `'a`
|
||||||
continue 'a;
|
continue 'a;
|
||||||
|
//^^^^^^^^^^^ error: continue outside of loop
|
||||||
// ^^ error: use of unreachable label `'a`
|
// ^^ error: use of unreachable label `'a`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -43,8 +45,10 @@ fn foo() {
|
||||||
'a: loop {
|
'a: loop {
|
||||||
|| {
|
|| {
|
||||||
break 'a;
|
break 'a;
|
||||||
|
//^^^^^^^^ error: break outside of loop
|
||||||
// ^^ error: use of unreachable label `'a`
|
// ^^ error: use of unreachable label `'a`
|
||||||
continue 'a;
|
continue 'a;
|
||||||
|
//^^^^^^^^^^^ error: continue outside of loop
|
||||||
// ^^ error: use of unreachable label `'a`
|
// ^^ error: use of unreachable label `'a`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
|
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
|
||||||
|
|
||||||
mod handlers {
|
mod handlers {
|
||||||
|
pub(crate) mod break_outside_of_loop;
|
||||||
pub(crate) mod expected_function;
|
pub(crate) mod expected_function;
|
||||||
pub(crate) mod inactive_code;
|
pub(crate) mod inactive_code;
|
||||||
pub(crate) mod incoherent_impl;
|
pub(crate) mod incoherent_impl;
|
||||||
|
@ -285,7 +286,7 @@ pub fn diagnostics(
|
||||||
AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
|
AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
|
||||||
AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
|
AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
|
||||||
AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d),
|
AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d),
|
||||||
|
AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
|
||||||
};
|
};
|
||||||
res.push(d)
|
res.push(d)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue