summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty/src/infer.rs')
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs39
1 files changed, 35 insertions, 4 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 46eeea0e6..10ffde87e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/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),
}
}
@@ -734,6 +761,7 @@ impl<'a> InferenceContext<'a> {
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
return (ty, Some(strukt.into()));
}
+ ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
_ => return (self.err_ty(), None),
},
Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
@@ -875,7 +903,10 @@ impl<'a> InferenceContext<'a> {
}
fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
- let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?;
+ let trait_ = self
+ .resolver
+ .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
+ .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
}