1use 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 let resume_ty = match sig_tys.first() {
83 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 self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected, expected_kind);
120
121 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 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 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 let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty, CoerceNever::Yes);
173
174 if matches!(closure_ty.kind(Interner), TyKind::Coroutine(..)) {
176 return;
177 }
178
179 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 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 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 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 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 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 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 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 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 for arg_type in arg_types.iter() {
469 let arg_ty = match arg_type {
470 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 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 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 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#[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 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 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 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 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 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 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 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 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 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(); }
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 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 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 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 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 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), 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 { .. } => (), &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 self.result.mutated_bindings_in_closure.insert(item.place.local);
1684 }
1685 }
1686 self.restrict_precision_for_unsafe();
1687 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 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 ¶ms,
1738 expr,
1739 );
1740 self.result.expr_adjustments.insert(callee, adjustments.into_boxed_slice());
1741 }
1742 }
1743 }
1744 }
1745
1746 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
1816fn 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}