From 22f853c620d970c6f80c8c206614a3bf766d028f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Tue, 14 Feb 2023 16:11:15 +0100 Subject: [PATCH 1/3] Avoid looping past bounds of args There might be more type params than args to a method call, which leads to an index out of bounds panic. --- compiler/rustc_hir_typeck/src/demand.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index ae00042eae73d..16d3115c233b0 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -323,13 +323,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut param_found = FxHashMap::default(); if self.can_eq(self.param_env, ty, found).is_ok() { // 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 sig.inputs().skip_binder().iter().skip(1).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( From 08cc628e7334b7f200b09f5f2c77700231103fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Wed, 15 Feb 2023 15:51:48 +0100 Subject: [PATCH 2/3] Add point-at-inference ui test for wrong arity case --- .../type/type-check/point-at-inference-4.rs | 23 +++++++++++ .../type-check/point-at-inference-4.stderr | 38 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tests/ui/type/type-check/point-at-inference-4.rs create mode 100644 tests/ui/type/type-check/point-at-inference-4.stderr 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..647c7d622fa56 --- /dev/null +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -0,0 +1,23 @@ +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 + //~| NOTE this is of type `i32`, which causes `s` to be inferred as `S` + //~| HELP change the type of the numeric literal from `i32` to `u32` + 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..62e798e56f7cd --- /dev/null +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -0,0 +1,38 @@ +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:18:24 + | +LL | s.infer(0i32); + | ---- this is of type `i32`, which causes `s` to be inferred as `S` +... +LL | let t: S = s; + | --------- ^ expected `S`, found `S` + | | + | expected due to this + | + = note: expected struct `S` + found struct `S` +help: change the type of the numeric literal from `i32` to `u32` + | +LL | s.infer(0u32); + | ~~~ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`. From e159c1e0ec3c70c1876790984e769f1e20b19a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Wed, 15 Feb 2023 18:45:20 +0100 Subject: [PATCH 3/3] Skip method calls with arity mismatch --- compiler/rustc_hir_typeck/src/demand.rs | 8 +++++++- tests/ui/type/type-check/point-at-inference-4.rs | 2 -- tests/ui/type/type-check/point-at-inference-4.stderr | 9 +-------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 16d3115c233b0..79b3c0590b6bf 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,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut param_found = FxHashMap::default(); if self.can_eq(self.param_env, ty, found).is_ok() { // We only point at the first place where the found type was inferred. - for (param_ty, arg) in sig.inputs().skip_binder().iter().skip(1).zip(args) { + 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 diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs index 647c7d622fa56..7903e9e83cfb3 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -13,8 +13,6 @@ fn main() { //~^ ERROR this method takes 2 arguments but 1 argument was supplied //~| NOTE an argument is missing //~| HELP provide the argument - //~| NOTE this is of type `i32`, which causes `s` to be inferred as `S` - //~| HELP change the type of the numeric literal from `i32` to `u32` let t: S = s; //~^ ERROR mismatched types //~| NOTE expected `S`, found `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 index 62e798e56f7cd..fac9701e4a11e 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -15,11 +15,8 @@ LL | s.infer(0i32, /* b */); | ~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/point-at-inference-4.rs:18:24 + --> $DIR/point-at-inference-4.rs:16:24 | -LL | s.infer(0i32); - | ---- this is of type `i32`, which causes `s` to be inferred as `S` -... LL | let t: S = s; | --------- ^ expected `S`, found `S` | | @@ -27,10 +24,6 @@ LL | let t: S = s; | = note: expected struct `S` found struct `S` -help: change the type of the numeric literal from `i32` to `u32` - | -LL | s.infer(0u32); - | ~~~ error: aborting due to 2 previous errors