Re-enable controlflow outside loop diagnostic

This commit is contained in:
Lukas Wirth 2023-04-06 15:37:53 +02:00
parent 0e7117900c
commit fbb1bd5880
8 changed files with 75 additions and 31 deletions

View file

@ -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,

View file

@ -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()
}

View file

@ -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>>,

View file

@ -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() {

View file

@ -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
}
}
"#,

View file

@ -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`
}
"#,

View file

@ -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`
};
}

View file

@ -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)
}