hir_ty/infer/
closure.rs

1//! Inference of closure parameter types based on the closure's expected type.
2
3use std::{cmp, convert::Infallible, mem, ops::ControlFlow};
4
5use chalk_ir::{
6    BoundVar, DebruijnIndex, FnSubst, GenericArg, Mutability, TyKind,
7    cast::Cast,
8    fold::{FallibleTypeFolder, Shift, TypeFoldable},
9    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
10};
11use either::Either;
12use hir_def::{
13    DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
14    expr_store::path::Path,
15    hir::{
16        Array, AsmOperand, BinaryOp, BindingId, CaptureBy, ClosureKind, Expr, ExprId, ExprOrPatId,
17        Pat, PatId, Statement, UnaryOp,
18    },
19    item_tree::FieldsShape,
20    lang_item::LangItem,
21    resolver::ValueNs,
22    type_ref::TypeRefId,
23};
24use hir_def::{ItemContainerId, Lookup, TraitId};
25use hir_expand::name::Name;
26use intern::sym;
27use rustc_hash::{FxHashMap, FxHashSet};
28use smallvec::{SmallVec, smallvec};
29use stdx::{format_to, never};
30use syntax::utils::is_raw_identifier;
31
32use crate::{
33    Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ClosureId, DynTy, DynTyExt, FnAbi,
34    FnPointer, FnSig, Interner, OpaqueTy, ProjectionTy, ProjectionTyExt, Substitution, Ty,
35    TyBuilder, TyExt, WhereClause,
36    db::{HirDatabase, InternedClosure, InternedCoroutine},
37    error_lifetime, from_assoc_type_id, from_chalk_trait_id, from_placeholder_idx,
38    generics::Generics,
39    infer::{BreakableKind, CoerceMany, Diverges, coerce::CoerceNever},
40    make_binders,
41    mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
42    to_assoc_type_id,
43    traits::FnTrait,
44    utils::{self, elaborate_clause_supertraits},
45};
46
47use super::{Expectation, InferenceContext};
48
49#[derive(Debug)]
50pub(super) struct ClosureSignature {
51    pub(super) ret_ty: Ty,
52    pub(super) expected_sig: FnPointer,
53}
54
55impl InferenceContext<'_> {
56    pub(super) fn infer_closure(
57        &mut self,
58        body: &ExprId,
59        args: &[PatId],
60        ret_type: &Option<TypeRefId>,
61        arg_types: &[Option<TypeRefId>],
62        closure_kind: ClosureKind,
63        tgt_expr: ExprId,
64        expected: &Expectation,
65    ) -> Ty {
66        assert_eq!(args.len(), arg_types.len());
67
68        let (expected_sig, expected_kind) = match expected.to_option(&mut self.table) {
69            Some(expected_ty) => self.deduce_closure_signature(&expected_ty, closure_kind),
70            None => (None, None),
71        };
72
73        let ClosureSignature { expected_sig: bound_sig, ret_ty: body_ret_ty } =
74            self.sig_of_closure(body, ret_type, arg_types, closure_kind, expected_sig);
75        let bound_sig = self.normalize_associated_types_in(bound_sig);
76        let sig_ty = TyKind::Function(bound_sig.clone()).intern(Interner);
77
78        let (id, ty, resume_yield_tys) = match closure_kind {
79            ClosureKind::Coroutine(_) => {
80                let sig_tys = bound_sig.substitution.0.as_slice(Interner);
81                // FIXME: report error when there are more than 1 parameter.
82                let resume_ty = match sig_tys.first() {
83                    // When `sig_tys.len() == 1` the first type is the return type, not the
84                    // first parameter type.
85                    Some(ty) if sig_tys.len() > 1 => ty.assert_ty_ref(Interner).clone(),
86                    _ => self.result.standard_types.unit.clone(),
87                };
88                let yield_ty = self.table.new_type_var();
89
90                let subst = TyBuilder::subst_for_coroutine(self.db, self.owner)
91                    .push(resume_ty.clone())
92                    .push(yield_ty.clone())
93                    .push(body_ret_ty.clone())
94                    .build();
95
96                let coroutine_id =
97                    self.db.intern_coroutine(InternedCoroutine(self.owner, tgt_expr)).into();
98                let coroutine_ty = TyKind::Coroutine(coroutine_id, subst).intern(Interner);
99
100                (None, coroutine_ty, Some((resume_ty, yield_ty)))
101            }
102            ClosureKind::Closure | ClosureKind::Async => {
103                let closure_id =
104                    self.db.intern_closure(InternedClosure(self.owner, tgt_expr)).into();
105                let closure_ty = TyKind::Closure(
106                    closure_id,
107                    TyBuilder::subst_for_closure(self.db, self.owner, sig_ty.clone()),
108                )
109                .intern(Interner);
110                self.deferred_closures.entry(closure_id).or_default();
111                self.add_current_closure_dependency(closure_id);
112                (Some(closure_id), closure_ty, None)
113            }
114        };
115
116        // Eagerly try to relate the closure type with the expected
117        // type, otherwise we often won't have enough information to
118        // infer the body.
119        self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected, expected_kind);
120
121        // Now go through the argument patterns
122        for (arg_pat, arg_ty) in args.iter().zip(bound_sig.substitution.0.as_slice(Interner).iter())
123        {
124            self.infer_top_pat(*arg_pat, arg_ty.assert_ty_ref(Interner), None);
125        }
126
127        // FIXME: lift these out into a struct
128        let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
129        let prev_closure = mem::replace(&mut self.current_closure, id);
130        let prev_ret_ty = mem::replace(&mut self.return_ty, body_ret_ty.clone());
131        let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(body_ret_ty));
132        let prev_resume_yield_tys = mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
133
134        self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
135            this.infer_return(*body);
136        });
137
138        self.diverges = prev_diverges;
139        self.return_ty = prev_ret_ty;
140        self.return_coercion = prev_ret_coercion;
141        self.current_closure = prev_closure;
142        self.resume_yield_tys = prev_resume_yield_tys;
143
144        self.table.normalize_associated_types_in(ty)
145    }
146
147    // This function handles both closures and coroutines.
148    pub(super) fn deduce_closure_type_from_expectations(
149        &mut self,
150        closure_expr: ExprId,
151        closure_ty: &Ty,
152        sig_ty: &Ty,
153        expectation: &Expectation,
154        expected_kind: Option<FnTrait>,
155    ) {
156        let expected_ty = match expectation.to_option(&mut self.table) {
157            Some(ty) => ty,
158            None => return,
159        };
160
161        match (closure_ty.kind(Interner), expected_kind) {
162            (TyKind::Closure(closure_id, _), Some(closure_kind)) => {
163                self.result
164                    .closure_info
165                    .entry(*closure_id)
166                    .or_insert_with(|| (Vec::new(), closure_kind));
167            }
168            _ => {}
169        }
170
171        // Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
172        let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty, CoerceNever::Yes);
173
174        // Coroutines are not Fn* so return early.
175        if matches!(closure_ty.kind(Interner), TyKind::Coroutine(..)) {
176            return;
177        }
178
179        // Deduction based on the expected `dyn Fn` is done separately.
180        if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner)
181            && let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty)
182        {
183            let expected_sig_ty = TyKind::Function(sig).intern(Interner);
184
185            self.unify(sig_ty, &expected_sig_ty);
186        }
187    }
188
189    // Closure kind deductions are mostly from `rustc_hir_typeck/src/closure.rs`.
190    // Might need to port closure sig deductions too.
191    pub(super) fn deduce_closure_signature(
192        &mut self,
193        expected_ty: &Ty,
194        closure_kind: ClosureKind,
195    ) -> (Option<FnSubst<Interner>>, Option<FnTrait>) {
196        match expected_ty.kind(Interner) {
197            TyKind::Alias(AliasTy::Opaque(OpaqueTy { .. })) | TyKind::OpaqueType(..) => {
198                let clauses = expected_ty.impl_trait_bounds(self.db).into_iter().flatten().map(
199                    |b: chalk_ir::Binders<chalk_ir::WhereClause<Interner>>| {
200                        b.into_value_and_skipped_binders().0
201                    },
202                );
203                self.deduce_closure_kind_from_predicate_clauses(expected_ty, clauses, closure_kind)
204            }
205            TyKind::Dyn(dyn_ty) => {
206                let sig =
207                    dyn_ty.bounds.skip_binders().as_slice(Interner).iter().find_map(|bound| {
208                        if let WhereClause::AliasEq(AliasEq {
209                            alias: AliasTy::Projection(projection_ty),
210                            ty: projected_ty,
211                        }) = bound.skip_binders()
212                            && let Some(sig) = self.deduce_sig_from_projection(
213                                closure_kind,
214                                projection_ty,
215                                projected_ty,
216                            )
217                        {
218                            return Some(sig);
219                        }
220                        None
221                    });
222
223                let kind = dyn_ty.principal().and_then(|principal_trait_ref| {
224                    self.fn_trait_kind_from_trait_id(from_chalk_trait_id(
225                        principal_trait_ref.skip_binders().skip_binders().trait_id,
226                    ))
227                });
228
229                (sig, kind)
230            }
231            TyKind::InferenceVar(ty, chalk_ir::TyVariableKind::General) => {
232                let clauses = self.clauses_for_self_ty(*ty);
233                self.deduce_closure_kind_from_predicate_clauses(
234                    expected_ty,
235                    clauses.into_iter(),
236                    closure_kind,
237                )
238            }
239            TyKind::Function(fn_ptr) => match closure_kind {
240                ClosureKind::Closure => (Some(fn_ptr.substitution.clone()), Some(FnTrait::Fn)),
241                ClosureKind::Async | ClosureKind::Coroutine(_) => (None, None),
242            },
243            _ => (None, None),
244        }
245    }
246
247    fn deduce_closure_kind_from_predicate_clauses(
248        &mut self,
249        expected_ty: &Ty,
250        clauses: impl DoubleEndedIterator<Item = WhereClause>,
251        closure_kind: ClosureKind,
252    ) -> (Option<FnSubst<Interner>>, Option<FnTrait>) {
253        let mut expected_sig = None;
254        let mut expected_kind = None;
255
256        for clause in elaborate_clause_supertraits(self.db, clauses.rev()) {
257            if expected_sig.is_none()
258                && let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) =
259                    &clause
260            {
261                let inferred_sig = self.deduce_sig_from_projection(closure_kind, projection, ty);
262                // Make sure that we didn't infer a signature that mentions itself.
263                // This can happen when we elaborate certain supertrait bounds that
264                // mention projections containing the `Self` type. See rust-lang/rust#105401.
265                struct MentionsTy<'a> {
266                    expected_ty: &'a Ty,
267                }
268                impl TypeVisitor<Interner> for MentionsTy<'_> {
269                    type BreakTy = ();
270
271                    fn interner(&self) -> Interner {
272                        Interner
273                    }
274
275                    fn as_dyn(
276                        &mut self,
277                    ) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy>
278                    {
279                        self
280                    }
281
282                    fn visit_ty(&mut self, t: &Ty, db: chalk_ir::DebruijnIndex) -> ControlFlow<()> {
283                        if t == self.expected_ty {
284                            ControlFlow::Break(())
285                        } else {
286                            t.super_visit_with(self, db)
287                        }
288                    }
289                }
290                if inferred_sig
291                    .visit_with(&mut MentionsTy { expected_ty }, chalk_ir::DebruijnIndex::INNERMOST)
292                    .is_continue()
293                {
294                    expected_sig = inferred_sig;
295                }
296            }
297
298            let trait_id = match clause {
299                WhereClause::AliasEq(AliasEq {
300                    alias: AliasTy::Projection(projection), ..
301                }) => projection.trait_(self.db),
302                WhereClause::Implemented(trait_ref) => from_chalk_trait_id(trait_ref.trait_id),
303                _ => continue,
304            };
305            if let Some(closure_kind) = self.fn_trait_kind_from_trait_id(trait_id) {
306                // always use the closure kind that is more permissive.
307                match (expected_kind, closure_kind) {
308                    (None, _) => expected_kind = Some(closure_kind),
309                    (Some(FnTrait::FnMut), FnTrait::Fn) => expected_kind = Some(FnTrait::Fn),
310                    (Some(FnTrait::FnOnce), FnTrait::Fn | FnTrait::FnMut) => {
311                        expected_kind = Some(closure_kind)
312                    }
313                    _ => {}
314                }
315            }
316        }
317
318        (expected_sig, expected_kind)
319    }
320
321    fn deduce_sig_from_dyn_ty(&self, dyn_ty: &DynTy) -> Option<FnPointer> {
322        // Search for a predicate like `<$self as FnX<Args>>::Output == Ret`
323
324        let fn_traits: SmallVec<[TraitId; 3]> =
325            utils::fn_traits(self.db, self.owner.module(self.db).krate()).collect();
326
327        let self_ty = self.result.standard_types.unknown.clone();
328        let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]);
329        for bound in bounds.iter(Interner) {
330            // NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer`
331            if let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) =
332                bound.skip_binders()
333            {
334                let trait_ =
335                    match from_assoc_type_id(projection.associated_ty_id).lookup(self.db).container
336                    {
337                        ItemContainerId::TraitId(t) => t,
338                        _ => panic!("associated type not in trait"),
339                    };
340                if !fn_traits.contains(&trait_) {
341                    return None;
342                }
343
344                // Skip `Self`, get the type argument.
345                let arg = projection.substitution.as_slice(Interner).get(1)?;
346                if let Some(subst) = arg.ty(Interner)?.as_tuple() {
347                    let generic_args = subst.as_slice(Interner);
348                    let mut sig_tys = Vec::with_capacity(generic_args.len() + 1);
349                    for arg in generic_args {
350                        sig_tys.push(arg.ty(Interner)?.clone());
351                    }
352                    sig_tys.push(ty.clone());
353
354                    cov_mark::hit!(dyn_fn_param_informs_call_site_closure_signature);
355                    return Some(FnPointer {
356                        num_binders: bound.len(Interner),
357                        sig: FnSig {
358                            abi: FnAbi::RustCall,
359                            safety: chalk_ir::Safety::Safe,
360                            variadic: false,
361                        },
362                        substitution: FnSubst(Substitution::from_iter(Interner, sig_tys)),
363                    });
364                }
365            }
366        }
367
368        None
369    }
370
371    fn deduce_sig_from_projection(
372        &mut self,
373        closure_kind: ClosureKind,
374        projection_ty: &ProjectionTy,
375        projected_ty: &Ty,
376    ) -> Option<FnSubst<Interner>> {
377        let container =
378            from_assoc_type_id(projection_ty.associated_ty_id).lookup(self.db).container;
379        let trait_ = match container {
380            hir_def::ItemContainerId::TraitId(trait_) => trait_,
381            _ => return None,
382        };
383
384        // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits,
385        // for closures and async closures, respectively.
386        let fn_trait_kind = self.fn_trait_kind_from_trait_id(trait_)?;
387        if !matches!(closure_kind, ClosureKind::Closure | ClosureKind::Async) {
388            return None;
389        }
390        if fn_trait_kind.is_async() {
391            // If the expected trait is `AsyncFn(...) -> X`, we don't know what the return type is,
392            // but we do know it must implement `Future<Output = X>`.
393            self.extract_async_fn_sig_from_projection(projection_ty, projected_ty)
394        } else {
395            self.extract_sig_from_projection(projection_ty, projected_ty)
396        }
397    }
398
399    fn extract_sig_from_projection(
400        &self,
401        projection_ty: &ProjectionTy,
402        projected_ty: &Ty,
403    ) -> Option<FnSubst<Interner>> {
404        let arg_param_ty = projection_ty.substitution.as_slice(Interner)[1].assert_ty_ref(Interner);
405
406        let TyKind::Tuple(_, input_tys) = arg_param_ty.kind(Interner) else {
407            return None;
408        };
409
410        let ret_param_ty = projected_ty;
411
412        Some(FnSubst(Substitution::from_iter(
413            Interner,
414            input_tys.iter(Interner).map(|t| t.cast(Interner)).chain(Some(GenericArg::new(
415                Interner,
416                chalk_ir::GenericArgData::Ty(ret_param_ty.clone()),
417            ))),
418        )))
419    }
420
421    fn extract_async_fn_sig_from_projection(
422        &mut self,
423        projection_ty: &ProjectionTy,
424        projected_ty: &Ty,
425    ) -> Option<FnSubst<Interner>> {
426        let arg_param_ty = projection_ty.substitution.as_slice(Interner)[1].assert_ty_ref(Interner);
427
428        let TyKind::Tuple(_, input_tys) = arg_param_ty.kind(Interner) else {
429            return None;
430        };
431
432        let ret_param_future_output = projected_ty;
433        let ret_param_future = self.table.new_type_var();
434        let future_output =
435            LangItem::FutureOutput.resolve_type_alias(self.db, self.resolver.krate())?;
436        let future_projection = crate::AliasTy::Projection(crate::ProjectionTy {
437            associated_ty_id: to_assoc_type_id(future_output),
438            substitution: Substitution::from1(Interner, ret_param_future.clone()),
439        });
440        self.table.register_obligation(
441            crate::AliasEq { alias: future_projection, ty: ret_param_future_output.clone() }
442                .cast(Interner),
443        );
444
445        Some(FnSubst(Substitution::from_iter(
446            Interner,
447            input_tys.iter(Interner).map(|t| t.cast(Interner)).chain(Some(GenericArg::new(
448                Interner,
449                chalk_ir::GenericArgData::Ty(ret_param_future),
450            ))),
451        )))
452    }
453
454    fn fn_trait_kind_from_trait_id(&self, trait_id: hir_def::TraitId) -> Option<FnTrait> {
455        FnTrait::from_lang_item(self.db.lang_attr(trait_id.into())?)
456    }
457
458    fn supplied_sig_of_closure(
459        &mut self,
460        body: &ExprId,
461        ret_type: &Option<TypeRefId>,
462        arg_types: &[Option<TypeRefId>],
463        closure_kind: ClosureKind,
464    ) -> ClosureSignature {
465        let mut sig_tys = Vec::with_capacity(arg_types.len() + 1);
466
467        // collect explicitly written argument types
468        for arg_type in arg_types.iter() {
469            let arg_ty = match arg_type {
470                // FIXME: I think rustc actually lowers closure params with `LifetimeElisionKind::AnonymousCreateParameter`
471                // (but the return type with infer).
472                Some(type_ref) => self.make_body_ty(*type_ref),
473                None => self.table.new_type_var(),
474            };
475            sig_tys.push(arg_ty);
476        }
477
478        // add return type
479        let ret_ty = match ret_type {
480            Some(type_ref) => self.make_body_ty(*type_ref),
481            None => self.table.new_type_var(),
482        };
483        if let ClosureKind::Async = closure_kind {
484            sig_tys.push(self.lower_async_block_type_impl_trait(ret_ty.clone(), *body));
485        } else {
486            sig_tys.push(ret_ty.clone());
487        }
488
489        let expected_sig = FnPointer {
490            num_binders: 0,
491            sig: FnSig { abi: FnAbi::RustCall, safety: chalk_ir::Safety::Safe, variadic: false },
492            substitution: FnSubst(
493                Substitution::from_iter(Interner, sig_tys.iter().cloned()).shifted_in(Interner),
494            ),
495        };
496
497        ClosureSignature { ret_ty, expected_sig }
498    }
499
500    /// The return type is the signature of the closure, and the return type
501    /// *as represented inside the body* (so, for async closures, the `Output` ty)
502    pub(super) fn sig_of_closure(
503        &mut self,
504        body: &ExprId,
505        ret_type: &Option<TypeRefId>,
506        arg_types: &[Option<TypeRefId>],
507        closure_kind: ClosureKind,
508        expected_sig: Option<FnSubst<Interner>>,
509    ) -> ClosureSignature {
510        if let Some(e) = expected_sig {
511            self.sig_of_closure_with_expectation(body, ret_type, arg_types, closure_kind, e)
512        } else {
513            self.sig_of_closure_no_expectation(body, ret_type, arg_types, closure_kind)
514        }
515    }
516
517    fn sig_of_closure_no_expectation(
518        &mut self,
519        body: &ExprId,
520        ret_type: &Option<TypeRefId>,
521        arg_types: &[Option<TypeRefId>],
522        closure_kind: ClosureKind,
523    ) -> ClosureSignature {
524        self.supplied_sig_of_closure(body, ret_type, arg_types, closure_kind)
525    }
526
527    fn sig_of_closure_with_expectation(
528        &mut self,
529        body: &ExprId,
530        ret_type: &Option<TypeRefId>,
531        arg_types: &[Option<TypeRefId>],
532        closure_kind: ClosureKind,
533        expected_sig: FnSubst<Interner>,
534    ) -> ClosureSignature {
535        let expected_sig = FnPointer {
536            num_binders: 0,
537            sig: FnSig { abi: FnAbi::RustCall, safety: chalk_ir::Safety::Safe, variadic: false },
538            substitution: expected_sig,
539        };
540
541        // If the expected signature does not match the actual arg types,
542        // then just return the expected signature
543        if expected_sig.substitution.0.len(Interner) != arg_types.len() + 1 {
544            let ret_ty = match ret_type {
545                Some(type_ref) => self.make_body_ty(*type_ref),
546                None => self.table.new_type_var(),
547            };
548            return ClosureSignature { expected_sig, ret_ty };
549        }
550
551        self.merge_supplied_sig_with_expectation(
552            body,
553            ret_type,
554            arg_types,
555            closure_kind,
556            expected_sig,
557        )
558    }
559
560    fn merge_supplied_sig_with_expectation(
561        &mut self,
562        body: &ExprId,
563        ret_type: &Option<TypeRefId>,
564        arg_types: &[Option<TypeRefId>],
565        closure_kind: ClosureKind,
566        expected_sig: FnPointer,
567    ) -> ClosureSignature {
568        let supplied_sig = self.supplied_sig_of_closure(body, ret_type, arg_types, closure_kind);
569
570        let snapshot = self.table.snapshot();
571        if !self.table.unify(&expected_sig.substitution, &supplied_sig.expected_sig.substitution) {
572            self.table.rollback_to(snapshot);
573        }
574
575        supplied_sig
576    }
577}
578
579// The below functions handle capture and closure kind (Fn, FnMut, ..)
580
581#[derive(Debug, Clone, PartialEq, Eq, Hash)]
582pub(crate) struct HirPlace {
583    pub(crate) local: BindingId,
584    pub(crate) projections: Vec<ProjectionElem<Infallible, Ty>>,
585}
586
587impl HirPlace {
588    fn ty(&self, ctx: &mut InferenceContext<'_>) -> Ty {
589        let mut ty = ctx.table.resolve_completely(ctx.result[self.local].clone());
590        for p in &self.projections {
591            ty = p.projected_ty(
592                ty,
593                ctx.db,
594                |_, _, _| {
595                    unreachable!("Closure field only happens in MIR");
596                },
597                ctx.owner.module(ctx.db).krate(),
598            );
599        }
600        ty
601    }
602
603    fn capture_kind_of_truncated_place(
604        &self,
605        mut current_capture: CaptureKind,
606        len: usize,
607    ) -> CaptureKind {
608        if let CaptureKind::ByRef(BorrowKind::Mut {
609            kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow,
610        }) = current_capture
611            && self.projections[len..].contains(&ProjectionElem::Deref)
612        {
613            current_capture =
614                CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture });
615        }
616        current_capture
617    }
618}
619
620#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
621pub enum CaptureKind {
622    ByRef(BorrowKind),
623    ByValue,
624}
625
626#[derive(Debug, Clone, PartialEq, Eq)]
627pub struct CapturedItem {
628    pub(crate) place: HirPlace,
629    pub(crate) kind: CaptureKind,
630    /// The inner vec is the stacks; the outer vec is for each capture reference.
631    ///
632    /// Even though we always report only the last span (i.e. the most inclusive span),
633    /// we need to keep them all, since when a closure occurs inside a closure, we
634    /// copy all captures of the inner closure to the outer closure, and then we may
635    /// truncate them, and we want the correct span to be reported.
636    span_stacks: SmallVec<[SmallVec<[MirSpan; 3]>; 3]>,
637    pub(crate) ty: Binders<Ty>,
638}
639
640impl CapturedItem {
641    pub fn local(&self) -> BindingId {
642        self.place.local
643    }
644
645    /// Returns whether this place has any field (aka. non-deref) projections.
646    pub fn has_field_projections(&self) -> bool {
647        self.place.projections.iter().any(|it| !matches!(it, ProjectionElem::Deref))
648    }
649
650    pub fn ty(&self, subst: &Substitution) -> Ty {
651        self.ty.clone().substitute(Interner, utils::ClosureSubst(subst).parent_subst())
652    }
653
654    pub fn kind(&self) -> CaptureKind {
655        self.kind
656    }
657
658    pub fn spans(&self) -> SmallVec<[MirSpan; 3]> {
659        self.span_stacks.iter().map(|stack| *stack.last().expect("empty span stack")).collect()
660    }
661
662    /// Converts the place to a name that can be inserted into source code.
663    pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
664        let body = db.body(owner);
665        let mut result = body[self.place.local].name.as_str().to_owned();
666        for proj in &self.place.projections {
667            match proj {
668                ProjectionElem::Deref => {}
669                ProjectionElem::Field(Either::Left(f)) => {
670                    let variant_data = f.parent.fields(db);
671                    match variant_data.shape {
672                        FieldsShape::Record => {
673                            result.push('_');
674                            result.push_str(variant_data.fields()[f.local_id].name.as_str())
675                        }
676                        FieldsShape::Tuple => {
677                            let index =
678                                variant_data.fields().iter().position(|it| it.0 == f.local_id);
679                            if let Some(index) = index {
680                                format_to!(result, "_{index}");
681                            }
682                        }
683                        FieldsShape::Unit => {}
684                    }
685                }
686                ProjectionElem::Field(Either::Right(f)) => format_to!(result, "_{}", f.index),
687                &ProjectionElem::ClosureField(field) => format_to!(result, "_{field}"),
688                ProjectionElem::Index(_)
689                | ProjectionElem::ConstantIndex { .. }
690                | ProjectionElem::Subslice { .. }
691                | ProjectionElem::OpaqueCast(_) => {
692                    never!("Not happen in closure capture");
693                    continue;
694                }
695            }
696        }
697        if is_raw_identifier(&result, owner.module(db).krate().data(db).edition) {
698            result.insert_str(0, "r#");
699        }
700        result
701    }
702
703    pub fn display_place_source_code(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
704        let body = db.body(owner);
705        let krate = owner.krate(db);
706        let edition = krate.data(db).edition;
707        let mut result = body[self.place.local].name.display(db, edition).to_string();
708        for proj in &self.place.projections {
709            match proj {
710                // In source code autoderef kicks in.
711                ProjectionElem::Deref => {}
712                ProjectionElem::Field(Either::Left(f)) => {
713                    let variant_data = f.parent.fields(db);
714                    match variant_data.shape {
715                        FieldsShape::Record => format_to!(
716                            result,
717                            ".{}",
718                            variant_data.fields()[f.local_id].name.display(db, edition)
719                        ),
720                        FieldsShape::Tuple => format_to!(
721                            result,
722                            ".{}",
723                            variant_data
724                                .fields()
725                                .iter()
726                                .position(|it| it.0 == f.local_id)
727                                .unwrap_or_default()
728                        ),
729                        FieldsShape::Unit => {}
730                    }
731                }
732                ProjectionElem::Field(Either::Right(f)) => {
733                    let field = f.index;
734                    format_to!(result, ".{field}");
735                }
736                &ProjectionElem::ClosureField(field) => {
737                    format_to!(result, ".{field}");
738                }
739                ProjectionElem::Index(_)
740                | ProjectionElem::ConstantIndex { .. }
741                | ProjectionElem::Subslice { .. }
742                | ProjectionElem::OpaqueCast(_) => {
743                    never!("Not happen in closure capture");
744                    continue;
745                }
746            }
747        }
748        let final_derefs_count = self
749            .place
750            .projections
751            .iter()
752            .rev()
753            .take_while(|proj| matches!(proj, ProjectionElem::Deref))
754            .count();
755        result.insert_str(0, &"*".repeat(final_derefs_count));
756        result
757    }
758
759    pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
760        let body = db.body(owner);
761        let krate = owner.krate(db);
762        let edition = krate.data(db).edition;
763        let mut result = body[self.place.local].name.display(db, edition).to_string();
764        let mut field_need_paren = false;
765        for proj in &self.place.projections {
766            match proj {
767                ProjectionElem::Deref => {
768                    result = format!("*{result}");
769                    field_need_paren = true;
770                }
771                ProjectionElem::Field(Either::Left(f)) => {
772                    if field_need_paren {
773                        result = format!("({result})");
774                    }
775                    let variant_data = f.parent.fields(db);
776                    let field = match variant_data.shape {
777                        FieldsShape::Record => {
778                            variant_data.fields()[f.local_id].name.as_str().to_owned()
779                        }
780                        FieldsShape::Tuple => variant_data
781                            .fields()
782                            .iter()
783                            .position(|it| it.0 == f.local_id)
784                            .unwrap_or_default()
785                            .to_string(),
786                        FieldsShape::Unit => "[missing field]".to_owned(),
787                    };
788                    result = format!("{result}.{field}");
789                    field_need_paren = false;
790                }
791                ProjectionElem::Field(Either::Right(f)) => {
792                    let field = f.index;
793                    if field_need_paren {
794                        result = format!("({result})");
795                    }
796                    result = format!("{result}.{field}");
797                    field_need_paren = false;
798                }
799                &ProjectionElem::ClosureField(field) => {
800                    if field_need_paren {
801                        result = format!("({result})");
802                    }
803                    result = format!("{result}.{field}");
804                    field_need_paren = false;
805                }
806                ProjectionElem::Index(_)
807                | ProjectionElem::ConstantIndex { .. }
808                | ProjectionElem::Subslice { .. }
809                | ProjectionElem::OpaqueCast(_) => {
810                    never!("Not happen in closure capture");
811                    continue;
812                }
813            }
814        }
815        result
816    }
817}
818
819#[derive(Debug, Clone, PartialEq, Eq)]
820pub(crate) struct CapturedItemWithoutTy {
821    pub(crate) place: HirPlace,
822    pub(crate) kind: CaptureKind,
823    /// The inner vec is the stacks; the outer vec is for each capture reference.
824    pub(crate) span_stacks: SmallVec<[SmallVec<[MirSpan; 3]>; 3]>,
825}
826
827impl CapturedItemWithoutTy {
828    fn with_ty(self, ctx: &mut InferenceContext<'_>) -> CapturedItem {
829        let ty = self.place.ty(ctx);
830        let ty = match &self.kind {
831            CaptureKind::ByValue => ty,
832            CaptureKind::ByRef(bk) => {
833                let m = match bk {
834                    BorrowKind::Mut { .. } => Mutability::Mut,
835                    _ => Mutability::Not,
836                };
837                TyKind::Ref(m, error_lifetime(), ty).intern(Interner)
838            }
839        };
840        return CapturedItem {
841            place: self.place,
842            kind: self.kind,
843            span_stacks: self.span_stacks,
844            ty: replace_placeholder_with_binder(ctx, ty),
845        };
846
847        fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders<Ty> {
848            struct Filler<'a> {
849                db: &'a dyn HirDatabase,
850                generics: &'a Generics,
851            }
852            impl FallibleTypeFolder<Interner> for Filler<'_> {
853                type Error = ();
854
855                fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
856                    self
857                }
858
859                fn interner(&self) -> Interner {
860                    Interner
861                }
862
863                fn try_fold_free_placeholder_const(
864                    &mut self,
865                    ty: chalk_ir::Ty<Interner>,
866                    idx: chalk_ir::PlaceholderIndex,
867                    outer_binder: DebruijnIndex,
868                ) -> Result<chalk_ir::Const<Interner>, Self::Error> {
869                    let x = from_placeholder_idx(self.db, idx).0;
870                    let Some(idx) = self.generics.type_or_const_param_idx(x) else {
871                        return Err(());
872                    };
873                    Ok(BoundVar::new(outer_binder, idx).to_const(Interner, ty))
874                }
875
876                fn try_fold_free_placeholder_ty(
877                    &mut self,
878                    idx: chalk_ir::PlaceholderIndex,
879                    outer_binder: DebruijnIndex,
880                ) -> std::result::Result<Ty, Self::Error> {
881                    let x = from_placeholder_idx(self.db, idx).0;
882                    let Some(idx) = self.generics.type_or_const_param_idx(x) else {
883                        return Err(());
884                    };
885                    Ok(BoundVar::new(outer_binder, idx).to_ty(Interner))
886                }
887            }
888            let filler = &mut Filler { db: ctx.db, generics: ctx.generics() };
889            let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty);
890            make_binders(ctx.db, filler.generics, result)
891        }
892    }
893}
894
895impl InferenceContext<'_> {
896    fn place_of_expr(&mut self, tgt_expr: ExprId) -> Option<HirPlace> {
897        let r = self.place_of_expr_without_adjust(tgt_expr)?;
898        let adjustments =
899            self.result.expr_adjustments.get(&tgt_expr).map(|it| &**it).unwrap_or_default();
900        apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments)
901    }
902
903    /// Pushes the span into `current_capture_span_stack`, *without clearing it first*.
904    fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option<HirPlace> {
905        if path.type_anchor().is_some() {
906            return None;
907        }
908        let hygiene = self.body.expr_or_pat_path_hygiene(id);
909        self.resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).and_then(|result| {
910            match result {
911                ValueNs::LocalBinding(binding) => {
912                    let mir_span = match id {
913                        ExprOrPatId::ExprId(id) => MirSpan::ExprId(id),
914                        ExprOrPatId::PatId(id) => MirSpan::PatId(id),
915                    };
916                    self.current_capture_span_stack.push(mir_span);
917                    Some(HirPlace { local: binding, projections: Vec::new() })
918                }
919                _ => None,
920            }
921        })
922    }
923
924    /// Changes `current_capture_span_stack` to contain the stack of spans for this expr.
925    fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option<HirPlace> {
926        self.current_capture_span_stack.clear();
927        match &self.body[tgt_expr] {
928            Expr::Path(p) => {
929                let resolver_guard =
930                    self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr);
931                let result = self.path_place(p, tgt_expr.into());
932                self.resolver.reset_to_guard(resolver_guard);
933                return result;
934            }
935            Expr::Field { expr, name: _ } => {
936                let mut place = self.place_of_expr(*expr)?;
937                let field = self.result.field_resolution(tgt_expr)?;
938                self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
939                place.projections.push(ProjectionElem::Field(field));
940                return Some(place);
941            }
942            Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
943                if matches!(
944                    self.expr_ty_after_adjustments(*expr).kind(Interner),
945                    TyKind::Ref(..) | TyKind::Raw(..)
946                ) {
947                    let mut place = self.place_of_expr(*expr)?;
948                    self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
949                    place.projections.push(ProjectionElem::Deref);
950                    return Some(place);
951                }
952            }
953            _ => (),
954        }
955        None
956    }
957
958    fn push_capture(&mut self, place: HirPlace, kind: CaptureKind) {
959        self.current_captures.push(CapturedItemWithoutTy {
960            place,
961            kind,
962            span_stacks: smallvec![self.current_capture_span_stack.iter().copied().collect()],
963        });
964    }
965
966    fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut truncate_to: usize) {
967        // The first span is the identifier, and it must always remain.
968        truncate_to += 1;
969        for span_stack in &mut capture.span_stacks {
970            let mut remained = truncate_to;
971            let mut actual_truncate_to = 0;
972            for &span in &*span_stack {
973                actual_truncate_to += 1;
974                if !span.is_ref_span(self.body) {
975                    remained -= 1;
976                    if remained == 0 {
977                        break;
978                    }
979                }
980            }
981            if actual_truncate_to < span_stack.len()
982                && span_stack[actual_truncate_to].is_ref_span(self.body)
983            {
984                // Include the ref operator if there is one, we will fix it later (in `strip_captures_ref_span()`) if it's incorrect.
985                actual_truncate_to += 1;
986            }
987            span_stack.truncate(actual_truncate_to);
988        }
989    }
990
991    fn ref_expr(&mut self, expr: ExprId, place: Option<HirPlace>) {
992        if let Some(place) = place {
993            self.add_capture(place, CaptureKind::ByRef(BorrowKind::Shared));
994        }
995        self.walk_expr(expr);
996    }
997
998    fn add_capture(&mut self, place: HirPlace, kind: CaptureKind) {
999        if self.is_upvar(&place) {
1000            self.push_capture(place, kind);
1001        }
1002    }
1003
1004    fn mutate_path_pat(&mut self, path: &Path, id: PatId) {
1005        if let Some(place) = self.path_place(path, id.into()) {
1006            self.add_capture(
1007                place,
1008                CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
1009            );
1010            self.current_capture_span_stack.pop(); // Remove the pattern span.
1011        }
1012    }
1013
1014    fn mutate_expr(&mut self, expr: ExprId, place: Option<HirPlace>) {
1015        if let Some(place) = place {
1016            self.add_capture(
1017                place,
1018                CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
1019            );
1020        }
1021        self.walk_expr(expr);
1022    }
1023
1024    fn consume_expr(&mut self, expr: ExprId) {
1025        if let Some(place) = self.place_of_expr(expr) {
1026            self.consume_place(place);
1027        }
1028        self.walk_expr(expr);
1029    }
1030
1031    fn consume_place(&mut self, place: HirPlace) {
1032        if self.is_upvar(&place) {
1033            let ty = place.ty(self);
1034            let kind = if self.is_ty_copy(ty) {
1035                CaptureKind::ByRef(BorrowKind::Shared)
1036            } else {
1037                CaptureKind::ByValue
1038            };
1039            self.push_capture(place, kind);
1040        }
1041    }
1042
1043    fn walk_expr_with_adjust(&mut self, tgt_expr: ExprId, adjustment: &[Adjustment]) {
1044        if let Some((last, rest)) = adjustment.split_last() {
1045            match &last.kind {
1046                Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => {
1047                    self.walk_expr_with_adjust(tgt_expr, rest)
1048                }
1049                Adjust::Deref(Some(m)) => match m.0 {
1050                    Some(m) => {
1051                        self.ref_capture_with_adjusts(m, tgt_expr, rest);
1052                    }
1053                    None => unreachable!(),
1054                },
1055                Adjust::Borrow(b) => {
1056                    self.ref_capture_with_adjusts(b.mutability(), tgt_expr, rest);
1057                }
1058            }
1059        } else {
1060            self.walk_expr_without_adjust(tgt_expr);
1061        }
1062    }
1063
1064    fn ref_capture_with_adjusts(&mut self, m: Mutability, tgt_expr: ExprId, rest: &[Adjustment]) {
1065        let capture_kind = match m {
1066            Mutability::Mut => CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
1067            Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared),
1068        };
1069        if let Some(place) = self.place_of_expr_without_adjust(tgt_expr)
1070            && let Some(place) =
1071                apply_adjusts_to_place(&mut self.current_capture_span_stack, place, rest)
1072        {
1073            self.add_capture(place, capture_kind);
1074        }
1075        self.walk_expr_with_adjust(tgt_expr, rest);
1076    }
1077
1078    fn walk_expr(&mut self, tgt_expr: ExprId) {
1079        if let Some(it) = self.result.expr_adjustments.get_mut(&tgt_expr) {
1080            // FIXME: this take is completely unneeded, and just is here to make borrow checker
1081            // happy. Remove it if you can.
1082            let x_taken = mem::take(it);
1083            self.walk_expr_with_adjust(tgt_expr, &x_taken);
1084            *self.result.expr_adjustments.get_mut(&tgt_expr).unwrap() = x_taken;
1085        } else {
1086            self.walk_expr_without_adjust(tgt_expr);
1087        }
1088    }
1089
1090    fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
1091        match &self.body[tgt_expr] {
1092            Expr::OffsetOf(_) => (),
1093            Expr::InlineAsm(e) => e.operands.iter().for_each(|(_, op)| match op {
1094                AsmOperand::In { expr, .. }
1095                | AsmOperand::Out { expr: Some(expr), .. }
1096                | AsmOperand::InOut { expr, .. } => self.walk_expr_without_adjust(*expr),
1097                AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
1098                    self.walk_expr_without_adjust(*in_expr);
1099                    if let Some(out_expr) = out_expr {
1100                        self.walk_expr_without_adjust(*out_expr);
1101                    }
1102                }
1103                AsmOperand::Out { expr: None, .. }
1104                | AsmOperand::Const(_)
1105                | AsmOperand::Label(_)
1106                | AsmOperand::Sym(_) => (),
1107            }),
1108            Expr::If { condition, then_branch, else_branch } => {
1109                self.consume_expr(*condition);
1110                self.consume_expr(*then_branch);
1111                if let &Some(expr) = else_branch {
1112                    self.consume_expr(expr);
1113                }
1114            }
1115            Expr::Async { statements, tail, .. }
1116            | Expr::Unsafe { statements, tail, .. }
1117            | Expr::Block { statements, tail, .. } => {
1118                for s in statements.iter() {
1119                    match s {
1120                        Statement::Let { pat, type_ref: _, initializer, else_branch } => {
1121                            if let Some(else_branch) = else_branch {
1122                                self.consume_expr(*else_branch);
1123                            }
1124                            if let Some(initializer) = initializer {
1125                                if else_branch.is_some() {
1126                                    self.consume_expr(*initializer);
1127                                } else {
1128                                    self.walk_expr(*initializer);
1129                                }
1130                                if let Some(place) = self.place_of_expr(*initializer) {
1131                                    self.consume_with_pat(place, *pat);
1132                                }
1133                            }
1134                        }
1135                        Statement::Expr { expr, has_semi: _ } => {
1136                            self.consume_expr(*expr);
1137                        }
1138                        Statement::Item(_) => (),
1139                    }
1140                }
1141                if let Some(tail) = tail {
1142                    self.consume_expr(*tail);
1143                }
1144            }
1145            Expr::Call { callee, args } => {
1146                self.consume_expr(*callee);
1147                self.consume_exprs(args.iter().copied());
1148            }
1149            Expr::MethodCall { receiver, args, .. } => {
1150                self.consume_expr(*receiver);
1151                self.consume_exprs(args.iter().copied());
1152            }
1153            Expr::Match { expr, arms } => {
1154                for arm in arms.iter() {
1155                    self.consume_expr(arm.expr);
1156                    if let Some(guard) = arm.guard {
1157                        self.consume_expr(guard);
1158                    }
1159                }
1160                self.walk_expr(*expr);
1161                if let Some(discr_place) = self.place_of_expr(*expr)
1162                    && self.is_upvar(&discr_place)
1163                {
1164                    let mut capture_mode = None;
1165                    for arm in arms.iter() {
1166                        self.walk_pat(&mut capture_mode, arm.pat);
1167                    }
1168                    if let Some(c) = capture_mode {
1169                        self.push_capture(discr_place, c);
1170                    }
1171                }
1172            }
1173            Expr::Break { expr, label: _ }
1174            | Expr::Return { expr }
1175            | Expr::Yield { expr }
1176            | Expr::Yeet { expr } => {
1177                if let &Some(expr) = expr {
1178                    self.consume_expr(expr);
1179                }
1180            }
1181            &Expr::Become { expr } => {
1182                self.consume_expr(expr);
1183            }
1184            Expr::RecordLit { fields, spread, .. } => {
1185                if let &Some(expr) = spread {
1186                    self.consume_expr(expr);
1187                }
1188                self.consume_exprs(fields.iter().map(|it| it.expr));
1189            }
1190            Expr::Field { expr, name: _ } => self.select_from_expr(*expr),
1191            Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
1192                if matches!(
1193                    self.expr_ty_after_adjustments(*expr).kind(Interner),
1194                    TyKind::Ref(..) | TyKind::Raw(..)
1195                ) {
1196                    self.select_from_expr(*expr);
1197                } else if let Some((f, _)) = self.result.method_resolution(tgt_expr) {
1198                    let mutability = 'b: {
1199                        if let Some(deref_trait) =
1200                            self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait())
1201                            && let Some(deref_fn) = deref_trait
1202                                .trait_items(self.db)
1203                                .method_by_name(&Name::new_symbol_root(sym::deref_mut))
1204                        {
1205                            break 'b deref_fn == f;
1206                        }
1207                        false
1208                    };
1209                    let place = self.place_of_expr(*expr);
1210                    if mutability {
1211                        self.mutate_expr(*expr, place);
1212                    } else {
1213                        self.ref_expr(*expr, place);
1214                    }
1215                } else {
1216                    self.select_from_expr(*expr);
1217                }
1218            }
1219            Expr::Let { pat, expr } => {
1220                self.walk_expr(*expr);
1221                if let Some(place) = self.place_of_expr(*expr) {
1222                    self.consume_with_pat(place, *pat);
1223                }
1224            }
1225            Expr::UnaryOp { expr, op: _ }
1226            | Expr::Array(Array::Repeat { initializer: expr, repeat: _ })
1227            | Expr::Await { expr }
1228            | Expr::Loop { body: expr, label: _ }
1229            | Expr::Box { expr }
1230            | Expr::Cast { expr, type_ref: _ } => {
1231                self.consume_expr(*expr);
1232            }
1233            Expr::Ref { expr, rawness: _, mutability } => {
1234                // We need to do this before we push the span so the order will be correct.
1235                let place = self.place_of_expr(*expr);
1236                self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
1237                match mutability {
1238                    hir_def::type_ref::Mutability::Shared => self.ref_expr(*expr, place),
1239                    hir_def::type_ref::Mutability::Mut => self.mutate_expr(*expr, place),
1240                }
1241            }
1242            Expr::BinaryOp { lhs, rhs, op } => {
1243                let Some(op) = op else {
1244                    return;
1245                };
1246                if matches!(op, BinaryOp::Assignment { .. }) {
1247                    let place = self.place_of_expr(*lhs);
1248                    self.mutate_expr(*lhs, place);
1249                    self.consume_expr(*rhs);
1250                    return;
1251                }
1252                self.consume_expr(*lhs);
1253                self.consume_expr(*rhs);
1254            }
1255            Expr::Range { lhs, rhs, range_type: _ } => {
1256                if let &Some(expr) = lhs {
1257                    self.consume_expr(expr);
1258                }
1259                if let &Some(expr) = rhs {
1260                    self.consume_expr(expr);
1261                }
1262            }
1263            Expr::Index { base, index } => {
1264                self.select_from_expr(*base);
1265                self.consume_expr(*index);
1266            }
1267            Expr::Closure { .. } => {
1268                let ty = self.expr_ty(tgt_expr);
1269                let TyKind::Closure(id, _) = ty.kind(Interner) else {
1270                    never!("closure type is always closure");
1271                    return;
1272                };
1273                let (captures, _) =
1274                    self.result.closure_info.get(id).expect(
1275                        "We sort closures, so we should always have data for inner closures",
1276                    );
1277                let mut cc = mem::take(&mut self.current_captures);
1278                cc.extend(captures.iter().filter(|it| self.is_upvar(&it.place)).map(|it| {
1279                    CapturedItemWithoutTy {
1280                        place: it.place.clone(),
1281                        kind: it.kind,
1282                        span_stacks: it.span_stacks.clone(),
1283                    }
1284                }));
1285                self.current_captures = cc;
1286            }
1287            Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => {
1288                self.consume_exprs(exprs.iter().copied())
1289            }
1290            &Expr::Assignment { target, value } => {
1291                self.walk_expr(value);
1292                let resolver_guard =
1293                    self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr);
1294                match self.place_of_expr(value) {
1295                    Some(rhs_place) => {
1296                        self.inside_assignment = true;
1297                        self.consume_with_pat(rhs_place, target);
1298                        self.inside_assignment = false;
1299                    }
1300                    None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] {
1301                        Pat::Path(path) => self.mutate_path_pat(path, pat),
1302                        &Pat::Expr(expr) => {
1303                            let place = self.place_of_expr(expr);
1304                            self.mutate_expr(expr, place);
1305                        }
1306                        _ => {}
1307                    }),
1308                }
1309                self.resolver.reset_to_guard(resolver_guard);
1310            }
1311
1312            Expr::Missing
1313            | Expr::Continue { .. }
1314            | Expr::Path(_)
1315            | Expr::Literal(_)
1316            | Expr::Const(_)
1317            | Expr::Underscore => (),
1318        }
1319    }
1320
1321    fn walk_pat(&mut self, result: &mut Option<CaptureKind>, pat: PatId) {
1322        let mut update_result = |ck: CaptureKind| match result {
1323            Some(r) => {
1324                *r = cmp::max(*r, ck);
1325            }
1326            None => *result = Some(ck),
1327        };
1328
1329        self.walk_pat_inner(
1330            pat,
1331            &mut update_result,
1332            BorrowKind::Mut { kind: MutBorrowKind::Default },
1333        );
1334    }
1335
1336    fn walk_pat_inner(
1337        &mut self,
1338        p: PatId,
1339        update_result: &mut impl FnMut(CaptureKind),
1340        mut for_mut: BorrowKind,
1341    ) {
1342        match &self.body[p] {
1343            Pat::Ref { .. }
1344            | Pat::Box { .. }
1345            | Pat::Missing
1346            | Pat::Wild
1347            | Pat::Tuple { .. }
1348            | Pat::Expr(_)
1349            | Pat::Or(_) => (),
1350            Pat::TupleStruct { .. } | Pat::Record { .. } => {
1351                if let Some(variant) = self.result.variant_resolution_for_pat(p) {
1352                    let adt = variant.adt_id(self.db);
1353                    let is_multivariant = match adt {
1354                        hir_def::AdtId::EnumId(e) => e.enum_variants(self.db).variants.len() != 1,
1355                        _ => false,
1356                    };
1357                    if is_multivariant {
1358                        update_result(CaptureKind::ByRef(BorrowKind::Shared));
1359                    }
1360                }
1361            }
1362            Pat::Slice { .. }
1363            | Pat::ConstBlock(_)
1364            | Pat::Path(_)
1365            | Pat::Lit(_)
1366            | Pat::Range { .. } => {
1367                update_result(CaptureKind::ByRef(BorrowKind::Shared));
1368            }
1369            Pat::Bind { id, .. } => match self.result.binding_modes[p] {
1370                crate::BindingMode::Move => {
1371                    if self.is_ty_copy(self.result.type_of_binding[*id].clone()) {
1372                        update_result(CaptureKind::ByRef(BorrowKind::Shared));
1373                    } else {
1374                        update_result(CaptureKind::ByValue);
1375                    }
1376                }
1377                crate::BindingMode::Ref(r) => match r {
1378                    Mutability::Mut => update_result(CaptureKind::ByRef(for_mut)),
1379                    Mutability::Not => update_result(CaptureKind::ByRef(BorrowKind::Shared)),
1380                },
1381            },
1382        }
1383        if self.result.pat_adjustments.get(&p).is_some_and(|it| !it.is_empty()) {
1384            for_mut = BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture };
1385        }
1386        self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut));
1387    }
1388
1389    fn expr_ty(&self, expr: ExprId) -> Ty {
1390        self.result[expr].clone()
1391    }
1392
1393    fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty {
1394        let mut ty = None;
1395        if let Some(it) = self.result.expr_adjustments.get(&e)
1396            && let Some(it) = it.last()
1397        {
1398            ty = Some(it.target.clone());
1399        }
1400        ty.unwrap_or_else(|| self.expr_ty(e))
1401    }
1402
1403    fn is_upvar(&self, place: &HirPlace) -> bool {
1404        if let Some(c) = self.current_closure {
1405            let InternedClosure(_, root) = self.db.lookup_intern_closure(c.into());
1406            return self.body.is_binding_upvar(place.local, root);
1407        }
1408        false
1409    }
1410
1411    fn is_ty_copy(&mut self, ty: Ty) -> bool {
1412        if let TyKind::Closure(id, _) = ty.kind(Interner) {
1413            // FIXME: We handle closure as a special case, since chalk consider every closure as copy. We
1414            // should probably let chalk know which closures are copy, but I don't know how doing it
1415            // without creating query cycles.
1416            return self.result.closure_info.get(id).map(|it| it.1 == FnTrait::Fn).unwrap_or(true);
1417        }
1418        self.table.resolve_completely(ty).is_copy(self.db, self.owner)
1419    }
1420
1421    fn select_from_expr(&mut self, expr: ExprId) {
1422        self.walk_expr(expr);
1423    }
1424
1425    fn restrict_precision_for_unsafe(&mut self) {
1426        // FIXME: Borrow checker problems without this.
1427        let mut current_captures = std::mem::take(&mut self.current_captures);
1428        for capture in &mut current_captures {
1429            let mut ty = self.table.resolve_completely(self.result[capture.place.local].clone());
1430            if ty.as_raw_ptr().is_some() || ty.is_union() {
1431                capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
1432                self.truncate_capture_spans(capture, 0);
1433                capture.place.projections.truncate(0);
1434                continue;
1435            }
1436            for (i, p) in capture.place.projections.iter().enumerate() {
1437                ty = p.projected_ty(
1438                    ty,
1439                    self.db,
1440                    |_, _, _| {
1441                        unreachable!("Closure field only happens in MIR");
1442                    },
1443                    self.owner.module(self.db).krate(),
1444                );
1445                if ty.as_raw_ptr().is_some() || ty.is_union() {
1446                    capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
1447                    self.truncate_capture_spans(capture, i + 1);
1448                    capture.place.projections.truncate(i + 1);
1449                    break;
1450                }
1451            }
1452        }
1453        self.current_captures = current_captures;
1454    }
1455
1456    fn adjust_for_move_closure(&mut self) {
1457        // FIXME: Borrow checker won't allow without this.
1458        let mut current_captures = std::mem::take(&mut self.current_captures);
1459        for capture in &mut current_captures {
1460            if let Some(first_deref) =
1461                capture.place.projections.iter().position(|proj| *proj == ProjectionElem::Deref)
1462            {
1463                self.truncate_capture_spans(capture, first_deref);
1464                capture.place.projections.truncate(first_deref);
1465            }
1466            capture.kind = CaptureKind::ByValue;
1467        }
1468        self.current_captures = current_captures;
1469    }
1470
1471    fn minimize_captures(&mut self) {
1472        self.current_captures.sort_unstable_by_key(|it| it.place.projections.len());
1473        let mut hash_map = FxHashMap::<HirPlace, usize>::default();
1474        let result = mem::take(&mut self.current_captures);
1475        for mut item in result {
1476            let mut lookup_place = HirPlace { local: item.place.local, projections: vec![] };
1477            let mut it = item.place.projections.iter();
1478            let prev_index = loop {
1479                if let Some(k) = hash_map.get(&lookup_place) {
1480                    break Some(*k);
1481                }
1482                match it.next() {
1483                    Some(it) => {
1484                        lookup_place.projections.push(it.clone());
1485                    }
1486                    None => break None,
1487                }
1488            };
1489            match prev_index {
1490                Some(p) => {
1491                    let prev_projections_len = self.current_captures[p].place.projections.len();
1492                    self.truncate_capture_spans(&mut item, prev_projections_len);
1493                    self.current_captures[p].span_stacks.extend(item.span_stacks);
1494                    let len = self.current_captures[p].place.projections.len();
1495                    let kind_after_truncate =
1496                        item.place.capture_kind_of_truncated_place(item.kind, len);
1497                    self.current_captures[p].kind =
1498                        cmp::max(kind_after_truncate, self.current_captures[p].kind);
1499                }
1500                None => {
1501                    hash_map.insert(item.place.clone(), self.current_captures.len());
1502                    self.current_captures.push(item);
1503                }
1504            }
1505        }
1506    }
1507
1508    fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) {
1509        let adjustments_count =
1510            self.result.pat_adjustments.get(&tgt_pat).map(|it| it.len()).unwrap_or_default();
1511        place.projections.extend((0..adjustments_count).map(|_| ProjectionElem::Deref));
1512        self.current_capture_span_stack
1513            .extend((0..adjustments_count).map(|_| MirSpan::PatId(tgt_pat)));
1514        'reset_span_stack: {
1515            match &self.body[tgt_pat] {
1516                Pat::Missing | Pat::Wild => (),
1517                Pat::Tuple { args, ellipsis } => {
1518                    let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
1519                    let field_count = match self.result[tgt_pat].kind(Interner) {
1520                        TyKind::Tuple(_, s) => s.len(Interner),
1521                        _ => break 'reset_span_stack,
1522                    };
1523                    let fields = 0..field_count;
1524                    let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev()));
1525                    for (&arg, i) in it {
1526                        let mut p = place.clone();
1527                        self.current_capture_span_stack.push(MirSpan::PatId(arg));
1528                        p.projections.push(ProjectionElem::Field(Either::Right(TupleFieldId {
1529                            tuple: TupleId(!0), // dummy this, as its unused anyways
1530                            index: i as u32,
1531                        })));
1532                        self.consume_with_pat(p, arg);
1533                        self.current_capture_span_stack.pop();
1534                    }
1535                }
1536                Pat::Or(pats) => {
1537                    for pat in pats.iter() {
1538                        self.consume_with_pat(place.clone(), *pat);
1539                    }
1540                }
1541                Pat::Record { args, .. } => {
1542                    let Some(variant) = self.result.variant_resolution_for_pat(tgt_pat) else {
1543                        break 'reset_span_stack;
1544                    };
1545                    match variant {
1546                        VariantId::EnumVariantId(_) | VariantId::UnionId(_) => {
1547                            self.consume_place(place)
1548                        }
1549                        VariantId::StructId(s) => {
1550                            let vd = s.fields(self.db);
1551                            for field_pat in args.iter() {
1552                                let arg = field_pat.pat;
1553                                let Some(local_id) = vd.field(&field_pat.name) else {
1554                                    continue;
1555                                };
1556                                let mut p = place.clone();
1557                                self.current_capture_span_stack.push(MirSpan::PatId(arg));
1558                                p.projections.push(ProjectionElem::Field(Either::Left(FieldId {
1559                                    parent: variant,
1560                                    local_id,
1561                                })));
1562                                self.consume_with_pat(p, arg);
1563                                self.current_capture_span_stack.pop();
1564                            }
1565                        }
1566                    }
1567                }
1568                Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => {
1569                    self.consume_place(place)
1570                }
1571                Pat::Path(path) => {
1572                    if self.inside_assignment {
1573                        self.mutate_path_pat(path, tgt_pat);
1574                    }
1575                    self.consume_place(place);
1576                }
1577                &Pat::Bind { id, subpat: _ } => {
1578                    let mode = self.result.binding_modes[tgt_pat];
1579                    let capture_kind = match mode {
1580                        BindingMode::Move => {
1581                            self.consume_place(place);
1582                            break 'reset_span_stack;
1583                        }
1584                        BindingMode::Ref(Mutability::Not) => BorrowKind::Shared,
1585                        BindingMode::Ref(Mutability::Mut) => {
1586                            BorrowKind::Mut { kind: MutBorrowKind::Default }
1587                        }
1588                    };
1589                    self.current_capture_span_stack.push(MirSpan::BindingId(id));
1590                    self.add_capture(place, CaptureKind::ByRef(capture_kind));
1591                    self.current_capture_span_stack.pop();
1592                }
1593                Pat::TupleStruct { path: _, args, ellipsis } => {
1594                    let Some(variant) = self.result.variant_resolution_for_pat(tgt_pat) else {
1595                        break 'reset_span_stack;
1596                    };
1597                    match variant {
1598                        VariantId::EnumVariantId(_) | VariantId::UnionId(_) => {
1599                            self.consume_place(place)
1600                        }
1601                        VariantId::StructId(s) => {
1602                            let vd = s.fields(self.db);
1603                            let (al, ar) =
1604                                args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
1605                            let fields = vd.fields().iter();
1606                            let it = al
1607                                .iter()
1608                                .zip(fields.clone())
1609                                .chain(ar.iter().rev().zip(fields.rev()));
1610                            for (&arg, (i, _)) in it {
1611                                let mut p = place.clone();
1612                                self.current_capture_span_stack.push(MirSpan::PatId(arg));
1613                                p.projections.push(ProjectionElem::Field(Either::Left(FieldId {
1614                                    parent: variant,
1615                                    local_id: i,
1616                                })));
1617                                self.consume_with_pat(p, arg);
1618                                self.current_capture_span_stack.pop();
1619                            }
1620                        }
1621                    }
1622                }
1623                Pat::Ref { pat, mutability: _ } => {
1624                    self.current_capture_span_stack.push(MirSpan::PatId(tgt_pat));
1625                    place.projections.push(ProjectionElem::Deref);
1626                    self.consume_with_pat(place, *pat);
1627                    self.current_capture_span_stack.pop();
1628                }
1629                Pat::Box { .. } => (), // not supported
1630                &Pat::Expr(expr) => {
1631                    self.consume_place(place);
1632                    let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack);
1633                    let old_inside_assignment = mem::replace(&mut self.inside_assignment, false);
1634                    let lhs_place = self.place_of_expr(expr);
1635                    self.mutate_expr(expr, lhs_place);
1636                    self.inside_assignment = old_inside_assignment;
1637                    self.current_capture_span_stack = pat_capture_span_stack;
1638                }
1639            }
1640        }
1641        self.current_capture_span_stack
1642            .truncate(self.current_capture_span_stack.len() - adjustments_count);
1643    }
1644
1645    fn consume_exprs(&mut self, exprs: impl Iterator<Item = ExprId>) {
1646        for expr in exprs {
1647            self.consume_expr(expr);
1648        }
1649    }
1650
1651    fn closure_kind(&self) -> FnTrait {
1652        let mut r = FnTrait::Fn;
1653        for it in &self.current_captures {
1654            r = cmp::min(
1655                r,
1656                match &it.kind {
1657                    CaptureKind::ByRef(BorrowKind::Mut { .. }) => FnTrait::FnMut,
1658                    CaptureKind::ByRef(BorrowKind::Shallow | BorrowKind::Shared) => FnTrait::Fn,
1659                    CaptureKind::ByValue => FnTrait::FnOnce,
1660                },
1661            )
1662        }
1663        r
1664    }
1665
1666    fn analyze_closure(&mut self, closure: ClosureId) -> FnTrait {
1667        let InternedClosure(_, root) = self.db.lookup_intern_closure(closure.into());
1668        self.current_closure = Some(closure);
1669        let Expr::Closure { body, capture_by, .. } = &self.body[root] else {
1670            unreachable!("Closure expression id is always closure");
1671        };
1672        self.consume_expr(*body);
1673        for item in &self.current_captures {
1674            if matches!(
1675                item.kind,
1676                CaptureKind::ByRef(BorrowKind::Mut {
1677                    kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow
1678                })
1679            ) && !item.place.projections.contains(&ProjectionElem::Deref)
1680            {
1681                // FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in
1682                // MIR. I didn't do that due duplicate diagnostics.
1683                self.result.mutated_bindings_in_closure.insert(item.place.local);
1684            }
1685        }
1686        self.restrict_precision_for_unsafe();
1687        // `closure_kind` should be done before adjust_for_move_closure
1688        // If there exists pre-deduced kind of a closure, use it instead of one determined by capture, as rustc does.
1689        // rustc also does diagnostics here if the latter is not a subtype of the former.
1690        let closure_kind = self
1691            .result
1692            .closure_info
1693            .get(&closure)
1694            .map_or_else(|| self.closure_kind(), |info| info.1);
1695        match capture_by {
1696            CaptureBy::Value => self.adjust_for_move_closure(),
1697            CaptureBy::Ref => (),
1698        }
1699        self.minimize_captures();
1700        self.strip_captures_ref_span();
1701        let result = mem::take(&mut self.current_captures);
1702        let captures = result.into_iter().map(|it| it.with_ty(self)).collect::<Vec<_>>();
1703        self.result.closure_info.insert(closure, (captures, closure_kind));
1704        closure_kind
1705    }
1706
1707    fn strip_captures_ref_span(&mut self) {
1708        // FIXME: Borrow checker won't allow without this.
1709        let mut captures = std::mem::take(&mut self.current_captures);
1710        for capture in &mut captures {
1711            if matches!(capture.kind, CaptureKind::ByValue) {
1712                for span_stack in &mut capture.span_stacks {
1713                    if span_stack[span_stack.len() - 1].is_ref_span(self.body) {
1714                        span_stack.truncate(span_stack.len() - 1);
1715                    }
1716                }
1717            }
1718        }
1719        self.current_captures = captures;
1720    }
1721
1722    pub(crate) fn infer_closures(&mut self) {
1723        let deferred_closures = self.sort_closures();
1724        for (closure, exprs) in deferred_closures.into_iter().rev() {
1725            self.current_captures = vec![];
1726            let kind = self.analyze_closure(closure);
1727
1728            for (derefed_callee, callee_ty, params, expr) in exprs {
1729                if let &Expr::Call { callee, .. } = &self.body[expr] {
1730                    let mut adjustments =
1731                        self.result.expr_adjustments.remove(&callee).unwrap_or_default().into_vec();
1732                    self.write_fn_trait_method_resolution(
1733                        kind,
1734                        &derefed_callee,
1735                        &mut adjustments,
1736                        &callee_ty,
1737                        &params,
1738                        expr,
1739                    );
1740                    self.result.expr_adjustments.insert(callee, adjustments.into_boxed_slice());
1741                }
1742            }
1743        }
1744    }
1745
1746    /// We want to analyze some closures before others, to have a correct analysis:
1747    /// * We should analyze nested closures before the parent, since the parent should capture some of
1748    ///   the things that its children captures.
1749    /// * If a closure calls another closure, we need to analyze the callee, to find out how we should
1750    ///   capture it (e.g. by move for FnOnce)
1751    ///
1752    /// These dependencies are collected in the main inference. We do a topological sort in this function. It
1753    /// will consume the `deferred_closures` field and return its content in a sorted vector.
1754    fn sort_closures(&mut self) -> Vec<(ClosureId, Vec<(Ty, Ty, Vec<Ty>, ExprId)>)> {
1755        let mut deferred_closures = mem::take(&mut self.deferred_closures);
1756        let mut dependents_count: FxHashMap<ClosureId, usize> =
1757            deferred_closures.keys().map(|it| (*it, 0)).collect();
1758        for deps in self.closure_dependencies.values() {
1759            for dep in deps {
1760                *dependents_count.entry(*dep).or_default() += 1;
1761            }
1762        }
1763        let mut queue: Vec<_> =
1764            deferred_closures.keys().copied().filter(|it| dependents_count[it] == 0).collect();
1765        let mut result = vec![];
1766        while let Some(it) = queue.pop() {
1767            if let Some(d) = deferred_closures.remove(&it) {
1768                result.push((it, d));
1769            }
1770            for dep in self.closure_dependencies.get(&it).into_iter().flat_map(|it| it.iter()) {
1771                let cnt = dependents_count.get_mut(dep).unwrap();
1772                *cnt -= 1;
1773                if *cnt == 0 {
1774                    queue.push(*dep);
1775                }
1776            }
1777        }
1778        assert!(deferred_closures.is_empty(), "we should have analyzed all closures");
1779        result
1780    }
1781
1782    pub(super) fn add_current_closure_dependency(&mut self, dep: ClosureId) {
1783        if let Some(c) = self.current_closure
1784            && !dep_creates_cycle(&self.closure_dependencies, &mut FxHashSet::default(), c, dep)
1785        {
1786            self.closure_dependencies.entry(c).or_default().push(dep);
1787        }
1788
1789        fn dep_creates_cycle(
1790            closure_dependencies: &FxHashMap<ClosureId, Vec<ClosureId>>,
1791            visited: &mut FxHashSet<ClosureId>,
1792            from: ClosureId,
1793            to: ClosureId,
1794        ) -> bool {
1795            if !visited.insert(from) {
1796                return false;
1797            }
1798
1799            if from == to {
1800                return true;
1801            }
1802
1803            if let Some(deps) = closure_dependencies.get(&to) {
1804                for dep in deps {
1805                    if dep_creates_cycle(closure_dependencies, visited, from, *dep) {
1806                        return true;
1807                    }
1808                }
1809            }
1810
1811            false
1812        }
1813    }
1814}
1815
1816/// Call this only when the last span in the stack isn't a split.
1817fn apply_adjusts_to_place(
1818    current_capture_span_stack: &mut Vec<MirSpan>,
1819    mut r: HirPlace,
1820    adjustments: &[Adjustment],
1821) -> Option<HirPlace> {
1822    let span = *current_capture_span_stack.last().expect("empty capture span stack");
1823    for adj in adjustments {
1824        match &adj.kind {
1825            Adjust::Deref(None) => {
1826                current_capture_span_stack.push(span);
1827                r.projections.push(ProjectionElem::Deref);
1828            }
1829            _ => return None,
1830        }
1831    }
1832    Some(r)
1833}