rustc_hir_typeck/fn_ctxt/
arg_matrix.rs1use core::cmp::Ordering;
2use std::cmp;
3
4use rustc_index::IndexVec;
5use rustc_middle::ty::error::TypeError;
6
7rustc_index::newtype_index! {
8 #[orderable]
9 #[debug_format = "ExpectedIdx({})"]
10 pub(crate) struct ExpectedIdx {}
11}
12
13rustc_index::newtype_index! {
14 #[orderable]
15 #[debug_format = "ProvidedIdx({})"]
16 pub(crate) struct ProvidedIdx {}
17}
18
19impl ExpectedIdx {
20 pub(crate) fn to_provided_idx(self) -> ProvidedIdx {
21 ProvidedIdx::from_usize(self.as_usize())
22 }
23}
24
25impl ProvidedIdx {
26 pub(crate) fn to_expected_idx(self) -> ExpectedIdx {
27 ExpectedIdx::from_u32(self.as_u32())
28 }
29}
30
31#[derive(Debug)]
33enum Issue {
34 Invalid(usize),
36 Missing(usize),
38 Extra(usize),
40 Swap(usize, usize),
42 Permutation(Vec<Option<usize>>),
44}
45
46#[derive(Clone, Debug, Eq, PartialEq)]
47pub(crate) enum Compatibility<'tcx> {
48 Compatible,
49 Incompatible(Option<TypeError<'tcx>>),
50}
51
52#[derive(Debug, PartialEq, Eq)]
54pub(crate) enum Error<'tcx> {
55 Invalid(ProvidedIdx, ExpectedIdx, Compatibility<'tcx>),
57 Missing(ExpectedIdx),
59 Extra(ProvidedIdx),
61 Swap(ProvidedIdx, ProvidedIdx, ExpectedIdx, ExpectedIdx),
63 Permutation(Vec<(ExpectedIdx, ProvidedIdx)>),
65}
66
67impl Ord for Error<'_> {
68 fn cmp(&self, other: &Self) -> Ordering {
69 let key = |error: &Error<'_>| -> usize {
70 match error {
71 Error::Invalid(..) => 0,
72 Error::Extra(_) => 1,
73 Error::Missing(_) => 2,
74 Error::Swap(..) => 3,
75 Error::Permutation(..) => 4,
76 }
77 };
78 match (self, other) {
79 (Error::Invalid(a, _, _), Error::Invalid(b, _, _)) => a.cmp(b),
80 (Error::Extra(a), Error::Extra(b)) => a.cmp(b),
81 (Error::Missing(a), Error::Missing(b)) => a.cmp(b),
82 (Error::Swap(a, b, ..), Error::Swap(c, d, ..)) => a.cmp(c).then(b.cmp(d)),
83 (Error::Permutation(a), Error::Permutation(b)) => a.cmp(b),
84 _ => key(self).cmp(&key(other)),
85 }
86 }
87}
88
89impl PartialOrd for Error<'_> {
90 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
91 Some(self.cmp(other))
92 }
93}
94
95pub(crate) struct ArgMatrix<'tcx> {
96 provided_indices: Vec<ProvidedIdx>,
99 expected_indices: Vec<ExpectedIdx>,
102 compatibility_matrix: Vec<Vec<Compatibility<'tcx>>>,
106}
107
108impl<'tcx> ArgMatrix<'tcx> {
109 pub(crate) fn new<F: FnMut(ProvidedIdx, ExpectedIdx) -> Compatibility<'tcx>>(
110 provided_count: usize,
111 expected_input_count: usize,
112 mut is_compatible: F,
113 ) -> Self {
114 let compatibility_matrix = (0..provided_count)
115 .map(|i| {
116 (0..expected_input_count)
117 .map(|j| is_compatible(ProvidedIdx::from_usize(i), ExpectedIdx::from_usize(j)))
118 .collect()
119 })
120 .collect();
121 ArgMatrix {
122 provided_indices: (0..provided_count).map(ProvidedIdx::from_usize).collect(),
123 expected_indices: (0..expected_input_count).map(ExpectedIdx::from_usize).collect(),
124 compatibility_matrix,
125 }
126 }
127
128 fn eliminate_provided(&mut self, idx: usize) {
130 self.provided_indices.remove(idx);
131 self.compatibility_matrix.remove(idx);
132 }
133
134 fn eliminate_expected(&mut self, idx: usize) {
136 self.expected_indices.remove(idx);
137 for row in &mut self.compatibility_matrix {
138 row.remove(idx);
139 }
140 }
141
142 fn satisfy_input(&mut self, provided_idx: usize, expected_idx: usize) {
144 self.eliminate_provided(provided_idx);
145 self.eliminate_expected(expected_idx);
146 }
147
148 fn eliminate_satisfied(&mut self) -> Vec<(ProvidedIdx, ExpectedIdx)> {
151 let num_args = cmp::min(self.provided_indices.len(), self.expected_indices.len());
152 let mut eliminated = vec![];
153 for i in (0..num_args).rev() {
154 if matches!(self.compatibility_matrix[i][i], Compatibility::Compatible) {
155 eliminated.push((self.provided_indices[i], self.expected_indices[i]));
156 self.satisfy_input(i, i);
157 }
158 }
159 eliminated
160 }
161
162 fn find_issue(&self) -> Option<Issue> {
164 let mat = &self.compatibility_matrix;
165 let ai = &self.expected_indices;
166 let ii = &self.provided_indices;
167
168 let mut next_unmatched_idx = 0;
171 for i in 0..cmp::max(ai.len(), ii.len()) {
172 if i >= mat.len() {
174 return Some(Issue::Missing(next_unmatched_idx));
175 }
176 if mat[i].len() == 0 {
178 return Some(Issue::Extra(next_unmatched_idx));
179 }
180
181 let is_arg = i < ai.len();
183 let is_input = i < ii.len();
184 if is_arg && is_input && matches!(mat[i][i], Compatibility::Compatible) {
185 next_unmatched_idx += 1;
187 continue;
188 }
189
190 let mut useless = true;
191 let mut unsatisfiable = true;
192 if is_arg {
193 for j in 0..ii.len() {
194 if matches!(mat[j][i], Compatibility::Compatible) {
197 unsatisfiable = false;
198 break;
199 }
200 }
201 }
202 if is_input {
203 for j in 0..ai.len() {
204 if matches!(mat[i][j], Compatibility::Compatible) {
207 useless = false;
208 break;
209 }
210 }
211 }
212
213 match (is_input, is_arg, useless, unsatisfiable) {
214 (true, true, true, true) => return Some(Issue::Invalid(i)),
217 (true, _, true, _) => return Some(Issue::Extra(i)),
219 (_, true, _, true) => return Some(Issue::Missing(i)),
221 (true, true, _, _) => {
222 for j in 0..cmp::min(ai.len(), ii.len()) {
228 if i == j || matches!(mat[j][j], Compatibility::Compatible) {
229 continue;
230 }
231 if matches!(mat[i][j], Compatibility::Compatible)
232 && matches!(mat[j][i], Compatibility::Compatible)
233 {
234 return Some(Issue::Swap(i, j));
235 }
236 }
237 }
238 _ => {
239 continue;
240 }
241 }
242 }
243
244 let mut permutation: Vec<Option<Option<usize>>> = vec![None; mat.len()];
252 let mut permutation_found = false;
253 for i in 0..mat.len() {
254 if permutation[i].is_some() {
255 continue;
257 }
258
259 let mut stack = vec![];
260 let mut j = i;
261 let mut last = i;
262 let mut is_cycle = true;
263 loop {
264 stack.push(j);
265 let compat: Vec<_> =
267 mat[j]
268 .iter()
269 .enumerate()
270 .filter_map(|(i, c)| {
271 if matches!(c, Compatibility::Compatible) { Some(i) } else { None }
272 })
273 .collect();
274 if compat.len() < 1 {
275 is_cycle = false;
277 break;
278 }
279 j = compat[0];
280 if stack.contains(&j) {
281 last = j;
282 break;
283 }
284 }
285 if stack.len() <= 2 {
286 is_cycle = false;
289 }
290 permutation_found = is_cycle;
294 while let Some(x) = stack.pop() {
295 if is_cycle {
296 permutation[x] = Some(Some(j));
297 j = x;
298 if j == last {
299 is_cycle = false;
302 }
303 } else {
304 permutation[x] = Some(None);
306 }
307 }
308 }
309
310 if permutation_found {
311 let final_permutation: Vec<Option<usize>> =
313 permutation.into_iter().map(|x| x.unwrap()).collect();
314 return Some(Issue::Permutation(final_permutation));
315 }
316 None
317 }
318
319 pub(crate) fn find_errors(
328 mut self,
329 ) -> (Vec<Error<'tcx>>, IndexVec<ExpectedIdx, Option<ProvidedIdx>>) {
330 let provided_arg_count = self.provided_indices.len();
331
332 let mut errors: Vec<Error<'tcx>> = vec![];
333 let mut matched_inputs: IndexVec<ExpectedIdx, Option<ProvidedIdx>> =
335 IndexVec::from_elem_n(None, self.expected_indices.len());
336
337 for (provided, expected) in self.eliminate_satisfied() {
347 matched_inputs[expected] = Some(provided);
348 }
349
350 while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() {
351 let res = self.find_issue();
352 match res {
353 Some(Issue::Invalid(idx)) => {
354 let compatibility = self.compatibility_matrix[idx][idx].clone();
355 let input_idx = self.provided_indices[idx];
356 let arg_idx = self.expected_indices[idx];
357 self.satisfy_input(idx, idx);
358 errors.push(Error::Invalid(input_idx, arg_idx, compatibility));
359 }
360 Some(Issue::Extra(idx)) => {
361 let input_idx = self.provided_indices[idx];
362 self.eliminate_provided(idx);
363 errors.push(Error::Extra(input_idx));
364 }
365 Some(Issue::Missing(idx)) => {
366 let arg_idx = self.expected_indices[idx];
367 self.eliminate_expected(idx);
368 errors.push(Error::Missing(arg_idx));
369 }
370 Some(Issue::Swap(idx, other)) => {
371 let input_idx = self.provided_indices[idx];
372 let other_input_idx = self.provided_indices[other];
373 let arg_idx = self.expected_indices[idx];
374 let other_arg_idx = self.expected_indices[other];
375 let (min, max) = (cmp::min(idx, other), cmp::max(idx, other));
376 self.satisfy_input(min, max);
377 self.satisfy_input(max - 1, min);
379 errors.push(Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx));
380 matched_inputs[other_arg_idx] = Some(input_idx);
381 matched_inputs[arg_idx] = Some(other_input_idx);
382 }
383 Some(Issue::Permutation(args)) => {
384 let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect();
385
386 let mut real_idxs: IndexVec<ProvidedIdx, Option<(ExpectedIdx, ProvidedIdx)>> =
387 IndexVec::from_elem_n(None, provided_arg_count);
388 for (src, dst) in
389 args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst)))
390 {
391 let src_input_idx = self.provided_indices[src];
392 let dst_input_idx = self.provided_indices[dst];
393 let dest_arg_idx = self.expected_indices[dst];
394 real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx));
395 matched_inputs[dest_arg_idx] = Some(src_input_idx);
396 }
397 idxs.sort();
398 idxs.reverse();
399 for i in idxs {
400 self.satisfy_input(i, i);
401 }
402 errors.push(Error::Permutation(real_idxs.into_iter().flatten().collect()));
403 }
404 None => {
405 let eliminated = self.eliminate_satisfied();
408 assert!(!eliminated.is_empty(), "didn't eliminated any indice in this round");
409 for (inp, arg) in eliminated {
410 matched_inputs[arg] = Some(inp);
411 }
412 }
413 };
414 }
415
416 errors.sort();
419 (errors, matched_inputs)
420 }
421}