Skip to content

Commit dee9aed

Browse files
authored
Rollup merge of rust-lang#97542 - compiler-errors:arg-mismatch, r=jackh726
Use typed indices in argument mismatch algorithm I kinda went overboard with the renames, but in general, "arg" is renamed to "expected", and "input" is renamed to "provided", and we use new typed indices to make sure we're indexing into the right sized array. Other drive-by changes: 1. Factor this logic into a new function, so we don't need to `break 'label` to escape it. 1. Factored out dependence on `final_arg_types`, which is never populated for arguments greater than the number of expected args. Instead, we just grab the final coerced expression type from `in_progress_typeck_results`. 1. Adjust the criteria we use to print (provided) type names, before we didn't suggest anything that had infer vars, but now we suggest thing that have infer vars but aren't `_`. ~Also, sorry in advance, I kinda want to backport this but I know I have folded in a lot of unnecessary drive-by changes that might discourage that. I would be open to brainstorming how to get some of these changes on beta at least.~ edit: Minimized the ICE-fixing changes to rust-lang#97557 cc `@jackh726` as author of rust-lang#92364, and `@estebank` as reviewer of the PR. fixes rust-lang#97484
2 parents 45740ac + f2277e0 commit dee9aed

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)