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
|
||||
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 {
|
||||
call_expr: ExprId,
|
||||
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> {
|
||||
fn new(
|
||||
db: &'a dyn HirDatabase,
|
||||
|
|
|
@ -25,7 +25,9 @@ use syntax::ast::RangeOp;
|
|||
use crate::{
|
||||
autoderef::{builtin_deref, deref_by_trait, Autoderef},
|
||||
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,
|
||||
lower::{
|
||||
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);
|
||||
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 } => {
|
||||
let val_ty = if let Some(expr) = expr {
|
||||
let opt_coerce_to = match find_breakable(&mut self.breakables, label) {
|
||||
Some(ctxt) => match &ctxt.coerce {
|
||||
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(),
|
||||
};
|
||||
|
@ -485,7 +503,13 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ macro_rules! diagnostics {
|
|||
}
|
||||
|
||||
diagnostics![
|
||||
BreakOutsideOfLoop,
|
||||
ExpectedFunction,
|
||||
InactiveCode,
|
||||
IncorrectCase,
|
||||
|
@ -62,6 +63,13 @@ diagnostics![
|
|||
UnusedMut,
|
||||
];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BreakOutsideOfLoop {
|
||||
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||
pub is_break: bool,
|
||||
pub bad_value_break: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnresolvedModule {
|
||||
pub decl: InFile<AstPtr<ast::Module>>,
|
||||
|
|
|
@ -85,13 +85,13 @@ use crate::db::{DefDatabase, HirDatabase};
|
|||
pub use crate::{
|
||||
attrs::{HasAttrs, Namespace},
|
||||
diagnostics::{
|
||||
AnyDiagnostic, ExpectedFunction, InactiveCode, IncoherentImpl, IncorrectCase,
|
||||
InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
|
||||
MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
|
||||
ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel, UnimplementedBuiltinMacro,
|
||||
UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport,
|
||||
UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro,
|
||||
UnusedMut,
|
||||
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
|
||||
IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
|
||||
MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
|
||||
PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel,
|
||||
UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
|
||||
UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
|
||||
UnresolvedProcMacro, UnusedMut,
|
||||
},
|
||||
has_source::HasSource,
|
||||
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
|
||||
|
@ -1483,6 +1483,14 @@ impl DefWithBody {
|
|||
.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() {
|
||||
|
|
|
@ -31,12 +31,8 @@ mod tests {
|
|||
fn foo() {
|
||||
break;
|
||||
//^^^^^ error: break outside of loop
|
||||
break 'a;
|
||||
//^^^^^^^^ error: break outside of loop
|
||||
continue;
|
||||
//^^^^^^^^ error: continue outside of loop
|
||||
continue 'a;
|
||||
//^^^^^^^^^^^ error: continue outside of loop
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
@ -51,12 +47,8 @@ fn foo() {
|
|||
async {
|
||||
break;
|
||||
//^^^^^ error: break outside of loop
|
||||
break 'a;
|
||||
//^^^^^^^^ error: break outside of loop
|
||||
continue;
|
||||
//^^^^^^^^ error: continue outside of loop
|
||||
continue 'a;
|
||||
//^^^^^^^^^^^ error: continue outside of loop
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -73,12 +65,8 @@ fn foo() {
|
|||
|| {
|
||||
break;
|
||||
//^^^^^ error: break outside of loop
|
||||
break 'a;
|
||||
//^^^^^^^^ error: break outside of loop
|
||||
continue;
|
||||
//^^^^^^^^ error: continue outside of loop
|
||||
continue 'a;
|
||||
//^^^^^^^^^^^ error: continue outside of loop
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -94,9 +82,7 @@ fn foo() {
|
|||
'a: loop {
|
||||
{
|
||||
break;
|
||||
break 'a;
|
||||
continue;
|
||||
continue 'a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,9 +98,7 @@ fn foo() {
|
|||
'a: loop {
|
||||
try {
|
||||
break;
|
||||
break 'a;
|
||||
continue;
|
||||
continue 'a;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -130,11 +114,8 @@ fn foo() {
|
|||
'a: {
|
||||
break;
|
||||
//^^^^^ error: break outside of loop
|
||||
break 'a;
|
||||
continue;
|
||||
//^^^^^^^^ error: continue outside of loop
|
||||
continue 'a;
|
||||
//^^^^^^^^^^^ error: continue outside of loop
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
|
|
@ -23,8 +23,10 @@ mod tests {
|
|||
r#"
|
||||
fn foo() {
|
||||
break 'a;
|
||||
//^^^^^^^^ error: break outside of loop
|
||||
//^^ error: use of undeclared label `'a`
|
||||
continue 'a;
|
||||
//^^^^^^^^^^^ error: continue outside of loop
|
||||
//^^ error: use of undeclared label `'a`
|
||||
}
|
||||
"#,
|
||||
|
|
|
@ -25,8 +25,10 @@ fn foo() {
|
|||
'a: loop {
|
||||
async {
|
||||
break 'a;
|
||||
//^^^^^^^^ error: break outside of loop
|
||||
// ^^ error: use of unreachable label `'a`
|
||||
continue 'a;
|
||||
//^^^^^^^^^^^ error: continue outside of loop
|
||||
// ^^ error: use of unreachable label `'a`
|
||||
};
|
||||
}
|
||||
|
@ -43,8 +45,10 @@ fn foo() {
|
|||
'a: loop {
|
||||
|| {
|
||||
break 'a;
|
||||
//^^^^^^^^ error: break outside of loop
|
||||
// ^^ error: use of unreachable label `'a`
|
||||
continue 'a;
|
||||
//^^^^^^^^^^^ error: continue outside of loop
|
||||
// ^^ error: use of unreachable label `'a`
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
|
||||
|
||||
mod handlers {
|
||||
pub(crate) mod break_outside_of_loop;
|
||||
pub(crate) mod expected_function;
|
||||
pub(crate) mod inactive_code;
|
||||
pub(crate) mod incoherent_impl;
|
||||
|
@ -285,7 +286,7 @@ pub fn diagnostics(
|
|||
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::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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue