about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-12 06:05:32 +0000
committerbors <bors@rust-lang.org>2022-09-12 06:05:32 +0000
commit56e7678ca97e9740f7d09206f767d5bb676917f7 (patch)
tree25342b60afc964801c6336b06b43a7a0805c9bac
parent3194958217c24744ee3118fdc5b3d6b274b7316d (diff)
parent7e7dfb83dc1fe63d1ce14101339f5eee5b76159d (diff)
downloadrust-56e7678ca97e9740f7d09206f767d5bb676917f7.tar.gz
rust-56e7678ca97e9740f7d09206f767d5bb676917f7.zip
Auto merge of #100502 - chenyukang:fix-100478, r=jackh726
Avoid infinite loop in function arguments checking

Fixes #100478
Fixes #101097
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs25
-rw-r--r--src/test/ui/argument-suggestions/issue-100478.rs52
-rw-r--r--src/test/ui/argument-suggestions/issue-100478.stderr81
-rw-r--r--src/test/ui/argument-suggestions/issue-101097.rs21
-rw-r--r--src/test/ui/argument-suggestions/issue-101097.stderr160
5 files changed, 330 insertions, 9 deletions
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..fc83994caf5 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 @@ impl<'tcx> ArgMatrix<'tcx> {
         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 @@ impl<'tcx> ArgMatrix<'tcx> {
             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 @@ impl<'tcx> ArgMatrix<'tcx> {
             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;
@@ -232,8 +236,8 @@ impl<'tcx> ArgMatrix<'tcx> {
                             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;
                 }
@@ -309,7 +313,8 @@ impl<'tcx> ArgMatrix<'tcx> {
         }
 
         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 @@ impl<'tcx> ArgMatrix<'tcx> {
                 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<T2>, p3: T3, p4: Arc<T4>, p5: T5, p6: T6, p7: T7, p8: Arc<T8>) {}
+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..df02a312cf1
--- /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<T2>` is missing
+   |
+note: function defined here
+  --> $DIR/issue-100478.rs:29:4
+   |
+LL | fn foo(p1: T1, p2: Arc<T2>, p3: T3, p4: Arc<T4>, p5: T5, p6: T6, p7: T7, p8: Arc<T8>) {}
+   |    ^^^ ------  -----------  ------  -----------  ------  ------  ------  -----------
+help: provide the argument
+   |
+LL |     foo(p1, /* Arc<T2> */, 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`.
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`.