diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 149c7dbef22f5..76e87a9e56629 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -298,6 +298,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // call's arguments and we can provide a more explicit span. let sig = self.tcx.fn_sig(def_id).subst_identity(); let def_self_ty = sig.input(0).skip_binder(); + let param_tys = sig.inputs().skip_binder().iter().skip(1); + // If there's an arity mismatch, pointing out the call as the source of an inference + // can be misleading, so we skip it. + if param_tys.len() != args.len() { + continue; + } let rcvr_ty = self.node_ty(rcvr.hir_id); // Get the evaluated type *after* calling the method call, so that the influence // of the arguments can be reflected in the receiver type. The receiver @@ -323,13 +329,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut param_found = FxHashMap::default(); if self.can_eq(self.param_env, ty, found) { // We only point at the first place where the found type was inferred. - for (i, param_ty) in sig.inputs().skip_binder().iter().skip(1).enumerate() { + for (param_ty, arg) in param_tys.zip(args) { if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() { // We found an argument that references a type parameter in `Self`, // so we assume that this is the argument that caused the found // type, which we know already because of `can_eq` above was first // inferred in this method call. - let arg = &args[i]; let arg_ty = self.node_ty(arg.hir_id); if !arg.span.overlaps(mismatch_span) { err.span_label( diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs new file mode 100644 index 0000000000000..7903e9e83cfb3 --- /dev/null +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -0,0 +1,21 @@ +struct S(Option<(A, B)>); + +impl S { + fn infer(&self, a: A, b: B) {} + //~^ NOTE associated function defined here + //~| NOTE + //~| NOTE +} + +fn main() { + let s = S(None); + s.infer(0i32); + //~^ ERROR this method takes 2 arguments but 1 argument was supplied + //~| NOTE an argument is missing + //~| HELP provide the argument + let t: S = s; + //~^ ERROR mismatched types + //~| NOTE expected `S`, found `S` + //~| NOTE expected due to this + //~| NOTE expected struct `S` +} diff --git a/tests/ui/type/type-check/point-at-inference-4.stderr b/tests/ui/type/type-check/point-at-inference-4.stderr new file mode 100644 index 0000000000000..fac9701e4a11e --- /dev/null +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -0,0 +1,31 @@ +error[E0061]: this method takes 2 arguments but 1 argument was supplied + --> $DIR/point-at-inference-4.rs:12:7 + | +LL | s.infer(0i32); + | ^^^^^------ an argument is missing + | +note: associated function defined here + --> $DIR/point-at-inference-4.rs:4:8 + | +LL | fn infer(&self, a: A, b: B) {} + | ^^^^^ ---- ---- +help: provide the argument + | +LL | s.infer(0i32, /* b */); + | ~~~~~~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/point-at-inference-4.rs:16:24 + | +LL | let t: S = s; + | --------- ^ expected `S`, found `S` + | | + | expected due to this + | + = note: expected struct `S` + found struct `S` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`.