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].is_empty() {
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 unsatisfiable = if is_arg {
192 !mat.iter().take(ii.len()).any(|c| matches!(c[i], Compatibility::Compatible))
193 } else {
194 true
195 };
196 let useless = if is_input {
198 !mat[i].iter().take(ai.len()).any(|c| matches!(c, Compatibility::Compatible))
199 } else {
200 true
201 };
202
203 match (is_input, is_arg, useless, unsatisfiable) {
204 (true, true, true, true) => return Some(Issue::Invalid(i)),
207 (true, _, true, _) => return Some(Issue::Extra(i)),
209 (_, true, _, true) => return Some(Issue::Missing(i)),
211 (true, true, _, _) => {
212 for j in 0..cmp::min(ai.len(), ii.len()) {
218 if i == j || matches!(mat[j][j], Compatibility::Compatible) {
219 continue;
220 }
221 if matches!(mat[i][j], Compatibility::Compatible)
222 && matches!(mat[j][i], Compatibility::Compatible)
223 {
224 return Some(Issue::Swap(i, j));
225 }
226 }
227 }
228 _ => {
229 continue;
230 }
231 }
232 }
233
234 let mut permutation: Vec<Option<Option<usize>>> = vec![None; mat.len()];
242 let mut permutation_found = false;
243 for i in 0..mat.len() {
244 if permutation[i].is_some() {
245 continue;
247 }
248
249 let mut stack = vec![];
250 let mut j = i;
251 let mut last = i;
252 let mut is_cycle = true;
253 loop {
254 stack.push(j);
255 let compat: Vec<_> =
257 mat[j]
258 .iter()
259 .enumerate()
260 .filter_map(|(i, c)| {
261 if matches!(c, Compatibility::Compatible) { Some(i) } else { None }
262 })
263 .collect();
264 if compat.len() < 1 {
265 is_cycle = false;
267 break;
268 }
269 j = compat[0];
270 if stack.contains(&j) {
271 last = j;
272 break;
273 }
274 }
275 if stack.len() <= 2 {
276 is_cycle = false;
279 }
280 permutation_found = is_cycle;
284 while let Some(x) = stack.pop() {
285 if is_cycle {
286 permutation[x] = Some(Some(j));
287 j = x;
288 if j == last {
289 is_cycle = false;
292 }
293 } else {
294 permutation[x] = Some(None);
296 }
297 }
298 }
299
300 if permutation_found {
301 let final_permutation: Vec<Option<usize>> =
303 permutation.into_iter().map(|x| x.unwrap()).collect();
304 return Some(Issue::Permutation(final_permutation));
305 }
306 None
307 }
308
309 pub(crate) fn find_errors(
318 mut self,
319 ) -> (Vec<Error<'tcx>>, IndexVec<ExpectedIdx, Option<ProvidedIdx>>) {
320 let provided_arg_count = self.provided_indices.len();
321
322 let mut errors: Vec<Error<'tcx>> = vec![];
323 let mut matched_inputs: IndexVec<ExpectedIdx, Option<ProvidedIdx>> =
325 IndexVec::from_elem_n(None, self.expected_indices.len());
326
327 for (provided, expected) in self.eliminate_satisfied() {
337 matched_inputs[expected] = Some(provided);
338 }
339
340 while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() {
341 let res = self.find_issue();
342 match res {
343 Some(Issue::Invalid(idx)) => {
344 let compatibility = self.compatibility_matrix[idx][idx].clone();
345 let input_idx = self.provided_indices[idx];
346 let arg_idx = self.expected_indices[idx];
347 self.satisfy_input(idx, idx);
348 errors.push(Error::Invalid(input_idx, arg_idx, compatibility));
349 }
350 Some(Issue::Extra(idx)) => {
351 let input_idx = self.provided_indices[idx];
352 self.eliminate_provided(idx);
353 errors.push(Error::Extra(input_idx));
354 }
355 Some(Issue::Missing(idx)) => {
356 let arg_idx = self.expected_indices[idx];
357 self.eliminate_expected(idx);
358 errors.push(Error::Missing(arg_idx));
359 }
360 Some(Issue::Swap(idx, other)) => {
361 let input_idx = self.provided_indices[idx];
362 let other_input_idx = self.provided_indices[other];
363 let arg_idx = self.expected_indices[idx];
364 let other_arg_idx = self.expected_indices[other];
365 let (min, max) = (cmp::min(idx, other), cmp::max(idx, other));
366 self.satisfy_input(min, max);
367 self.satisfy_input(max - 1, min);
369 errors.push(Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx));
370 matched_inputs[other_arg_idx] = Some(input_idx);
371 matched_inputs[arg_idx] = Some(other_input_idx);
372 }
373 Some(Issue::Permutation(args)) => {
374 let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect();
375
376 let mut real_idxs: IndexVec<ProvidedIdx, Option<(ExpectedIdx, ProvidedIdx)>> =
377 IndexVec::from_elem_n(None, provided_arg_count);
378 for (src, dst) in
379 args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst)))
380 {
381 let src_input_idx = self.provided_indices[src];
382 let dst_input_idx = self.provided_indices[dst];
383 let dest_arg_idx = self.expected_indices[dst];
384 real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx));
385 matched_inputs[dest_arg_idx] = Some(src_input_idx);
386 }
387 idxs.sort();
388 idxs.reverse();
389 for i in idxs {
390 self.satisfy_input(i, i);
391 }
392 errors.push(Error::Permutation(real_idxs.into_iter().flatten().collect()));
393 }
394 None => {
395 let eliminated = self.eliminate_satisfied();
398 assert!(!eliminated.is_empty(), "didn't eliminated any indice in this round");
399 for (inp, arg) in eliminated {
400 matched_inputs[arg] = Some(inp);
401 }
402 }
403 };
404 }
405
406 errors.sort();
409 (errors, matched_inputs)
410 }
411}