Skip to content

Commit

Permalink
Auto merge of rust-lang#100502 - chenyukang:fix-100478, r=jackh726
Browse files Browse the repository at this point in the history
Avoid infinite loop in function arguments checking

Fixes rust-lang#100478
Fixes rust-lang#101097
  • Loading branch information
bors committed Sep 12, 2022
2 parents 3194958 + 7e7dfb8 commit 56e7678
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 9 deletions.
25 changes: 16 additions & 9 deletions compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,25 @@ 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
let is_arg = i < ai.len();
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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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);
}
}
Expand Down
52 changes: 52 additions & 0 deletions src/test/ui/argument-suggestions/issue-100478.rs
Original file line number Diff line number Diff line change
@@ -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,
);
}
81 changes: 81 additions & 0 deletions src/test/ui/argument-suggestions/issue-100478.stderr
Original file line number Diff line number Diff line change
@@ -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`.
21 changes: 21 additions & 0 deletions src/test/ui/argument-suggestions/issue-101097.rs
Original file line number Diff line number Diff line change
@@ -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]
}
160 changes: 160 additions & 0 deletions src/test/ui/argument-suggestions/issue-101097.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 56e7678

Please sign in to comment.