From 50e5d03e16790400f0c5b6ce6d3a27f6a71c5298 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 14 Aug 2022 14:09:16 +0800 Subject: [PATCH 1/2] Avoid infinite loop in function arguments checking --- .../src/check/fn_ctxt/arg_matrix.rs | 21 +++-- .../ui/argument-suggestions/issue-100478.rs | 52 ++++++++++++ .../argument-suggestions/issue-100478.stderr | 81 +++++++++++++++++++ 3 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/argument-suggestions/issue-100478.rs create mode 100644 src/test/ui/argument-suggestions/issue-100478.stderr diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs index 7602f2550e8..90a2589d747 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs @@ -130,14 +130,17 @@ fn find_issue(&self) -> Option { let ai = &self.expected_indices; let ii = &self.provided_indices; + // Issue: 100478, when we end the iteration, + // `next_unmatched_idx` will point to the index of the first unmatched + let mut next_unmatched_idx = 0; for i in 0..cmp::max(ai.len(), ii.len()) { - // If we eliminate the last row, any left-over inputs are considered missing + // If we eliminate the last row, any left-over arguments are considered missing if i >= mat.len() { - return Some(Issue::Missing(i)); + return Some(Issue::Missing(next_unmatched_idx)); } - // If we eliminate the last column, any left-over arguments are extra + // If we eliminate the last column, any left-over inputs are extra if mat[i].len() == 0 { - return Some(Issue::Extra(i)); + return Some(Issue::Extra(next_unmatched_idx)); } // Make sure we don't pass the bounds of our matrix @@ -145,6 +148,7 @@ fn find_issue(&self) -> Option { let is_input = i < ii.len(); if is_arg && is_input && matches!(mat[i][i], Compatibility::Compatible) { // This is a satisfied input, so move along + next_unmatched_idx += 1; continue; } @@ -163,7 +167,7 @@ fn find_issue(&self) -> Option { if is_input { for j in 0..ai.len() { // If we find at least one argument that could satisfy this input - // this argument isn't useless + // this input isn't useless if matches!(mat[i][j], Compatibility::Compatible) { useless = false; break; @@ -309,7 +313,8 @@ pub(crate) fn find_errors( } while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() { - match self.find_issue() { + let res = self.find_issue(); + match res { Some(Issue::Invalid(idx)) => { let compatibility = self.compatibility_matrix[idx][idx].clone(); let input_idx = self.provided_indices[idx]; @@ -364,7 +369,9 @@ pub(crate) fn find_errors( None => { // We didn't find any issues, so we need to push the algorithm forward // First, eliminate any arguments that currently satisfy their inputs - for (inp, arg) in self.eliminate_satisfied() { + let eliminated = self.eliminate_satisfied(); + assert!(!eliminated.is_empty(), "didn't eliminated any indice in this round"); + for (inp, arg) in eliminated { matched_inputs[arg] = Some(inp); } } diff --git a/src/test/ui/argument-suggestions/issue-100478.rs b/src/test/ui/argument-suggestions/issue-100478.rs new file mode 100644 index 00000000000..6bef6ad1038 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-100478.rs @@ -0,0 +1,52 @@ +use std::sync::Arc; +macro_rules! GenT { + ($name:tt) => { + #[derive(Default, Debug)] + struct $name { + #[allow(unused)] + val: i32, + } + + impl $name { + #[allow(unused)] + fn new(val: i32) -> Self { + $name { val } + } + } + }; +} + +GenT!(T1); +GenT!(T2); +GenT!(T3); +GenT!(T4); +GenT!(T5); +GenT!(T6); +GenT!(T7); +GenT!(T8); + +#[allow(unused)] +fn foo(p1: T1, p2: Arc, p3: T3, p4: Arc, p5: T5, p6: T6, p7: T7, p8: Arc) {} +fn three_diff(_a: T1, _b: T2, _c: T3) {} +fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} + +fn main() { + three_diff(T2::new(0)); //~ ERROR this function takes + four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR 35:5: 35:17: arguments to this function are incorrect [E0308] + four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR 36:5: 36:17: arguments to this function are incorrect [E0308] + + let p1 = T1::new(0); + let p2 = Arc::new(T2::new(0)); + let p3 = T3::new(0); + let p4 = Arc::new(T4::new(1)); + let p5 = T5::new(0); + let p6 = T6::new(0); + let p7 = T7::new(0); + let p8 = Arc::default(); + + foo( + //~^ 47:5: 47:8: this function takes 8 arguments but 7 arguments were supplied [E0061] + p1, //p2, + p3, p4, p5, p6, p7, p8, + ); +} diff --git a/src/test/ui/argument-suggestions/issue-100478.stderr b/src/test/ui/argument-suggestions/issue-100478.stderr new file mode 100644 index 00000000000..a77889a9679 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-100478.stderr @@ -0,0 +1,81 @@ +error[E0061]: this function takes 3 arguments but 1 argument was supplied + --> $DIR/issue-100478.rs:34:5 + | +LL | three_diff(T2::new(0)); + | ^^^^^^^^^^------------ + | || + | |an argument of type `T1` is missing + | an argument of type `T3` is missing + | +note: function defined here + --> $DIR/issue-100478.rs:30:4 + | +LL | fn three_diff(_a: T1, _b: T2, _c: T3) {} + | ^^^^^^^^^^ ------ ------ ------ +help: provide the arguments + | +LL | three_diff(/* T1 */, T2::new(0), /* T3 */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-100478.rs:35:5 + | +LL | four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); + | ^^^^^^^^^^^^ ------------- ------------- ------------- ------------- expected `T4`, found `T2` + | | | | + | | | expected `T3`, found `T1` + | | expected `T2`, found `T4` + | expected `T1`, found `T3` + | +note: function defined here + --> $DIR/issue-100478.rs:31:4 + | +LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} + | ^^^^^^^^^^^^ ------ ------ ------ ------ +help: did you mean + | +LL | four_shuffle(T1::default(), T2::default(), T3::default(), T4::default()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-100478.rs:36:5 + | +LL | four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); + | ^^^^^^^^^^^^ ------------- ------------- ------------- expected struct `T4`, found struct `T3` + | | | + | | expected `T3`, found `T1` + | expected `T1`, found `T3` + | +note: function defined here + --> $DIR/issue-100478.rs:31:4 + | +LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} + | ^^^^^^^^^^^^ ------ ------ ------ ------ +help: swap these arguments + | +LL | four_shuffle(T1::default(), T2::default(), T3::default(), /* T4 */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0061]: this function takes 8 arguments but 7 arguments were supplied + --> $DIR/issue-100478.rs:47:5 + | +LL | foo( + | ^^^ +... +LL | p3, p4, p5, p6, p7, p8, + | -- an argument of type `Arc` is missing + | +note: function defined here + --> $DIR/issue-100478.rs:29:4 + | +LL | fn foo(p1: T1, p2: Arc, p3: T3, p4: Arc, p5: T5, p6: T6, p7: T7, p8: Arc) {} + | ^^^ ------ ----------- ------ ----------- ------ ------ ------ ----------- +help: provide the argument + | +LL | foo(p1, /* Arc */, p3, p4, p5, p6, p7, p8); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`. From 7e7dfb83dc1fe63d1ce14101339f5eee5b76159d Mon Sep 17 00:00:00 2001 From: chenyukang Date: Tue, 30 Aug 2022 10:03:02 +0800 Subject: [PATCH 2/2] fix #101097, avoid infinite loop in fn arguments checking --- .../src/check/fn_ctxt/arg_matrix.rs | 4 +- .../argument-suggestions/issue-100478.stderr | 8 +- .../ui/argument-suggestions/issue-101097.rs | 21 +++ .../argument-suggestions/issue-101097.stderr | 160 ++++++++++++++++++ 4 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/argument-suggestions/issue-101097.rs create mode 100644 src/test/ui/argument-suggestions/issue-101097.stderr diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs index 90a2589d747..fc83994caf5 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs @@ -236,8 +236,8 @@ fn find_issue(&self) -> Option { if matches!(c, Compatibility::Compatible) { Some(i) } else { None } }) .collect(); - if compat.len() != 1 { - // this could go into multiple slots, don't bother exploring both + if compat.len() < 1 { + // try to find a cycle even when this could go into multiple slots, see #101097 is_cycle = false; break; } diff --git a/src/test/ui/argument-suggestions/issue-100478.stderr b/src/test/ui/argument-suggestions/issue-100478.stderr index a77889a9679..df02a312cf1 100644 --- a/src/test/ui/argument-suggestions/issue-100478.stderr +++ b/src/test/ui/argument-suggestions/issue-100478.stderr @@ -15,7 +15,7 @@ LL | fn three_diff(_a: T1, _b: T2, _c: T3) {} help: provide the arguments | LL | three_diff(/* T1 */, T2::new(0), /* T3 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/issue-100478.rs:35:5 @@ -35,7 +35,7 @@ LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} help: did you mean | LL | four_shuffle(T1::default(), T2::default(), T3::default(), T4::default()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/issue-100478.rs:36:5 @@ -54,7 +54,7 @@ LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} help: swap these arguments | LL | four_shuffle(T1::default(), T2::default(), T3::default(), /* T4 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 8 arguments but 7 arguments were supplied --> $DIR/issue-100478.rs:47:5 @@ -73,7 +73,7 @@ LL | fn foo(p1: T1, p2: Arc, p3: T3, p4: Arc, p5: T5, p6: T6, p7: T7, p8 help: provide the argument | LL | foo(p1, /* Arc */, p3, p4, p5, p6, p7, p8); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors diff --git a/src/test/ui/argument-suggestions/issue-101097.rs b/src/test/ui/argument-suggestions/issue-101097.rs new file mode 100644 index 00000000000..7994d3cd995 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-101097.rs @@ -0,0 +1,21 @@ +struct A; +struct B; +struct C; +struct D; + +fn f( + a1: A, + a2: A, + b1: B, + b2: B, + c1: C, + c2: C, +) {} + +fn main() { + f(C, A, A, A, B, B, C); //~ ERROR this function takes 6 arguments but 7 arguments were supplied [E0061] + f(C, C, A, A, B, B); //~ ERROR arguments to this function are incorrect [E0308] + f(A, A, D, D, B, B); //~ arguments to this function are incorrect [E0308] + f(C, C, B, B, A, A); //~ arguments to this function are incorrect [E0308] + f(C, C, A, B, A, A); //~ arguments to this function are incorrect [E0308] +} diff --git a/src/test/ui/argument-suggestions/issue-101097.stderr b/src/test/ui/argument-suggestions/issue-101097.stderr new file mode 100644 index 00000000000..096f8c226f2 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-101097.stderr @@ -0,0 +1,160 @@ +error[E0061]: this function takes 6 arguments but 7 arguments were supplied + --> $DIR/issue-101097.rs:16:5 + | +LL | f(C, A, A, A, B, B, C); + | ^ - - - - expected `C`, found `B` + | | | | + | | | argument of type `A` unexpected + | | expected `B`, found `A` + | expected `A`, found `C` + | +note: function defined here + --> $DIR/issue-101097.rs:6:4 + | +LL | fn f( + | ^ +LL | a1: A, + | ----- +LL | a2: A, + | ----- +LL | b1: B, + | ----- +LL | b2: B, + | ----- +LL | c1: C, + | ----- +LL | c2: C, + | ----- +help: did you mean + | +LL | f(A, A, B, B, C, C); + | ~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-101097.rs:17:5 + | +LL | f(C, C, A, A, B, B); + | ^ + | +note: function defined here + --> $DIR/issue-101097.rs:6:4 + | +LL | fn f( + | ^ +LL | a1: A, + | ----- +LL | a2: A, + | ----- +LL | b1: B, + | ----- +LL | b2: B, + | ----- +LL | c1: C, + | ----- +LL | c2: C, + | ----- +help: did you mean + | +LL | f(A, A, B, B, C, C); + | ~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-101097.rs:18:5 + | +LL | f(A, A, D, D, B, B); + | ^ - - ---- two arguments of type `C` and `C` are missing + | | | + | | argument of type `D` unexpected + | argument of type `D` unexpected + | +note: function defined here + --> $DIR/issue-101097.rs:6:4 + | +LL | fn f( + | ^ +LL | a1: A, + | ----- +LL | a2: A, + | ----- +LL | b1: B, + | ----- +LL | b2: B, + | ----- +LL | c1: C, + | ----- +LL | c2: C, + | ----- +help: did you mean + | +LL | f(A, A, B, B, /* C */, /* C */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-101097.rs:19:5 + | +LL | f(C, C, B, B, A, A); + | ^ - - - - expected `C`, found `A` + | | | | + | | | expected `C`, found `A` + | | expected `A`, found `C` + | expected `A`, found `C` + | +note: function defined here + --> $DIR/issue-101097.rs:6:4 + | +LL | fn f( + | ^ +LL | a1: A, + | ----- +LL | a2: A, + | ----- +LL | b1: B, + | ----- +LL | b2: B, + | ----- +LL | c1: C, + | ----- +LL | c2: C, + | ----- +help: did you mean + | +LL | f(A, A, B, B, C, C); + | ~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-101097.rs:20:5 + | +LL | f(C, C, A, B, A, A); + | ^ - - - - - expected `C`, found `A` + | | | | | + | | | | expected `C`, found `A` + | | | expected struct `B`, found struct `A` + | | expected `A`, found `C` + | expected `A`, found `C` + | +note: function defined here + --> $DIR/issue-101097.rs:6:4 + | +LL | fn f( + | ^ +LL | a1: A, + | ----- +LL | a2: A, + | ----- +LL | b1: B, + | ----- +LL | b2: B, + | ----- +LL | c1: C, + | ----- +LL | c2: C, + | ----- +help: did you mean + | +LL | f(A, A, /* B */, B, C, C); + | ~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`.