Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer.rs')
-rw-r--r--crates/hir-ty/src/infer.rs33
1 files changed, 30 insertions, 3 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 5df48e5fdc..10ffde87ee 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -182,7 +182,7 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum InferenceDiagnostic {
NoSuchField { expr: ExprId },
- BreakOutsideOfLoop { expr: ExprId },
+ BreakOutsideOfLoop { expr: ExprId, is_break: bool },
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
}
@@ -418,18 +418,45 @@ pub(crate) struct InferenceContext<'a> {
#[derive(Clone, Debug)]
struct BreakableContext {
+ /// Whether this context contains at least one break expression.
may_break: bool,
+ /// The coercion target of the context.
coerce: CoerceMany,
+ /// The optional label of the context.
label: Option<name::Name>,
+ kind: BreakableKind,
+}
+
+#[derive(Clone, Debug)]
+enum BreakableKind {
+ Block,
+ Loop,
+ /// A border is something like an async block, closure etc. Anything that prevents
+ /// breaking/continuing through
+ Border,
}
fn find_breakable<'c>(
ctxs: &'c mut [BreakableContext],
label: Option<&name::Name>,
) -> Option<&'c mut BreakableContext> {
+ let mut ctxs = ctxs
+ .iter_mut()
+ .rev()
+ .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
+ match label {
+ Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
+ None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
+ }
+}
+
+fn find_continuable<'c>(
+ ctxs: &'c mut [BreakableContext],
+ label: Option<&name::Name>,
+) -> Option<&'c mut BreakableContext> {
match label {
- Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
- None => ctxs.last_mut(),
+ Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
+ None => find_breakable(ctxs, label),
}
}