about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2025-08-07 21:09:42 +0000
committerEsteban Küber <esteban@kuber.com.ar>2025-08-10 19:22:49 +0000
commit2484e189bfbc3decc2aa8480ce249dd84f6d2f9c (patch)
tree3c1f98ed5903f07a6bdd09285e74be89a1534896 /compiler
parent1aa5668d20d53976860d141a66aa727e425e1079 (diff)
Add support for method calls
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs74
1 files changed, 41 insertions, 33 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index b24cb012d2b..5adbaca7e11 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -9,6 +9,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
+use rustc_span::def_id::DefId;
 use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -507,38 +508,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 );
 
                 let closure_span = tcx.def_span(def_id);
-                let mut clause_span = DUMMY_SP;
-                let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
-                if let Some(closure_def_id) = def_id.as_local()
-                    && let hir::Node::Expr(expr) = tcx.hir_node_by_def_id(closure_def_id)
-                    && let hir::Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id)
-                    && let hir::ExprKind::Call(callee, _) = parent.kind
-                    && let Some(ty) = typck_result.node_type_opt(callee.hir_id)
-                    && let ty::FnDef(fn_def_id, args) = ty.kind()
-                    && let predicates = tcx.predicates_of(fn_def_id).instantiate(tcx, args)
-                    && let Some((_, span)) =
-                        predicates.predicates.iter().zip(predicates.spans.iter()).find(
-                            |(pred, _)| match pred.as_trait_clause() {
-                                Some(clause)
-                                    if let ty::Closure(clause_closure_def_id, _) =
-                                        clause.self_ty().skip_binder().kind()
-                                        && clause_closure_def_id == def_id
-                                        && (tcx.lang_items().fn_mut_trait()
-                                            == Some(clause.def_id())
-                                            || tcx.lang_items().fn_trait()
-                                                == Some(clause.def_id())) =>
-                                {
-                                    // Found `<TyOfCapturingClosure as FnMut>`
-                                    true
-                                }
-                                _ => false,
-                            },
-                        )
-                {
-                    // We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
-                    // could be changed to `FnOnce()` to avoid the move error.
-                    clause_span = *span;
-                }
 
                 self.cannot_move_out_of(span, &place_description)
                     .with_span_label(upvar_span, "captured outer variable")
@@ -547,7 +516,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         format!("captured by this `{closure_kind}` closure"),
                     )
                     .with_span_help(
-                        clause_span,
+                        self.get_closure_bound_clause_span(*def_id),
                         "`Fn` and `FnMut` closures require captured values to be able to be \
                          consumed multiple times, but an `FnOnce` consume them only once",
                     )
@@ -599,6 +568,45 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         err
     }
 
+    fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
+        let tcx = self.infcx.tcx;
+        let typeck_result = tcx.typeck(self.mir_def_id());
+        let Some(closure_def_id) = def_id.as_local() else { return DUMMY_SP };
+        let hir::Node::Expr(expr) = tcx.hir_node_by_def_id(closure_def_id) else { return DUMMY_SP };
+        let hir::Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id) else { return DUMMY_SP };
+        let predicates = match parent.kind {
+            hir::ExprKind::Call(callee, _) => {
+                let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
+                let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
+                tcx.predicates_of(fn_def_id).instantiate(tcx, args)
+            }
+            hir::ExprKind::MethodCall(..) => {
+                let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
+                    return DUMMY_SP;
+                };
+                let args = typeck_result.node_args(parent.hir_id);
+                tcx.predicates_of(method).instantiate(tcx, args)
+            }
+            _ => return DUMMY_SP,
+        };
+        for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
+            tracing::info!(?pred);
+            tracing::info!(?span);
+            if let Some(clause) = pred.as_trait_clause()
+                && let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
+                && *clause_closure_def_id == def_id
+                && (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
+                    || tcx.lang_items().fn_trait() == Some(clause.def_id()))
+            {
+                // Found `<TyOfCapturingClosure as FnMut>`
+                // We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
+                // could be changed to `FnOnce()` to avoid the move error.
+                return *span;
+            }
+        }
+        DUMMY_SP
+    }
+
     fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
         match error {
             GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {