Skip to content

Commit 9a3f17b

Browse files
authored
Rollup merge of rust-lang#96823 - jackh726:params-heuristics-fix, r=estebank
Properly fix rust-lang#96638 Closes rust-lang#96638 The main part of this change is `Error::Invalid` now returns both the input and arg indices. However, I realized the code here was kind of confusing and not internally consistent (and thus I was having trouble getting the right behavior). So I've also switched `input_indices` and `arg_indices` to more closely match some naming in `checks` (although I think a more thorough cleanup there could be beneficial). I've added comments, but essentially `input_indices` refers to *user provided* inputs and `arg_indices` refers to *expected* args.
2 parents 7b32e93 + 1d68e6d commit 9a3f17b

File tree

2 files changed

+89
-86
lines changed

2 files changed

+89
-86
lines changed

compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs

+51-43
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::cmp;
33
use rustc_middle::ty::error::TypeError;
44

55
// An issue that might be found in the compatibility matrix
6+
#[derive(Debug)]
67
enum Issue {
78
/// The given argument is the invalid type for the input
89
Invalid(usize),
@@ -23,9 +24,10 @@ pub(crate) enum Compatibility<'tcx> {
2324
}
2425

2526
/// Similar to `Issue`, but contains some extra information
27+
#[derive(Debug)]
2628
pub(crate) enum Error<'tcx> {
27-
/// The given argument is the invalid type for the input
28-
Invalid(usize, Compatibility<'tcx>),
29+
/// The provided argument is the invalid type for the expected input
30+
Invalid(usize, usize, Compatibility<'tcx>), // provided, expected
2931
/// There is a missing input
3032
Missing(usize),
3133
/// There's a superfluous argument
@@ -37,8 +39,15 @@ pub(crate) enum Error<'tcx> {
3739
}
3840

3941
pub(crate) struct ArgMatrix<'tcx> {
42+
/// Maps the indices in the `compatibility_matrix` rows to the indices of
43+
/// the *user provided* inputs
4044
input_indexes: Vec<usize>,
45+
/// Maps the indices in the `compatibility_matrix` columns to the indices
46+
/// of the *expected* args
4147
arg_indexes: Vec<usize>,
48+
/// The first dimension (rows) are the remaining user provided inputs to
49+
/// match and the second dimension (cols) are the remaining expected args
50+
/// to match
4251
compatibility_matrix: Vec<Vec<Compatibility<'tcx>>>,
4352
}
4453

@@ -52,24 +61,24 @@ impl<'tcx> ArgMatrix<'tcx> {
5261
.map(|i| (0..minimum_input_count).map(|j| is_compatible(i, j)).collect())
5362
.collect();
5463
ArgMatrix {
55-
input_indexes: (0..minimum_input_count).collect(),
56-
arg_indexes: (0..provided_arg_count).collect(),
64+
input_indexes: (0..provided_arg_count).collect(),
65+
arg_indexes: (0..minimum_input_count).collect(),
5766
compatibility_matrix,
5867
}
5968
}
6069

6170
/// Remove a given input from consideration
6271
fn eliminate_input(&mut self, idx: usize) {
6372
self.input_indexes.remove(idx);
64-
for row in &mut self.compatibility_matrix {
65-
row.remove(idx);
66-
}
73+
self.compatibility_matrix.remove(idx);
6774
}
6875

6976
/// Remove a given argument from consideration
7077
fn eliminate_arg(&mut self, idx: usize) {
7178
self.arg_indexes.remove(idx);
72-
self.compatibility_matrix.remove(idx);
79+
for row in &mut self.compatibility_matrix {
80+
row.remove(idx);
81+
}
7382
}
7483

7584
/// "satisfy" an input with a given arg, removing both from consideration
@@ -78,21 +87,23 @@ impl<'tcx> ArgMatrix<'tcx> {
7887
self.eliminate_arg(arg_idx);
7988
}
8089

90+
// Returns a `Vec` of (user input, expected arg) of matched arguments. These
91+
// are inputs on the remaining diagonal that match.
8192
fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> {
8293
let mut i = cmp::min(self.input_indexes.len(), self.arg_indexes.len());
8394
let mut eliminated = vec![];
8495
while i > 0 {
8596
let idx = i - 1;
8697
if matches!(self.compatibility_matrix[idx][idx], Compatibility::Compatible) {
87-
eliminated.push((self.arg_indexes[idx], self.input_indexes[idx]));
98+
eliminated.push((self.input_indexes[idx], self.arg_indexes[idx]));
8899
self.satisfy_input(idx, idx);
89100
}
90101
i -= 1;
91102
}
92103
return eliminated;
93104
}
94105

95-
// Check for the above mismatch cases
106+
// Find some issue in the compatibility matrix
96107
fn find_issue(&self) -> Option<Issue> {
97108
let mat = &self.compatibility_matrix;
98109
let ai = &self.arg_indexes;
@@ -121,26 +132,26 @@ impl<'tcx> ArgMatrix<'tcx> {
121132
if is_arg {
122133
for j in 0..ii.len() {
123134
// If we find at least one input this argument could satisfy
124-
// this argument isn't completely useless
125-
if matches!(mat[i][j], Compatibility::Compatible) {
126-
useless = false;
135+
// this argument isn't unsatisfiable
136+
if matches!(mat[j][i], Compatibility::Compatible) {
137+
unsatisfiable = false;
127138
break;
128139
}
129140
}
130141
}
131142
if is_input {
132143
for j in 0..ai.len() {
133144
// If we find at least one argument that could satisfy this input
134-
// this argument isn't unsatisfiable
135-
if matches!(mat[j][i], Compatibility::Compatible) {
136-
unsatisfiable = false;
145+
// this argument isn't useless
146+
if matches!(mat[i][j], Compatibility::Compatible) {
147+
useless = false;
137148
break;
138149
}
139150
}
140151
}
141152

142-
match (is_arg, is_input, useless, unsatisfiable) {
143-
// If an input is unsatisfied, and the argument in its position is useless
153+
match (is_input, is_arg, useless, unsatisfiable) {
154+
// If an argument is unsatisfied, and the input in its position is useless
144155
// then the most likely explanation is that we just got the types wrong
145156
(true, true, true, true) => return Some(Issue::Invalid(i)),
146157
// Otherwise, if an input is useless, then indicate that this is an extra argument
@@ -167,7 +178,7 @@ impl<'tcx> ArgMatrix<'tcx> {
167178
_ => {
168179
continue;
169180
}
170-
};
181+
}
171182
}
172183

173184
// We didn't find any of the individual issues above, but
@@ -254,11 +265,11 @@ impl<'tcx> ArgMatrix<'tcx> {
254265
// We'll want to know which arguments and inputs these rows and columns correspond to
255266
// even after we delete them.
256267
pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
257-
let provided_arg_count = self.arg_indexes.len();
268+
let provided_arg_count = self.input_indexes.len();
258269

259270
let mut errors: Vec<Error<'tcx>> = vec![];
260271
// For each expected argument, the matched *actual* input
261-
let mut matched_inputs: Vec<Option<usize>> = vec![None; self.input_indexes.len()];
272+
let mut matched_inputs: Vec<Option<usize>> = vec![None; self.arg_indexes.len()];
262273

263274
// Before we start looking for issues, eliminate any arguments that are already satisfied,
264275
// so that an argument which is already spoken for by the input it's in doesn't
@@ -269,28 +280,28 @@ impl<'tcx> ArgMatrix<'tcx> {
269280
// Without this elimination, the first argument causes the second argument
270281
// to show up as both a missing input and extra argument, rather than
271282
// just an invalid type.
272-
for (arg, inp) in self.eliminate_satisfied() {
273-
matched_inputs[inp] = Some(arg);
283+
for (inp, arg) in self.eliminate_satisfied() {
284+
matched_inputs[arg] = Some(inp);
274285
}
275286

276287
while self.input_indexes.len() > 0 || self.arg_indexes.len() > 0 {
277-
// Check for the first relevant issue
278288
match self.find_issue() {
279289
Some(Issue::Invalid(idx)) => {
280290
let compatibility = self.compatibility_matrix[idx][idx].clone();
281291
let input_idx = self.input_indexes[idx];
292+
let arg_idx = self.arg_indexes[idx];
282293
self.satisfy_input(idx, idx);
283-
errors.push(Error::Invalid(input_idx, compatibility));
294+
errors.push(Error::Invalid(input_idx, arg_idx, compatibility));
284295
}
285296
Some(Issue::Extra(idx)) => {
286-
let arg_idx = self.arg_indexes[idx];
287-
self.eliminate_arg(idx);
288-
errors.push(Error::Extra(arg_idx));
289-
}
290-
Some(Issue::Missing(idx)) => {
291297
let input_idx = self.input_indexes[idx];
292298
self.eliminate_input(idx);
293-
errors.push(Error::Missing(input_idx));
299+
errors.push(Error::Extra(input_idx));
300+
}
301+
Some(Issue::Missing(idx)) => {
302+
let arg_idx = self.arg_indexes[idx];
303+
self.eliminate_arg(idx);
304+
errors.push(Error::Missing(arg_idx));
294305
}
295306
Some(Issue::Swap(idx, other)) => {
296307
let input_idx = self.input_indexes[idx];
@@ -302,24 +313,21 @@ impl<'tcx> ArgMatrix<'tcx> {
302313
// Subtract 1 because we already removed the "min" row
303314
self.satisfy_input(max - 1, min);
304315
errors.push(Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx));
305-
matched_inputs[input_idx] = Some(other_arg_idx);
306-
matched_inputs[other_input_idx] = Some(arg_idx);
316+
matched_inputs[other_arg_idx] = Some(input_idx);
317+
matched_inputs[arg_idx] = Some(other_input_idx);
307318
}
308319
Some(Issue::Permutation(args)) => {
309-
// FIXME: If satisfy_input ever did anything non-trivial (emit obligations to help type checking, for example)
310-
// we'd want to call this function with the correct arg/input pairs, but for now, we just throw them in a bucket.
311-
// This works because they force a cycle, so each row is guaranteed to also be a column
312320
let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect();
313321

314322
let mut real_idxs = vec![None; provided_arg_count];
315323
for (src, dst) in
316324
args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst)))
317325
{
318-
let src_arg = self.arg_indexes[src];
319-
let dst_arg = self.arg_indexes[dst];
320-
let dest_input = self.input_indexes[dst];
321-
real_idxs[src_arg] = Some((dst_arg, dest_input));
322-
matched_inputs[dest_input] = Some(src_arg);
326+
let src_input_idx = self.input_indexes[src];
327+
let dst_input_idx = self.input_indexes[dst];
328+
let dest_arg_idx = self.arg_indexes[dst];
329+
real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx));
330+
matched_inputs[dest_arg_idx] = Some(src_input_idx);
323331
}
324332
idxs.sort();
325333
idxs.reverse();
@@ -331,8 +339,8 @@ impl<'tcx> ArgMatrix<'tcx> {
331339
None => {
332340
// We didn't find any issues, so we need to push the algorithm forward
333341
// First, eliminate any arguments that currently satisfy their inputs
334-
for (arg, inp) in self.eliminate_satisfied() {
335-
matched_inputs[inp] = Some(arg);
342+
for (inp, arg) in self.eliminate_satisfied() {
343+
matched_inputs[arg] = Some(inp);
336344
}
337345
}
338346
};

0 commit comments

Comments
 (0)