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 7602f2550e85b..637392d135882 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs @@ -110,6 +110,36 @@ impl<'tcx> ArgMatrix<'tcx> { self.eliminate_expected(expected_idx); } + fn print_mat(&self, msg: &str) { + println!("================== {} ==================", msg); + let mat = &self.compatibility_matrix; + let mut head = false; + for (i, row) in mat.iter().enumerate() { + if !head { + print!("x| "); + for (j, _) in row.iter().enumerate() { + print!(" {} ", j); + } + print!("\n-| "); + for (_, _) in row.iter().enumerate() { + print!(" - "); + } + head = true; + println!(); + } + print!("{}| ", i); + for (_j, cell) in row.iter().enumerate() { + match cell { + Compatibility::Compatible => print!(" 1 "), + Compatibility::Incompatible(_err) => { + print!(" 0 "); + } + } + } + println!(); + } + } + // Returns a `Vec` of (user input, expected arg) of matched arguments. These // are inputs on the remaining diagonal that match. fn eliminate_satisfied(&mut self) -> Vec<(ProvidedIdx, ExpectedIdx)> { @@ -130,14 +160,18 @@ impl<'tcx> ArgMatrix<'tcx> { let ai = &self.expected_indices; let ii = &self.provided_indices; + println!("ai: {:?}", ai); + println!("ii: {:?}", ii); + self.print_mat("find_issue:"); + let mut cur_matched_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(cur_matched_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(cur_matched_idx)); } // Make sure we don't pass the bounds of our matrix @@ -145,6 +179,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 + cur_matched_idx += 1; continue; } @@ -163,7 +198,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; @@ -171,6 +206,10 @@ impl<'tcx> ArgMatrix<'tcx> { } } + println!( + "i: {}, is_input: {}, is_arg: {}, useless: {}, unsatisfiable: {}", + i, is_input, is_arg, useless, unsatisfiable + ); match (is_input, is_arg, useless, unsatisfiable) { // If an argument is unsatisfied, and the input in its position is useless // then the most likely explanation is that we just got the types wrong @@ -232,6 +271,7 @@ impl<'tcx> ArgMatrix<'tcx> { if matches!(c, Compatibility::Compatible) { Some(i) } else { None } }) .collect(); + println!("loop i: {} j: {} compat: {:?}", i, j, compat); if compat.len() != 1 { // this could go into multiple slots, don't bother exploring both is_cycle = false; @@ -252,6 +292,7 @@ impl<'tcx> ArgMatrix<'tcx> { // ex: [1,2,3,4]; last = 2; j = 2; // So, we want to mark 4, 3, and 2 as part of a permutation permutation_found = is_cycle; + println!("permutation_found: {}", permutation_found); while let Some(x) = stack.pop() { if is_cycle { permutation[x] = Some(Some(j)); @@ -264,6 +305,7 @@ impl<'tcx> ArgMatrix<'tcx> { } else { // Some(None) ensures we save time by skipping this argument again permutation[x] = Some(None); + println!("now permutation: {:?}", permutation); } } } @@ -309,7 +351,9 @@ impl<'tcx> ArgMatrix<'tcx> { } while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() { - match self.find_issue() { + let res = self.find_issue(); + println!("res: {:?}", res); + match res { Some(Issue::Invalid(idx)) => { let compatibility = self.compatibility_matrix[idx][idx].clone(); let input_idx = self.provided_indices[idx]; @@ -364,7 +408,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 0000000000000..6bef6ad103862 --- /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 0000000000000..a77889a9679ca --- /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`. 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 0000000000000..9a1315a6ab79e --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-101097.rs @@ -0,0 +1,35 @@ +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, C, A, A, B, B); + //f(C, A, A, A, B, B, C); + //f(A, A, D, D, B, B); //ok + //f(C, C, B, B, A, A); + //f(C, C, A, B, A, A); +} + + +/* +fn f(a1: A, a2: A, b1: B, c1: C) {} + +fn main() { + f( + C, + A, + A, + B, + ); +} +*/ \ No newline at end of file