about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-03-03 00:44:22 +0000
committerMichael Goulet <michael@errs.io>2023-04-12 23:20:12 +0000
commit5a71029dd3b54046fbd6144de20e320db539820f (patch)
treefa711dff5802b38df8cd818d7b00ab49a377542e /compiler
parent29aee6a125ac65a01932cb0ece5485e7cf8cfe87 (diff)
downloadrust-5a71029dd3b54046fbd6144de20e320db539820f.tar.gz
rust-5a71029dd3b54046fbd6144de20e320db539820f.zip
Properly note source of arg mismatch
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs57
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs13
2 files changed, 64 insertions, 6 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index f219068b4e8..9ffee567023 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -62,7 +62,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
 
         if !suggested {
-            self.note_source_of_type_mismatch_constraint(err, expr, expected);
+            self.note_source_of_type_mismatch_constraint(
+                err,
+                expr,
+                TypeMismatchSource::Ty(expected),
+            );
         }
     }
 
@@ -222,7 +226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
-        expected_ty: Ty<'tcx>,
+        source: TypeMismatchSource<'tcx>,
     ) -> bool {
         let hir = self.tcx.hir();
 
@@ -295,6 +299,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             },
         };
 
+        let expected_ty = match source {
+            TypeMismatchSource::Ty(expected_ty) => expected_ty,
+            TypeMismatchSource::Arg(call_expr, idx) => {
+                let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else {
+                    return false;
+                };
+                let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
+                    return false;
+                };
+                let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| {
+                    let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
+                    let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
+                    let method = self
+                        .lookup_method(
+                            possible_rcvr_ty,
+                            segment,
+                            DUMMY_SP,
+                            call_expr,
+                            binding,
+                            args,
+                        )
+                        .ok()?;
+                    let _ = self
+                        .at(&ObligationCause::dummy(), self.param_env)
+                        .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty)
+                        .ok()?;
+                    self.select_obligations_where_possible(|errs| {
+                        // Yeet the errors, we're already reporting errors.
+                        errs.clear();
+                    });
+                    Some(self.resolve_vars_if_possible(possible_rcvr_ty))
+                });
+                if let Some(rcvr_ty) = possible_rcvr_ty {
+                    rcvr_ty
+                } else {
+                    return false;
+                }
+            }
+        };
+
         if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
             return false;
         }
@@ -360,7 +404,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             "... which constrains `{ident}` to have type `{next_use_ty}`"
                         ),
                     );
-                    if let Ok(ideal_method_sig) = ideal_method_sig {
+                    if matches!(source, TypeMismatchSource::Ty(_))
+                        && let Ok(ideal_method_sig) = ideal_method_sig
+                    {
                         self.emit_type_mismatch_suggestions(
                             err,
                             arg_expr,
@@ -2044,3 +2090,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 }
+
+pub enum TypeMismatchSource<'tcx> {
+    Ty(Ty<'tcx>),
+    Arg(&'tcx hir::Expr<'tcx>, usize),
+}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index d98e0d9096f..9ecb78e2dda 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -472,7 +472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err_code: &str,
         fn_def_id: Option<DefId>,
         call_span: Span,
-        call_expr: &hir::Expr<'tcx>,
+        call_expr: &'tcx hir::Expr<'tcx>,
     ) {
         // Next, let's construct the error
         let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
@@ -808,8 +808,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 format!("arguments to this {} are incorrect", call_name),
             );
 
-            // TODO: We would like to point out when the rcvr was constrained
-            // such that the arg mismatch occurs.
+            if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
+                && provided_idx.as_usize() == expected_idx.as_usize()
+            {
+                self.note_source_of_type_mismatch_constraint(
+                    &mut err,
+                    rcvr,
+                    crate::demand::TypeMismatchSource::Arg(call_expr, provided_idx.as_usize()),
+                );
+            }
 
             // Call out where the function is defined
             self.label_fn_like(