Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/closure.rs')
-rw-r--r--crates/hir-ty/src/infer/closure.rs120
1 files changed, 94 insertions, 26 deletions
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index e9825cf099..5a251683b9 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -11,11 +11,12 @@ use either::Either;
use hir_def::{
data::adt::VariantData,
hir::{
- Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement,
- UnaryOp,
+ Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId,
+ Statement, UnaryOp,
},
lang_item::LangItem,
- resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
+ path::Path,
+ resolver::ValueNs,
DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
};
use hir_expand::name::Name;
@@ -282,11 +283,11 @@ impl CapturedItem {
ProjectionElem::Deref => {}
ProjectionElem::Field(Either::Left(f)) => {
match &*f.parent.variant_data(db.upcast()) {
- VariantData::Record(fields) => {
+ VariantData::Record { fields, .. } => {
result.push('_');
result.push_str(fields[f.local_id].name.as_str())
}
- VariantData::Tuple(fields) => {
+ VariantData::Tuple { fields, .. } => {
let index = fields.iter().position(|it| it.0 == f.local_id);
if let Some(index) = index {
format_to!(result, "_{index}");
@@ -324,12 +325,12 @@ impl CapturedItem {
ProjectionElem::Field(Either::Left(f)) => {
let variant_data = f.parent.variant_data(db.upcast());
match &*variant_data {
- VariantData::Record(fields) => format_to!(
+ VariantData::Record { fields, .. } => format_to!(
result,
".{}",
fields[f.local_id].name.display(db.upcast(), edition)
),
- VariantData::Tuple(fields) => format_to!(
+ VariantData::Tuple { fields, .. } => format_to!(
result,
".{}",
fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default()
@@ -382,8 +383,10 @@ impl CapturedItem {
}
let variant_data = f.parent.variant_data(db.upcast());
let field = match &*variant_data {
- VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(),
- VariantData::Tuple(fields) => fields
+ VariantData::Record { fields, .. } => {
+ fields[f.local_id].name.as_str().to_owned()
+ }
+ VariantData::Tuple { fields, .. } => fields
.iter()
.position(|it| it.0 == f.local_id)
.unwrap_or_default()
@@ -508,18 +511,39 @@ impl InferenceContext<'_> {
apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments)
}
+ /// Pushes the span into `current_capture_span_stack`, *without clearing it first*.
+ fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option<HirPlace> {
+ if path.type_anchor().is_some() {
+ return None;
+ }
+ let hygiene = self.body.expr_or_pat_path_hygiene(id);
+ let result = self
+ .resolver
+ .resolve_path_in_value_ns_fully(self.db.upcast(), path, hygiene)
+ .and_then(|result| match result {
+ ValueNs::LocalBinding(binding) => {
+ let mir_span = match id {
+ ExprOrPatId::ExprId(id) => MirSpan::ExprId(id),
+ ExprOrPatId::PatId(id) => MirSpan::PatId(id),
+ };
+ self.current_capture_span_stack.push(mir_span);
+ Some(HirPlace { local: binding, projections: Vec::new() })
+ }
+ _ => None,
+ });
+ result
+ }
+
/// Changes `current_capture_span_stack` to contain the stack of spans for this expr.
fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option<HirPlace> {
self.current_capture_span_stack.clear();
match &self.body[tgt_expr] {
Expr::Path(p) => {
- let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
- if let Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(b), _)) =
- resolver.resolve_path_in_value_ns(self.db.upcast(), p)
- {
- self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
- return Some(HirPlace { local: b, projections: vec![] });
- }
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+ let result = self.path_place(p, tgt_expr.into());
+ self.resolver.reset_to_guard(resolver_guard);
+ return result;
}
Expr::Field { expr, name: _ } => {
let mut place = self.place_of_expr(*expr)?;
@@ -590,6 +614,16 @@ impl InferenceContext<'_> {
}
}
+ fn mutate_path_pat(&mut self, path: &Path, id: PatId) {
+ if let Some(place) = self.path_place(path, id.into()) {
+ self.add_capture(
+ place,
+ CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
+ );
+ self.current_capture_span_stack.pop(); // Remove the pattern span.
+ }
+ }
+
fn mutate_expr(&mut self, expr: ExprId, place: Option<HirPlace>) {
if let Some(place) = place {
self.add_capture(
@@ -715,14 +749,14 @@ impl InferenceContext<'_> {
Statement::Expr { expr, has_semi: _ } => {
self.consume_expr(*expr);
}
- Statement::Item => (),
+ Statement::Item(_) => (),
}
}
if let Some(tail) = tail {
self.consume_expr(*tail);
}
}
- Expr::Call { callee, args, is_assignee_expr: _ } => {
+ Expr::Call { callee, args } => {
self.consume_expr(*callee);
self.consume_exprs(args.iter().copied());
}
@@ -838,7 +872,7 @@ impl InferenceContext<'_> {
self.consume_expr(expr);
}
}
- Expr::Index { base, index, is_assignee_expr: _ } => {
+ Expr::Index { base, index } => {
self.select_from_expr(*base);
self.consume_expr(*index);
}
@@ -862,10 +896,30 @@ impl InferenceContext<'_> {
}));
self.current_captures = cc;
}
- Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ })
- | Expr::Tuple { exprs, is_assignee_expr: _ } => {
+ Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => {
self.consume_exprs(exprs.iter().copied())
}
+ &Expr::Assignment { target, value } => {
+ self.walk_expr(value);
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+ match self.place_of_expr(value) {
+ Some(rhs_place) => {
+ self.inside_assignment = true;
+ self.consume_with_pat(rhs_place, target);
+ self.inside_assignment = false;
+ }
+ None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] {
+ Pat::Path(path) => self.mutate_path_pat(path, pat),
+ &Pat::Expr(expr) => {
+ let place = self.place_of_expr(expr);
+ self.mutate_expr(expr, place);
+ }
+ _ => {}
+ }),
+ }
+ self.resolver.reset_to_guard(resolver_guard);
+ }
Expr::Missing
| Expr::Continue { .. }
@@ -903,6 +957,7 @@ impl InferenceContext<'_> {
| Pat::Missing
| Pat::Wild
| Pat::Tuple { .. }
+ | Pat::Expr(_)
| Pat::Or(_) => (),
Pat::TupleStruct { .. } | Pat::Record { .. } => {
if let Some(variant) = self.result.variant_resolution_for_pat(p) {
@@ -1122,11 +1177,15 @@ impl InferenceContext<'_> {
}
}
}
- Pat::Range { .. }
- | Pat::Slice { .. }
- | Pat::ConstBlock(_)
- | Pat::Path(_)
- | Pat::Lit(_) => self.consume_place(place),
+ Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => {
+ self.consume_place(place)
+ }
+ Pat::Path(path) => {
+ if self.inside_assignment {
+ self.mutate_path_pat(path, tgt_pat);
+ }
+ self.consume_place(place);
+ }
&Pat::Bind { id, subpat: _ } => {
let mode = self.result.binding_modes[tgt_pat];
let capture_kind = match mode {
@@ -1180,6 +1239,15 @@ impl InferenceContext<'_> {
self.current_capture_span_stack.pop();
}
Pat::Box { .. } => (), // not supported
+ &Pat::Expr(expr) => {
+ self.consume_place(place);
+ let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack);
+ let old_inside_assignment = mem::replace(&mut self.inside_assignment, false);
+ let lhs_place = self.place_of_expr(expr);
+ self.mutate_expr(expr, lhs_place);
+ self.inside_assignment = old_inside_assignment;
+ self.current_capture_span_stack = pat_capture_span_stack;
+ }
}
}
self.current_capture_span_stack