Skip to content

Avoid infinite loop in function arguments checking #100502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`.