Skip to content

Commit f2277e0

Browse files
Use typed indices in argument mismatch algorithm
1 parent 7f08d04 commit f2277e0

19 files changed

+759
-682
lines changed

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

+77-52
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
use std::cmp;
22

3+
use rustc_index::vec::IndexVec;
34
use rustc_middle::ty::error::TypeError;
45

6+
rustc_index::newtype_index! {
7+
pub(crate) struct ExpectedIdx {
8+
DEBUG_FORMAT = "ExpectedIdx({})",
9+
}
10+
}
11+
12+
rustc_index::newtype_index! {
13+
pub(crate) struct ProvidedIdx {
14+
DEBUG_FORMAT = "ProvidedIdx({})",
15+
}
16+
}
17+
18+
impl ExpectedIdx {
19+
pub fn to_provided_idx(self) -> ProvidedIdx {
20+
ProvidedIdx::from_usize(self.as_usize())
21+
}
22+
}
23+
524
// An issue that might be found in the compatibility matrix
625
#[derive(Debug)]
726
enum Issue {
@@ -27,87 +46,89 @@ pub(crate) enum Compatibility<'tcx> {
2746
#[derive(Debug)]
2847
pub(crate) enum Error<'tcx> {
2948
/// The provided argument is the invalid type for the expected input
30-
Invalid(usize, usize, Compatibility<'tcx>), // provided, expected
49+
Invalid(ProvidedIdx, ExpectedIdx, Compatibility<'tcx>),
3150
/// There is a missing input
32-
Missing(usize),
51+
Missing(ExpectedIdx),
3352
/// There's a superfluous argument
34-
Extra(usize),
53+
Extra(ProvidedIdx),
3554
/// Two arguments should be swapped
36-
Swap(usize, usize, usize, usize),
55+
Swap(ProvidedIdx, ProvidedIdx, ExpectedIdx, ExpectedIdx),
3756
/// Several arguments should be reordered
38-
Permutation(Vec<(usize, usize)>), // dest_arg, dest_input
57+
Permutation(Vec<(ExpectedIdx, ProvidedIdx)>),
3958
}
4059

4160
pub(crate) struct ArgMatrix<'tcx> {
4261
/// Maps the indices in the `compatibility_matrix` rows to the indices of
4362
/// the *user provided* inputs
44-
input_indexes: Vec<usize>,
63+
provided_indices: Vec<ProvidedIdx>,
4564
/// Maps the indices in the `compatibility_matrix` columns to the indices
4665
/// of the *expected* args
47-
arg_indexes: Vec<usize>,
66+
expected_indices: Vec<ExpectedIdx>,
4867
/// The first dimension (rows) are the remaining user provided inputs to
4968
/// match and the second dimension (cols) are the remaining expected args
5069
/// to match
5170
compatibility_matrix: Vec<Vec<Compatibility<'tcx>>>,
5271
}
5372

5473
impl<'tcx> ArgMatrix<'tcx> {
55-
pub(crate) fn new<F: FnMut(usize, usize) -> Compatibility<'tcx>>(
56-
minimum_input_count: usize,
57-
provided_arg_count: usize,
74+
pub(crate) fn new<F: FnMut(ProvidedIdx, ExpectedIdx) -> Compatibility<'tcx>>(
75+
provided_count: usize,
76+
expected_input_count: usize,
5877
mut is_compatible: F,
5978
) -> Self {
60-
let compatibility_matrix = (0..provided_arg_count)
61-
.map(|i| (0..minimum_input_count).map(|j| is_compatible(i, j)).collect())
79+
let compatibility_matrix = (0..provided_count)
80+
.map(|i| {
81+
(0..expected_input_count)
82+
.map(|j| is_compatible(ProvidedIdx::from_usize(i), ExpectedIdx::from_usize(j)))
83+
.collect()
84+
})
6285
.collect();
6386
ArgMatrix {
64-
input_indexes: (0..provided_arg_count).collect(),
65-
arg_indexes: (0..minimum_input_count).collect(),
87+
provided_indices: (0..provided_count).map(ProvidedIdx::from_usize).collect(),
88+
expected_indices: (0..expected_input_count).map(ExpectedIdx::from_usize).collect(),
6689
compatibility_matrix,
6790
}
6891
}
6992

7093
/// Remove a given input from consideration
71-
fn eliminate_input(&mut self, idx: usize) {
72-
self.input_indexes.remove(idx);
94+
fn eliminate_provided(&mut self, idx: usize) {
95+
self.provided_indices.remove(idx);
7396
self.compatibility_matrix.remove(idx);
7497
}
7598

7699
/// Remove a given argument from consideration
77-
fn eliminate_arg(&mut self, idx: usize) {
78-
self.arg_indexes.remove(idx);
100+
fn eliminate_expected(&mut self, idx: usize) {
101+
self.expected_indices.remove(idx);
79102
for row in &mut self.compatibility_matrix {
80103
row.remove(idx);
81104
}
82105
}
83106

84107
/// "satisfy" an input with a given arg, removing both from consideration
85-
fn satisfy_input(&mut self, input_idx: usize, arg_idx: usize) {
86-
self.eliminate_input(input_idx);
87-
self.eliminate_arg(arg_idx);
108+
fn satisfy_input(&mut self, provided_idx: usize, expected_idx: usize) {
109+
self.eliminate_provided(provided_idx);
110+
self.eliminate_expected(expected_idx);
88111
}
89112

90113
// Returns a `Vec` of (user input, expected arg) of matched arguments. These
91114
// are inputs on the remaining diagonal that match.
92-
fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> {
93-
let mut i = cmp::min(self.input_indexes.len(), self.arg_indexes.len());
115+
fn eliminate_satisfied(&mut self) -> Vec<(ProvidedIdx, ExpectedIdx)> {
116+
let num_args = cmp::min(self.provided_indices.len(), self.expected_indices.len());
94117
let mut eliminated = vec![];
95-
while i > 0 {
96-
let idx = i - 1;
97-
if matches!(self.compatibility_matrix[idx][idx], Compatibility::Compatible) {
98-
eliminated.push((self.input_indexes[idx], self.arg_indexes[idx]));
99-
self.satisfy_input(idx, idx);
118+
for i in (0..num_args).rev() {
119+
if matches!(self.compatibility_matrix[i][i], Compatibility::Compatible) {
120+
eliminated.push((self.provided_indices[i], self.expected_indices[i]));
121+
self.satisfy_input(i, i);
100122
}
101-
i -= 1;
102123
}
103-
return eliminated;
124+
eliminated
104125
}
105126

106127
// Find some issue in the compatibility matrix
107128
fn find_issue(&self) -> Option<Issue> {
108129
let mat = &self.compatibility_matrix;
109-
let ai = &self.arg_indexes;
110-
let ii = &self.input_indexes;
130+
let ai = &self.expected_indices;
131+
let ii = &self.provided_indices;
111132

112133
for i in 0..cmp::max(ai.len(), ii.len()) {
113134
// If we eliminate the last row, any left-over inputs are considered missing
@@ -264,12 +285,15 @@ impl<'tcx> ArgMatrix<'tcx> {
264285
//
265286
// We'll want to know which arguments and inputs these rows and columns correspond to
266287
// even after we delete them.
267-
pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
268-
let provided_arg_count = self.input_indexes.len();
288+
pub(crate) fn find_errors(
289+
mut self,
290+
) -> (Vec<Error<'tcx>>, IndexVec<ExpectedIdx, Option<ProvidedIdx>>) {
291+
let provided_arg_count = self.provided_indices.len();
269292

270293
let mut errors: Vec<Error<'tcx>> = vec![];
271294
// For each expected argument, the matched *actual* input
272-
let mut matched_inputs: Vec<Option<usize>> = vec![None; self.arg_indexes.len()];
295+
let mut matched_inputs: IndexVec<ExpectedIdx, Option<ProvidedIdx>> =
296+
IndexVec::from_elem_n(None, self.expected_indices.len());
273297

274298
// Before we start looking for issues, eliminate any arguments that are already satisfied,
275299
// so that an argument which is already spoken for by the input it's in doesn't
@@ -280,34 +304,34 @@ impl<'tcx> ArgMatrix<'tcx> {
280304
// Without this elimination, the first argument causes the second argument
281305
// to show up as both a missing input and extra argument, rather than
282306
// just an invalid type.
283-
for (inp, arg) in self.eliminate_satisfied() {
284-
matched_inputs[arg] = Some(inp);
307+
for (provided, expected) in self.eliminate_satisfied() {
308+
matched_inputs[expected] = Some(provided);
285309
}
286310

287-
while self.input_indexes.len() > 0 || self.arg_indexes.len() > 0 {
311+
while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() {
288312
match self.find_issue() {
289313
Some(Issue::Invalid(idx)) => {
290314
let compatibility = self.compatibility_matrix[idx][idx].clone();
291-
let input_idx = self.input_indexes[idx];
292-
let arg_idx = self.arg_indexes[idx];
315+
let input_idx = self.provided_indices[idx];
316+
let arg_idx = self.expected_indices[idx];
293317
self.satisfy_input(idx, idx);
294318
errors.push(Error::Invalid(input_idx, arg_idx, compatibility));
295319
}
296320
Some(Issue::Extra(idx)) => {
297-
let input_idx = self.input_indexes[idx];
298-
self.eliminate_input(idx);
321+
let input_idx = self.provided_indices[idx];
322+
self.eliminate_provided(idx);
299323
errors.push(Error::Extra(input_idx));
300324
}
301325
Some(Issue::Missing(idx)) => {
302-
let arg_idx = self.arg_indexes[idx];
303-
self.eliminate_arg(idx);
326+
let arg_idx = self.expected_indices[idx];
327+
self.eliminate_expected(idx);
304328
errors.push(Error::Missing(arg_idx));
305329
}
306330
Some(Issue::Swap(idx, other)) => {
307-
let input_idx = self.input_indexes[idx];
308-
let other_input_idx = self.input_indexes[other];
309-
let arg_idx = self.arg_indexes[idx];
310-
let other_arg_idx = self.arg_indexes[other];
331+
let input_idx = self.provided_indices[idx];
332+
let other_input_idx = self.provided_indices[other];
333+
let arg_idx = self.expected_indices[idx];
334+
let other_arg_idx = self.expected_indices[other];
311335
let (min, max) = (cmp::min(idx, other), cmp::max(idx, other));
312336
self.satisfy_input(min, max);
313337
// Subtract 1 because we already removed the "min" row
@@ -319,13 +343,14 @@ impl<'tcx> ArgMatrix<'tcx> {
319343
Some(Issue::Permutation(args)) => {
320344
let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect();
321345

322-
let mut real_idxs = vec![None; provided_arg_count];
346+
let mut real_idxs: IndexVec<ProvidedIdx, Option<(ExpectedIdx, ProvidedIdx)>> =
347+
IndexVec::from_elem_n(None, provided_arg_count);
323348
for (src, dst) in
324349
args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst)))
325350
{
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];
351+
let src_input_idx = self.provided_indices[src];
352+
let dst_input_idx = self.provided_indices[dst];
353+
let dest_arg_idx = self.expected_indices[dst];
329354
real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx));
330355
matched_inputs[dest_arg_idx] = Some(src_input_idx);
331356
}

0 commit comments

Comments
 (0)